Skip to content

feat(ui): add app typeface and a real dark-mode elevation ladder - #1754

Merged
giswqs merged 3 commits into
mainfrom
feat/ui-elevation-typography
Aug 7, 2026
Merged

feat(ui): add app typeface and a real dark-mode elevation ladder#1754
giswqs merged 3 commits into
mainfrom
feat/ui-elevation-typography

Conversation

@giswqs

@giswqs giswqs commented Aug 7, 2026

Copy link
Copy Markdown
Member

What

The theme was unmodified shadcn/ui: the stock slate + blue palette, and no font declared anywhere — so the app rendered in Segoe UI on Windows, Roboto on Linux and SF on macOS. This is the first of a planned set of UI modernization changes (typography + elevation); shadow/motion/radius systematization is deliberately left for follow-up.

Typography

  • Self-host IBM Plex Sans (UI) + IBM Plex Mono (coordinate/numeric readouts) via @fontsource, driven from a Tailwind v4 @theme block so both the font-sans/font-mono utilities and preflight pick them up. One matched superfamily, so the StatusBar readout and the surrounding UI share a voice.
  • No CDN: the desktop build must render offline under the Tauri CSP (default-src 'self'). No CSP change was needed — fonts are emitted as same-origin files, and none are inlined as data: URIs.

One trap worth flagging for review

The @font-face rules are imported from main.tsx, not index.css. Tailwind v4 resolves CSS @imports itself and inlines them before Vite sees them, so fontsource's relative url(./files/*.woff2) was never rewritten into an asset reference and zero font files were emitted into dist/. That build succeeds and 404s at runtime, silently falling back to system fonts — i.e. the change would have looked done and been a no-op. Importing from JS routes the CSS through Vite's asset pipeline.

Size

Roman weight axis only, and subsets are unicode-range-scoped:

download
Plex Sans variable, latin 44.6 KB
Plex Mono 400, latin 14.4 KB
What a Latin user actually fetches ~59 KB
Current dist/ 192 MB

The ar/fa/hi/ja/ka/ko/th/zh locales fetch zero Plex bytes — Plex has no coverage there, so they fall through to the system stack per glyph (which is why that fallback list is kept full and ordered). font-display: swap, so nothing blocks first paint.

Elevation

Dark mode had --background, --card and --popover all at 222.2 84% 4.9%, and --border, --input, --muted, --secondary and --accent all at 217.2 32.6% 17.5%five tokens, one colour. Panels, dialogs and menus were indistinguishable from the canvas, separated only by a 1px border.

  • Explicit ladder: background 9% / card 12% / popover 15% / muted 20% / accent 22% (accent must read above popover, since menu items sit on it).
  • Dark saturation drops 84% → ~22%; the old value was a strongly blue-tinted near-black that clashed with satellite imagery in the map view. Light neutrals drop 40% → ~16% for the same reason.
  • --input (a control boundary) is split from --border (decorative); they were identical.
  • Dialog moves to bg-popover — it used bg-background, which under the new ladder would put the highest-elevation surface on the lowest step. Map-floating panels intentionally stay on bg-background/90..95: they are translucent scrims over imagery, where the base step is correct.
  • Dark --ring now matches --primary, as every non-default accent scheme already does.

Accessibility

Every foreground/surface pair clears WCAG AA 4.5:1; the tightest is muted-foreground on accent at 4.82:1.

Input-border contrast improves from 1.23:1 → 1.84:1 (light) and 1.37:1 → 2.58:1 (dark). That is still short of the 3:1 WCAG 1.4.11 asks of control boundaries — both the old and new values fail it. Closing it fully needs a visibly heavier field outline (roughly L 58% in light), which is a design decision rather than a token tweak, so it is left for follow-up rather than smuggled into this PR.

