Skip to content

web: Gable light, a calm light mode beside Industrial Dark - #147

Merged
futurebuildai merged 12 commits into
refactor/v1from
refactor/gable-light
Oct 15, 2026
Merged

futurebuildai merged 12 commits into
refactor/v1from
refactor/gable-light

Conversation

@futurebuildai

@futurebuildai futurebuildai commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Gable light: a calm light mode beside Industrial Dark. Industrial Dark is the default and draws exactly as before; light is the alternative a person sets for themselves and keeps. Palette values are used as given; nothing else from their source is in this PR.

What it is

  • Tokens (tokens.css): every colour is an RGB channel variable (--gb-*). :root holds today's values exactly (Tailwind v3 defaults, the brand hex); :root[data-theme="light"] holds the light palette and the semantic HSL values. color-scheme is set only in the light block.
  • Tailwind theme: brand aliases, white, black, the neutral and status palettes (now including fuchsia, derived for light) read rgb(var(--gb-...) / <alpha-value>). Glow and elevation shadows read variables (no glow in light).
  • Tokens with their own dark value (so dark is byte exact and light follows the palette): plate, backdrop, gable-green-hover, gable-green-tint; the till dialog colours (till-*); pale, well, well-hover; the portal ground and panel; chip-ground, shade, photo-btn, map-note; the glow sizes; chart-tick, chart-fulfilled; picture-plate, tile, hover-row.
  • Second voice (voice, voice-soft, voice-text, voice-fill): today's neutrals in dark, sage in light, for the counter's category chips, the quote's "Material list" tag and "draft" chip.
  • Switch: theme.ts and <gable-theme-toggle> (a native button named "Light mode" / "Dark mode") in the desk header and on the front door. Stored per signed in subject under gable_theme:<subject>, last used under gable_theme; a person's key only ever holds their own choice; a storage listener follows other tabs; applied at the app entry before the first render and on sign in.
  • Boot screens: both index.html pages load /theme-boot.js (a same origin script, because the CSP refuses inline ones) and read the variables, so there is no dark flash.
  • One check over all of web/apps (no-literal-colour.test.ts): no hex of three to eight digits, no rgb() literal, no arbitrary hex class, no literal white or black surface, no named colour in a style. The allowlist names file plus literal plus reason, and the rest of the file is still scanned. Its failure message names the file, the literal and the token to use.
  • Charts and the route map read the variables at render and redraw on a mode change.

Tests

Dark: every dark variable is listed and pinned (none unlisted, none different). Light: every value equals the palette; the derived fuchsia ramp; no glow. Contrast: every pair computed from the token values. The switch, the control, the boot script, the sweep guard and its planted cases.

Pair Ratio Needed
ink on ground 13.52:1 4.5:1
ink on card 14.84:1 4.5:1
ink on modal 15.99:1 4.5:1
muted (neutral 400) on card 6.59:1 4.5:1
muted (neutral 400) on ground 6.01:1 4.5:1
hint (neutral 500) on card 4.99:1 4.5:1
hint (neutral 500) on ground 4.55:1 4.5:1
control edge (neutral 600) on card 3.59:1 3.0:1
control edge (neutral 600) on ground 3.27:1 3.0:1
green control on ground 5.36:1 3.0:1
green text on card 5.89:1 4.5:1
green text on ground 5.36:1 4.5:1
paper label on green 6.23:1 4.5:1
paper label on green hover 7.77:1 4.5:1
blue text on card 5.56:1 4.5:1
blue text on ground 5.06:1 4.5:1
red text on card 5.54:1 4.5:1
red text on ground 5.04:1 4.5:1
paper label on red 5.86:1 4.5:1
sage text on card 5.79:1 4.5:1
sage text on ground 5.27:1 4.5:1
ink label on sage fill 4.57:1 4.5:1
green text on green tint 5.39:1 4.5:1
sage text on sage tint 5.16:1 4.5:1
fuchsia 300 on card 6.69:1 4.5:1
fuchsia 300 on ground 6.09:1 4.5:1

For the principal's ruling

  • Five card islands (saved reports, the report builder, the activity modal, the portal's my account, the activity feed) were white cards in dark; they now use the desk's dark card vocabulary so light can work. That moves those five in dark.
  • Till dialogs: the confirm buttons are green in light where dark draws them violet.

🤖 Generated with Claude Code

futurebuildai and others added 12 commits October 14, 2026 12:46
Every colour the desk draws is now an RGB channel variable (--gb-*) in the
design system tokens: :root holds Industrial Dark exactly as before and
:root[data-theme="light"] holds the Gable light palette. The Tailwind
theme reads them (white, black, zinc, slate, gray and the status palettes,
the brand aliases, plate and backdrop, glow and elevation shadows).

A theme module and a sun or moon control in the desk header and on the
front door let a person set light or dark for themselves, stored per
signed in subject and applied before the first render.

The 250 arbitrary hex colour classes in the apps became tokens, picture
plates and switch knobs use plate, modal veils use backdrop, and a check
keeps the sweep swept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
The counter's till open, till close and return dialogs read the colour
variables instead of fixed hex. A white label on a solid status fill
(text-white on bg-red-600 and the like) is text-plate, so it stays a white
label in dark and reads against the deepened fill in light.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Chart.js colours (series, grid, ticks, tooltip) are read from the
variables at render and the charts draw again when the mode changes.
The route map's line, stop markers and popup follow the mode, and its
tile filter is dark only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Inline backgrounds become tokens, the dealer accent falls back to the
mode's Gable green, and the status colours read the variables.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Hex status colours on reconciliation, matching, the product geometry
preview and the millwork configurators read the variables; photo
scrims are backdrop; wells that were a black veil are deep space; a
white label on a solid fill is plate.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
The CRM activity modal, account activity feed, portal account page, report
builder and saved reports drew white cards with gray text and 50 to 900
tints, which invert in light. They now use the same card, edge, text and
tint tokens as the rest of the desk.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
…ck and Tech Admin

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>

# Conflicts:
#	web/apps/desk/src/pages/millwork/BlueprintVerifier.ts
…ollow the mode

Each place that had moved onto a nearest token gets its own token whose dark
value is exactly today's value (the counter dialogs, the glow shadow sizes,
the configurator text, the scanner dialog and matrix row hover) and whose
light value is the palette's nearest step; the dark unchanged leg pins them.
Secondary chips and tags read the voice tokens: today's neutrals in dark,
sage in light. The boot screens apply the stored mode before the first paint
from a same origin script (the CSP refuses inline ones) and read the
variables. One check guards every literal colour across web/apps.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
…ight polish

Dark: drop color-scheme from :root; the portal ground and panel, the scanner
body and badge, the margin modal inputs, the media tab badge and photo
buttons and the route map note each get a token whose dark value is today's;
the dark leg lists every dark variable (none unlisted, none different).
Guard: the allowlist names file plus literal plus reason, hex takes three to
eight digits, named colours in a style are caught. Fuchsia is themed.
A person's key holds only their own choice and a storage listener follows
other tabs. The revenue chart tick, the donut's fulfilled series, the
counter tiles and picture plates, the portal hover row and a portal brand
colour that does not read on the light card follow light only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: colton <colton@futurebuild.ai>
@futurebuildai
futurebuildai merged commit 040cbda into refactor/v1 Oct 15, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant