Skip to content

Align web UI with Lumen Design System#36

Merged
fakechris merged 2 commits into
mainfrom
design/lumen-alignment
Jul 23, 2026
Merged

Align web UI with Lumen Design System#36
fakechris merged 2 commits into
mainfrom
design/lumen-alignment

Conversation

@fakechris

@fakechris fakechris commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Aligns Involute's web UI/UX to the Lumen Design System — the warm, quiet, local-first visual language (IBM Plex, Atelier/Vault dual theme, quiet-utility ethos).

All changes flow through the CSS token layer; page components use semantic classes and need no markup edits.

Changes

  • Type: Geist → IBM Plex Sans / Sans SC / Mono
  • Color: Atelier (light, now the default) — parchment + terracotta; Vault (dark) — near-black + deep blue + cyan
  • Ethos: flat warm backgrounds (removed radial gradients, grid texture, backdrop blur); inline cards drop shadows and lean on 1px borders; shadows kept only on the shell + popovers; radius scale 10/12/16/20/999; global :focus-visible accent ring
  • Default theme flips dark → Atelier light, with a no-flash boot script in index.html

Verification

  • pnpm --filter @turnkeyai/involute-web typecheck
  • web test suite (47 tests) ✅
  • production build ✅
  • light + dark screenshots confirmed faithful to the scheme

Note

In Vault (dark), Lumen's --danger is pink (#f472b6), so the "urgent" label reads pink in dark mode — faithful to the scheme. Easy to swap for a conventional red if preferred.

Summary by CodeRabbit

  • New Features

    • Added an updated visual theme with refreshed typography, colors, spacing, borders, and focus states.
    • Added faster theme initialization to prevent a flash of the wrong theme when loading.
    • Light mode is now the default when no valid theme preference is available.
  • Bug Fixes

    • Improved theme loading reliability when saved preferences cannot be accessed.

Adopt the Lumen "warm light" visual language across the web app: IBM Plex
type, the Atelier (light, default) / Vault (dark) dual theme, and the
quiet-utility ethos. Everything flows through the CSS token layer, so page
components (all semantic classes) need no markup changes.

- tokens: Geist -> IBM Plex Sans/SC/Mono; Atelier + Vault palettes mapped
  onto existing var names; radius scale 10/12/16/20/999; shadows limited to
  shell + popovers; global :focus-visible accent ring.
- ethos: drop body radial gradients + grid texture and backdrop blur for
  flat warm backgrounds; strip shadows from inline cards (borders do the
  structural work).
- default theme flips dark -> Atelier light, with a no-flash boot script in
  index.html.

Verified: typecheck, web tests (47), and production build all pass.
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fakechris, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 669e5651-1ef9-44d0-970e-5fab99a869bd

📥 Commits

Reviewing files that changed from the base of the PR and between a46f5bb and c9ef604.

📒 Files selected for processing (2)
  • packages/web/src/App.tsx
  • packages/web/src/styles/app.css
📝 Walkthrough

Walkthrough

The web app now applies a light theme before first paint, uses light as the runtime fallback, and adopts updated Lumen-aligned typography, tokens, colors, radii, motion, focus styling, and surface treatments.

Changes

Theme initialization and UI styling

Layer / File(s) Summary
Early and runtime theme selection
packages/web/index.html, packages/web/src/App.tsx
The document head validates involute.theme before first paint, and runtime storage failures now fall back to light.
Light and dark design tokens
packages/web/src/styles/app.css
Typography, radius, motion, color, selection, shadow, and priority tokens were updated for explicit light and dark themes.
Application surface styling
packages/web/src/styles/app.css
Shell, toolbar, board, issue, panel, tweaks, and mobile surfaces now use standardized backgrounds, borders, radii, and reduced blur and shadow effects.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ThemeBoot as index.html theme boot
  participant LocalStorage
  participant DocumentRoot as document.documentElement
  participant AppTheme as App.tsx getStoredTheme
  ThemeBoot->>LocalStorage: Read involute.theme
  LocalStorage-->>ThemeBoot: dark, light, or error
  ThemeBoot->>DocumentRoot: Set data-theme
  AppTheme->>LocalStorage: Read stored theme
  LocalStorage-->>AppTheme: Stored theme or error
  AppTheme->>DocumentRoot: Apply runtime theme fallback
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: aligning the web UI with the Lumen Design System.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch design/lumen-alignment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/web/src/styles/app.css (2)