Verification

  • npm run build — clean; font files confirmed emitted into dist/assets/.
  • npm run test:frontend5473 pass, 0 fail.
  • pre-commit run --files <changed> — all hooks pass.
  • Driven in the built app with Playwright in both themes: document.fonts.check() reports Plex Sans and Plex Mono as genuinely loaded (not fallback), and the three dark surfaces measure as distinct sampled pixels — canvas (17,21,28), toolbar (24,28,37), menu and dialog (30,35,46). Light mode verified white by pixel sample.

Light mode is deliberately the smaller change here: it gets the typeface, desaturated neutrals and crisper borders, but no elevation ladder, because white-on-white surfaces there are load-bearing for the 42 map-floating panels. Light-mode depth is a shadow-scale problem, which is the follow-up.

Summary by CodeRabbit

  • Style
    • Added IBM Plex Sans and IBM Plex Mono typography with offline and multilingual fallbacks.
    • Refined light and dark theme colors, borders, surfaces, and focus states for improved contrast and visual hierarchy.
    • Updated dialog surfaces to use popover background styling for better consistency.

The theme was unmodified shadcn/ui: the stock slate + blue palette, and no
font declared anywhere, so the app rendered in Segoe UI on Windows, Roboto on
Linux and SF on macOS.

Typography
- Self-host IBM Plex Sans (UI) + IBM Plex Mono (coordinate/numeric readouts)
  via @fontsource, and drive them from a Tailwind v4 `@theme` block so both the
  `font-sans`/`font-mono` utilities and preflight pick them up. One matched
  superfamily, so the StatusBar readout and the surrounding UI share a voice.
- The @font-face rules are imported from main.tsx, not index.css: Tailwind v4
  resolves CSS @imports itself and inlines them before Vite sees them, so
  fontsource's relative `url(./files/*.woff2)` was never rewritten and no font
  file was emitted into dist/. That builds clean and 404s at runtime, silently
  falling back to system fonts.
- Roman weight axis only, and no CDN — the desktop build must render offline
  under the Tauri CSP (`default-src 'self'`). Subsets are unicode-range scoped,
  so a Latin user downloads ~59 KB and the ar/fa/hi/ja/ka/ko/th/zh locales
  fetch nothing and fall through to the system stack per glyph.

Elevation
- Dark mode had --background, --card and --popover all at 222.2 84% 4.9%, and
  --border, --input, --muted, --secondary and --accent all at 217.2 32.6% 17.5%
  — five tokens, one colour. Panels, dialogs and menus were indistinguishable
  from the canvas, separated only by a 1px border. Replace with an explicit
  ladder: background 9% / card 12% / popover 15% / muted 20% / accent 22%.
- Drop dark-mode saturation from 84% to ~22%: the old value was a strongly
  blue-tinted near-black that clashed with satellite imagery in the map view.
- Split --input (a control boundary) from --border (decorative); both were
  identical. Contrast against their surfaces goes 1.23:1 -> 1.84:1 (light) and
  1.37:1 -> 2.58:1 (dark). Still short of the 3:1 that WCAG 1.4.11 asks of
  control boundaries — closing that fully means a visibly heavier field outline,
  which is a design call left for follow-up.
- Point Dialog at bg-popover; it used bg-background, which under the new ladder
  would put the highest-elevation surface on the lowest step. Map-floating
  panels stay on bg-background/90..95 — they are translucent scrims over
  imagery, where the base step is correct.
- Desaturate the light neutrals from 40% to ~16% so the chrome reads grey next
  to the map rather than tinting blue, and set the dark --ring to --primary, as
  every non-default accent scheme already does.

Every foreground/surface pair clears WCAG AA 4.5:1; the tightest is
muted-foreground on accent at 4.82:1.

Verified in the built app with Playwright in both themes: fonts report as
loaded rather than fallback, and the three dark surfaces measure as distinct
pixels (canvas 17,21,28 / toolbar 24,28,37 / menu and dialog 30,35,46).
Copilot AI lite review requested due to automatic review settings August 7, 2026 05:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d9f1f5b9-e734-4054-b631-1fecfebb98d4

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba72c8 and cd65327.

📒 Files selected for processing (1)
  • packages/ui/src/globals.css

📝 Walkthrough

Walkthrough

The desktop app now uses IBM Plex fonts with system fallbacks. Shared light and dark theme tokens were updated for neutral surfaces, borders, inputs, and focus rings. Dialogs now use the popover background color.

Changes

Visual styling

Layer / File(s) Summary
IBM Plex font integration
apps/geolibre-desktop/package.json, apps/geolibre-desktop/src/main.tsx, apps/geolibre-desktop/src/index.css
The desktop app adds IBM Plex font packages, imports their stylesheets, and defines Tailwind font stacks with system fallbacks.
Theme surfaces and dialog styling
packages/ui/src/globals.css, packages/ui/src/components/dialog.tsx
Light and dark theme tokens now use updated surface, border, input, accent, and focus-ring values. DialogContent uses bg-popover and ring-offset-popover.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit hops through fonts so neat,
Plex Sans makes the pages sweet.
Dark surfaces settle, borders align,
Popover dialogs softly shine.
“Thump!” says the hare—the theme is fine.

🚥 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 clearly summarizes the two primary changes: adding application fonts and introducing a dark-mode elevation ladder.
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 feat/ui-elevation-typography

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.6)
packages/ui/src/globals.css

File contains syntax errors that prevent linting: Line 143: Tailwind-specific syntax is disabled.; Line 147: Tailwind-specific syntax is disabled.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


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.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://11fd8cf5.geolibre-preview.pages.dev
Demo app https://11fd8cf5.geolibre-preview.pages.dev/demo/
Commit cd65327

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@apps/geolibre-desktop/package.json`:
- Around line 34-35: Update the workspace lockfile to include the new
dependencies declared in apps/geolibre-desktop/package.json by running npm
install --package-lock-only from the workspace root, then commit the resulting
package-lock.json.

In `@packages/ui/src/globals.css`:
- Around line 27-30: Keep --border as the decorative token and introduce a
dedicated control-boundary token with at least 3:1 contrast in both themes;
update the MapLibre controls in maplibre-dggal.ts and other affected
interactive-border consumers to use it instead of --border or --input. Add
contrast checks covering normal, hover, and focus states, while preserving
existing decorative-edge usage.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2a711dde-1a20-4f1c-9bab-a98b70eb23a1

📥 Commits

Reviewing files that changed from the base of the PR and between ca6a5fc and e34d240.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • apps/geolibre-desktop/package.json
  • apps/geolibre-desktop/src/index.css
  • apps/geolibre-desktop/src/main.tsx
  • packages/ui/src/components/dialog.tsx
  • packages/ui/src/globals.css

Comment thread apps/geolibre-desktop/package.json
Comment thread packages/ui/src/globals.css
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code review

I reviewed this PR closely, including recomputing the WCAG contrast ratios cited in the code comments (e.g. muted-foreground on dark accent → 4.82:1, light --input vs --background → 1.84:1) by hand from the HSL values — both matched the claims exactly, which gives high confidence in the design-token math throughout. I also checked the Tauri CSP (default-src 'self', no explicit font-src), confirmed no other @theme/fontFamily declarations conflict with the new font tokens, verified no other component hardcodes the old flat dark-mode color values, checked bg-input/font-weight usage for gaps, and confirmed Dialog is the only modal primitive in packages/ui (so no other component needed the same bg-popover fix for consistency).

Bugs: None found.

Security: None found — fonts are self-hosted (no CDN), consistent with the Tauri CSP's default-src 'self'.

Performance: None found — font subsetting/weight choices are deliberate and small (~59 KB for Latin), font-display: swap avoids blocking first paint.

Quality: Minor/low-confidence: DialogClose's ring-offset-background (packages/ui/src/components/dialog.tsx:48, unchanged by this diff) now sits on a bg-popover surface instead of bg-background, but since no ring-offset-* width utility is applied there, the offset color is currently inert and produces no visible artifact — not worth a code change now, just flagging as a latent inconsistency if an offset ring is ever added there later.

CLAUDE.md: No violations — CSP/tile-host allowlist untouched (correctly, since nothing external was added), no node_modules edits, no new hardcoded colors outside the token system, i18n untouched (no new user-facing strings).

Overall this is a well-scoped, carefully verified change; I found nothing worth blocking on.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit cd65327

- Point DialogClose's ring-offset at --popover instead of --background. The
  previous commit moved DialogContent to bg-popover, which left the close
  button declaring a ring offset colour for a surface it no longer sits on.
  Inert today — no ring-offset width utility is applied, so the offset colour
  never paints — but wrong the moment one is added. Verified the
  `ring-offset-popover` utility generates:
  `.ring-offset-popover{--tw-ring-offset-color:hsl(var(--popover))}`.
@giswqs

giswqs commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

Addressed the one item from the Claude review summary in 3ba72c8.

DialogClose was still declaring ring-offset-background after DialogContent moved to bg-popover, so the offset colour named a surface the button no longer sits on. You correctly identified it as inert — no ring-offset-{width} utility is applied, so the width is 0px and the colour never paints — but I'd rather not leave a wrong-surface token in a shared primitive, since it becomes a visible wrong-colour halo the moment someone adds ring-offset-2. Changed to ring-offset-popover and confirmed the utility generates:

.ring-offset-popover{--tw-ring-offset-color:hsl(var(--popover))}

Also checked the GitHub Pages PR preview → Deploy failed note: that is pre-existing and unrelated to this branch — PRs #1753 and #1752 both show the identical failure, and the check reports as skipping rather than failing.

Comment thread packages/ui/src/globals.css Outdated
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • None found. The font-loading trap the PR description calls out (importing @font-face CSS from main.tsx instead of @import-ing it in index.css, to route it through Vite's asset pipeline) is correctly implemented, and no CSP change was needed for either the Tauri desktop build (default-src 'self' with no font-src override) or the nginx web build (same). Confidence: high.

Security

  • None found. Fonts are self-hosted via @fontsource/@fontsource-variable, no CDN/data: URIs introduced, consistent with the offline/CSP requirements in CLAUDE.md.

Performance

  • None found. font-display: swap avoids blocking first paint, and the extra ibm-plex-mono 700-weight import is justified (used by font-mono font-bold in CommentsPanel.tsx), so it isn't dead weight.

Quality

  • Misleading comment added in packages/ui/src/globals.css (lines 72–74): it claims dark --ring matches --primary "as every non-default accent scheme below already does," but [data-theme="emerald"].dark has --ring: 142.4 71.8% 29.2% vs. --primary: 142.1 70.6% 45.3% — they don't match. The mismatch predates this PR, but the new comment states an invariant that isn't actually true, which could mislead future edits. Confidence: medium. (Posted inline.)
  • I independently recomputed the HSL→RGB and WCAG contrast values cited in the PR description (elevation ladder RGB samples, muted-foreground/accent 4.82:1, light/dark input-border contrast 1.23→1.84 and 1.37→2.58) and all matched exactly, giving good confidence the color/contrast work is correct and not just asserted.

CLAUDE.md

  • No violations found. New user-facing behavior doesn't add untranslated strings, RTL logical-property conventions aren't touched by this change (only color tokens/border classes), and no new external tile/font CDN host was introduced that would require a Tauri CSP allowlist update.

- Correct the --ring comment in .dark. It claimed every non-default accent
  scheme already pairs ring with primary; emerald did not (--ring
  142.4 71.8% 29.2% vs --primary 142.1 70.6% 45.3%). Violet, rose and amber do.

- Pair emerald's dark --ring with its --primary. Checking the above surfaced a
  real side effect of this PR: against the old near-black canvas emerald's
  darker ring cleared the 3:1 focus-indicator floor at 3.98:1, but the lifted
  surfaces drop it to 3.65:1 on --background and 3.13:1 on --popover — passing
  by ~4%, so any later surface tweak would silently break it. Pairing with
  primary restores headroom (8.04:1 on --background) and makes the
  ring == primary invariant actually hold across all four schemes.
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code review

I reviewed the full diff (font self-hosting, Tailwind @theme typography tokens, the dark-mode elevation ladder, and the Dialog surface change) against the surrounding code.

Bugs: None found. The @fontsource imports are correctly placed in main.tsx per the documented Vite/Tailwind @import-inlining trap; apps/geolibre-desktop/vite.config.ts's PWA globPatterns (line 759) already includes woff/woff2, so the new font files will be precached offline without a separate fix. text-popover-foreground and ring-offset-popover are valid generated Tailwind utilities given the existing tailwind.config.js color mapping (confidence: high).

Security: No CSP change is needed, as claimed — tauri.conf.json's CSP has no font-src directive, so same-origin font assets are covered by default-src 'self' (confidence: high).

Performance: None — font subsetting and font-display: swap choices are reasonable; no regressions.

Quality: The Dialogbg-popover change brings it in line with dropdown-menu.tsx and tooltip.tsx, which already use bg-popover/text-popover-foreground — this fixes a real inconsistency rather than introducing one (confidence: high). I independently recomputed the WCAG contrast ratios cited in the comments (dark muted-foreground on accent = 4.82:1, light --input vs --background = 1.84:1) and both match the stated figures precisely, so the accessibility claims are trustworthy rather than just asserted (confidence: high).

CLAUDE.md adherence: Consistent with repo conventions — no new external tile/font host was added (self-hosted via @fontsource), so the Tauri CSP allowlist correctly did not need updating, and no node_modules files were hand-edited for MapLibre control styling.

No inline comments were posted since no defects were identified.

@giswqs
giswqs merged commit 556589f into main Aug 7, 2026
22 checks passed
@giswqs
giswqs deleted the feat/ui-elevation-typography branch August 7, 2026 18:23
giswqs added a commit that referenced this pull request Aug 7, 2026
…ius (#1764)

* feat(ui): codify map-floating glass, theme-aware shadows, tighter radius

Follow-up to #1754. Three changes, all working through tokens rather than
per-component edits.

Map-floating chrome ("instrument glass")
- The translucent-blur treatment was already in use across 11 components, but
  copy-pasted with drifted values: bg-background/90 vs /95, backdrop-blur-sm vs
  -md vs bare backdrop-blur. Replace all of them with one `.map-glass` class so
  the look has a single home.
- Encodes the rule the app was already half-following: chrome docked BESIDE the
  map (toolbar, status bar, side panels) is opaque; panels floating OVER the map
  are translucent, because translucency is what signals "this sits above your
  data".
- Deliberately a plain unlayered class, not an `@utility`. It is applied next to
  components that already emit a bg-* utility (MapGrid's Button variant="outline"
  carries bg-background); as a utility both would sit in the same cascade layer
  and the winner would depend on Tailwind's internal sort rather than intent.
- Added to MapGrid's pane controls, which float over the map but never had it.
  Deliberately NOT added to PixelTimeSeriesControl or the dialogs: that panel is
  content (a chart) rather than chrome, and dialogs sit on a dimmed overlay, not
  on the map. DesktopShell's file-drop scrim keeps its own bg-background/70,
  being a full-cover dim rather than a panel.
- Falls back to 97% opaque via @supports where backdrop-filter is unavailable;
  at 85% with no blur, panels over live imagery are unreadable.

Theme-aware shadow scale
- Tailwind v4 bakes a 10%-black colour into its shadow utilities, so all ~65
  shadow sites in the app were effectively invisible in dark mode and elevation
  rested entirely on the surface ladder from #1754. Redefine --shadow-sm/md/lg/xl
  against inheritable --elev-penumbra/--elev-umbra tokens that switch per theme.
  Fixes every existing site without touching a component.
- Those tokens are plain custom properties precisely so they inherit: Tailwind
  registers --tw-shadow-color with `inherits: false`, so retinting shadows by
  setting that on :root silently does nothing.
- Colours are written bare; Tailwind adds the var(--tw-shadow-color, …) wrapper
  itself, so `shadow-<color>` overrides keep working.

Other
- --radius 0.5rem -> 0.375rem. A dense tool UI reads sharper, and the derived
  md/sm steps stay positive. This is the most subjective change here.
- One global prefers-reduced-motion guard. Two components respected the
  preference against ~53 transition sites; motion is reduced to a near-instant
  cross-fade rather than removed, since an abrupt swap is its own problem.

Verified in the built app with Playwright: 5 .map-glass panels render as
rgba(17,21,28,0.85) with blur(12px) saturate(1.4) and radius 4px, shadows
resolve to rgba(0,0,0,0.4)/rgba(0,0,0,0.55) in dark instead of the old
invisible 10% black, and the toolbar stays rgb(255,255,255) opaque in light.

Not verified: backdrop-filter cost on real GPU compositing. The test browser
runs SwiftShader, where blur on/off medians were identical (66.8 vs 66.7ms) at a
software-bound ~15fps, so the measurement says nothing useful. Note the blur
radius went from 4px to 12px plus a saturate(), so GPU cost is higher than on
main — worth a look on real hardware.

* Address Claude review feedback

- Move .map-glass into Tailwind's utilities layer (@Utility) instead of leaving
  it unlayered. Unlayered CSS beats every layered declaration for the same
  property, and cascade-layer precedence resolves before specificity, so the
  unlayered rule also beat `hover:bg-accent` — killing the hover fill on
  MapGrid's two pane buttons and the CollaborationStatusBadge toggle. Confirmed
  dead in the built app before the fix (idle == hovered on all three), and
  restored after (idle rgba(17,21,28,0.85) -> hover rgb(46,53,66) = --accent).
  The @supports fallback is nested inside the utility so it stays in the layer;
  hoisting it out would reintroduce the same bug where backdrop-filter is
  unsupported.

- Switch MapGrid's layers trigger from Button variant="outline" to "ghost".
  Inside the utilities layer, outline's own bg-background ties with map-glass on
  specificity and won on order, so that button rendered opaque beside its glass
  siblings. ghost sets no base background and still supplies hover:bg-accent;
  the border is restored explicitly. (bg-transparent was tried first and is
  worse — tailwind-merge drops bg-background, but bg-transparent then beats
  map-glass and the button renders fully see-through.)

- Add --shadow-xs and bare --shadow to the elevation scale. Only sm/md/lg/xl
  were redefined, but shadow-xs is what @geolibre/ui's form primitives use
  (input, textarea, select, color-field, color-ramp-select) plus 7 app sites, so
  every input, textarea, select and colour field in the app was still on the
  invisible-in-dark 10% black this scale exists to fix. Verified: a real input's
  shadow now resolves to rgba(0,0,0,0.4) in dark mode. shadow-2xl and
  shadow-inner are unused and left out, with a note to extend if that changes.

* Address Claude review feedback

- Exempt indeterminate progress indicators from the reduced-motion guard. The
  blanket `animation-iteration-count: 1` gave every spinner a single 0.01ms
  iteration and then froze it mid-rotation, so during a long raster/segmentation/
  conversion job the UI would read as hung — a worse outcome for the same user
  than the abrupt transitions the guard exists to fix. 70 animate-spin sites and
  6 animate-pulse were affected. Slowed rather than stopped (1.5s / 3s, still
  infinite): the preference targets large vestibular-triggering motion, which a
  small in-place spinner is not, so this keeps the "still working" signal while
  calming it. Verified under emulated prefers-reduced-motion: animate-spin
  resolves to 1.5s/infinite and animate-pulse to 3s/infinite, while a decorative
  `animate-in fade-in-0` is still suppressed to 0.00001s/1.

- Bump Dialog from shadow-lg to shadow-xl. The scale documents shadow-xl as
  "modal dialog", but the shared primitive every modal renders through was still
  on shadow-lg — the same step as "panel floating over the map" — so the
  ladder's one-step-per-surface invariant was false for the one component that
  most literally is a modal dialog. Bumping the primitive makes the documented
  mapping true rather than aspirational.
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.

2 participants