8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stylelint import-notation will fail CI. The rule expects the plain string form rather than url(...). Both are valid CSS; switching to a string satisfies the configured lint rule.

♻️ Proposed fix
-@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Sans+SC:wght@400;500;600;700&display=swap');
+@import 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Sans+SC:wght@400;500;600;700&display=swap';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/styles/app.css` at line 8, Update the Google Fonts `@import`
declaration in app.css to use the plain quoted string form instead of url(...),
preserving the existing font URL and query parameters so it satisfies
Stylelint’s import-notation rule.

Source: Linters/SAST tools


11-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

value-keyword-case is flagging real font-family names. Stylelint wants BlinkMacSystemFont, Roboto, Menlo, Consolas, Georgia lowercased, but these are proper font names and blindly lowercasing them is undesirable. Prefer adding them to ignoreKeywords (or disabling the rule for these declarations) in your Stylelint config rather than editing the names, so CI passes without altering the intended font stack.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/styles/app.css` around lines 11 - 13, Update the Stylelint
configuration for value-keyword-case to ignore the proper font-family names used
by the --font-sans, --font-mono, and --font-serif declarations, including
BlinkMacSystemFont, Roboto, Menlo, Consolas, and Georgia. Preserve the original
font stack casing and avoid changing the CSS declarations.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/web/src/styles/app.css`:
- Around line 171-175: Increase the contrast of the :focus-visible outline in
app.css by replacing the 32% mixed accent color with var(--accent) or another
stronger-contrast accent shade. Preserve the existing 3px outline and 2px offset
while ensuring the light-theme focus ring meets the required visibility.

---

Nitpick comments:
In `@packages/web/src/styles/app.css`:
- Line 8: Update the Google Fonts `@import` declaration in app.css to use the
plain quoted string form instead of url(...), preserving the existing font URL
and query parameters so it satisfies Stylelint’s import-notation rule.
- Around line 11-13: Update the Stylelint configuration for value-keyword-case
to ignore the proper font-family names used by the --font-sans, --font-mono, and
--font-serif declarations, including BlinkMacSystemFont, Roboto, Menlo,
Consolas, and Georgia. Preserve the original font stack casing and avoid
changing the CSS declarations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c36aa95e-51c8-476b-825a-73f8506b1e41

📥 Commits

Reviewing files that changed from the base of the PR and between 119fd29 and a46f5bb.

📒 Files selected for processing (3)
  • packages/web/index.html
  • packages/web/src/App.tsx
  • packages/web/src/styles/app.css

Comment on lines +171 to +175
/* Focus — 3px accent outline at 2px offset (Lumen :focus-visible). */
:focus-visible {
outline: 3px solid color-mix(in srgb, var(--accent) 32%, transparent);
outline-offset: 2px;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python3 - <<'PY'
def lin(c):
    c/=255
    return c/12.92 if c<=0.03928 else ((c+0.055)/1.055)**2.4
def L(r,g,b):
    return 0.2126*lin(r)+0.7152*lin(g)+0.0722*lin(b)
def ratio(a,b):
    l1,l2=L(*a),L(*b)
    hi,lo=max(l1,l2),min(l1,l2)
    return (hi+0.05)/(lo+0.05)
accent=(159,79,36); alpha=0.32
for name,bg in [("bg",(247,246,242)),("bg-raised",(255,253,250)),("bg-sunken",(239,236,229))]:
    eff=tuple(round(alpha*a+(1-alpha)*b) for a,b in zip(accent,bg))
    print(f"over {name}: outline≈{eff} contrast={ratio(eff,bg):.2f}:1 (need >=3:1)")
PY

Repository: fakechris/Involute

Length of output: 356


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate app.css =="
fd -a 'app.css' . | sed 's#^\./##'

echo
echo "== relevant CSS variables and focus rules =="
if [ -f packages/web/src/styles/app.css ]; then
  nl -ba packages/web/src/styles/app.css | sed -n '1,230p'
fi

echo
echo "== search for Atelier/light palette usage =="
rg -n "Atelier|atelier|accent|bg-raised|bg-sunken|--bg" -S . -g '!node_modules' -g '!dist' -g '!build' | head -n 200

Repository: fakechris/Involute

Length of output: 315


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant CSS variables and focus rules =="
[ -f packages/web/src/styles/app.css ] && sed -n '1,230p' packages/web/src/styles/app.css

echo
echo "== search for Atelier/light palette usage =="
rg -n "Atelier|atelier|accent|bg-raised|bg-sunken|--bg" -S . -g '!node_modules' -g '!dist' -g '!build' | head -n 200

Repository: fakechris/Involute

Length of output: 13771


🌐 Web query:

WCAG 2.4.11 Focus Appearance level AA contrast outline outline offset specification

💡 Result:

There is a common confusion regarding the numbering of the WCAG Focus Appearance criteria. Success Criterion 2.4.11 is titled Focus Not Obscured (Minimum) (Level AA) [1][2], while the criteria detailing specific requirements for focus indicator size and contrast are found under Success Criterion 2.4.13 Focus Appearance (Level AAA) [3][4][5]. WCAG 2.4.11 (Level AA) does not specify requirements for outline thickness, contrast, or offset [1][2]. Its purpose is to ensure that when a component receives keyboard focus, it is not entirely hidden by author-created content (such as sticky headers or footers) [1][2]. Requirements for focus indicator size and contrast are specified in WCAG 2.4.13 (Level AAA) [3][4]. While 2.4.13 is the relevant standard for appearance, it does not mandate specific CSS properties like outline or outline-offset, but rather defines functional requirements for the indicator's area and contrast change [3][6][5]: 1. Size (Minimum Area): The focus indicator must be at least as large as the area of a 2 CSS pixel thick perimeter of the unfocused component [3][6][4]. 2. Contrast (State Change): There must be a contrast ratio of at least 3:1 between the pixels of the indicator in the focused state versus the same pixels in the unfocused state [3][6][5]. Although not required by the standard, using the CSS outline and outline-offset properties is a widely accepted technique to meet these criteria [6][7][5]. A common, compliant implementation is to use an outline at least 2px thick, often combined with an outline-offset to separate the indicator from the component's edge, ensuring it remains distinct [6][4][5]. Top Results: [1], [2], [3], [6], [4], [5]

Citations:


Increase the Atelier focus-ring contrast

The 32% mixed light accent produces ~1.6:1 contrast against the parchment backgrounds, below WCAG 2.4.13 Focus Appearance’s 3:1 state-change requirement. Use var(--accent) or a stronger contrast shade for :focus-visible so keyboard focus remains reliably visible in the light theme.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/styles/app.css` around lines 171 - 175, Increase the
contrast of the :focus-visible outline in app.css by replacing the 32% mixed
accent color with var(--accent) or another stronger-contrast accent shade.
Preserve the existing 3px outline and 2px offset while ensuring the light-theme
focus ring meets the required visibility.

# Conflicts:
#	packages/web/src/styles/app.css
@fakechris
fakechris merged commit de94abd into main Jul 23, 2026
2 checks passed
@fakechris
fakechris deleted the design/lumen-alignment branch July 23, 2026 11:58
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