diff --git a/documentation/GUIDE__AE_UI_Style_Guidelines.md b/documentation/GUIDE__AE_UI_Style_Guidelines.md new file mode 100644 index 00000000..f0773bbf --- /dev/null +++ b/documentation/GUIDE__AE_UI_Style_Guidelines.md @@ -0,0 +1,248 @@ +# Aether UI — Design System Style Guidelines +> **Version:** 1.0 (2026-03-06) +> **Author:** One Sky IT / Scott Idem +> **Scope:** All Aether SvelteKit frontend components +> **Related:** `AE__UI_Component_Patterns.md`, `ae-firefly.css`, `documentation/AE__Components.md` + +--- + +## 1. Design Philosophy + +**"Shiny serenity, like a firefly."** + +The Aether UI is calm, focused, and softly luminous. It must be immediately readable under conference-room lighting, at a glance, by presenters who are nervous and in a hurry. Staff in the Speaker Ready Room need scan-speed identity confirmation. Remote presenters uploading files from home need a clear, unambiguous interface that doesn't waste their time. + +Core principles: +- **Identity first.** The user's first question is always *"Am I in the right place?"* Answer it with the hero card — name, time, room — before anything else is shown. +- **Progressive disclosure.** Admin fields (codes, IDs, passcodes) are hidden unless `edit_mode` is active. +- **Theme-aware always.** Zero hardcoded colors. Every background, border, and text color must respond to light/dark mode and the active theme via CSS variables. +- **Transitions, not pops.** Every interactive state change is smoothed with `transition-colors duration-200`. +- **Section 508 / WCAG 2.1 AA** compliance is non-negotiable. Contrast ratios, focus indicators, ARIA labels, and screen-reader regions are required everywhere. + +--- + +## 2. The AE_Firefly Theme + +**App default since 2026-03-06.** Set in `ae_stores.ts` as `theme_name = 'AE_Firefly'`. +File: `src/ae-firefly.css` | Activated by: `data-theme="AE_Firefly"` + +| Role | Palette Name | Hue | Use Case | +|---|---|---|---| +| **Primary** | Luminescent Teal | ~184° | Primary actions, date/time chips, focus rings, anchor links | +| **Secondary** | Warm Amber-Gold | ~90° | Secondary actions, copy/email buttons, soft highlights | +| **Tertiary** | Night-Sky Indigo | ~277° | Location/room chips, depth accents | +| **Surface** | Moonlit Slate | ~215–233° | All backgrounds — off-white (light) → midnight slate (dark) | +| **Warning** | Amber semantic | n/a | Disabled/inactive records, "no results" states, code badges | +| **Success** | Green semantic | n/a | Active/complete states, file count badges | +| **Error** | Red semantic | n/a | Errors, disabled-presenter states | + +### Contrast Guarantees +- Body text (`surface-950` on `surface-50`): > 15:1 in light mode ✓ +- Primary buttons: ≥ 3:1 for interactive component threshold ✓ +- Designed using OKLCH perceptual lightness — not HSL estimates + +--- + +## 3. Color Token Rules + +### ✅ Always Use Theme Tokens + +**Backgrounds / surfaces:** +``` +bg-surface-50-900 ← card faces (light: near-white, dark: deep slate) +bg-surface-100-900 ← inner sections, code blocks, secondary panels +bg-surface-50-950 ← page-level containers +bg-surface-200-800 ← skeleton pulse placeholders, dividers +``` + +**Borders:** +``` +border-surface-200-800 ← standard card/panel borders +border-primary-500 ← focus rings (via focus-visible:ring) +border-warning-500 ← warning/caution interactive zones +border-surface-500/20 ← subtle section dividers +``` + +**Primary color accents (teal):** +``` +bg-primary-500/10 ← tinted chip background (time chips) +text-primary-700 dark:text-primary-300 ← chip text with auto dark mode +hover:text-primary-500 ← link hover color +``` + +**Tertiary color accents (indigo):** +``` +bg-tertiary-500/10 ← tinted chip background (room/location chips) +text-tertiary-700 dark:text-tertiary-300 +``` + +**Skeleton presets:** +``` +preset-tonal-warning ← "no results", disabled rows, code tag badges +preset-tonal-primary ← primary action buttons +preset-tonal-surface ← neutral/secondary actions, status badges +preset-tonal-success ← success states, file count badges +preset-tonal-error ← error/blocked states +preset-filled-*-500 ← solid-fill buttons (hover state for tonal) +``` + +**Warning/error semantic backgrounds:** +``` +bg-warning-100 border border-warning-300 ← inline warning banners +bg-error-100 border border-error-300 ← inline error banners +``` + +--- + +### ❌ Never Use These + +| Forbidden | Reason | Replace With | +|---|---|---| +| `bg-gray-*` | Fixed color, breaks dark mode | `bg-surface-*` tokens | +| `bg-neutral-*` | Same — fixed hue | `bg-surface-*` tokens | +| `bg-white` | Light-mode only | `bg-surface-50-900` | +| `text-gray-*` | Breaks dark mode | `opacity-60` on inherited text | +| `text-neutral-*` | Same | `opacity-*` | +| `border-gray-*` | Non-theme border | `border-surface-200-800` | +| `bg-yellow-*`, `text-yellow-*` | Bypasses warning semantic | `preset-tonal-warning` | +| `bg-red-*`, `text-red-*` | Bypasses error semantic | `bg-error-100` / `preset-tonal-error` | +| `bg-white dark:bg-gray-800` | Manual light/dark pair | Let theme tokens handle it — remove entirely | +| `text-gray-600 dark:text-gray-400` | Manual light/dark pair | `opacity-60` | +| `rounded-container-token` | Skeleton v3 class | `rounded-xl` | +| `variant-soft-*` | Skeleton v3 class | `preset-tonal-*` | +| `variant-ghost-*` | Skeleton v3 class | `preset-ghost-*` | +| `variant-ringed-*` | Skeleton v3 class | `preset-outlined-*` | +| `variant-filled-*` | Skeleton v3 class | `preset-filled-*` | +| `preset-filled-surface-300-700` | v3 dual-shade notation | `bg-surface-200-800` or `bg-surface-100-900` | +| `preset-filled-surface-400-600` | v3 dual-shade notation | `bg-surface-100-900` | +| `overflow-x-scroll` | Forces scrollbar visible | `overflow-x-auto` | + +--- + +## 4. Skeleton v3 → v4 Migration Reference + +The app uses **Skeleton v4**. v3 classes produce wrong or zero styling and must be updated on sight. + +| Skeleton v3 | Skeleton v4 Equivalent | +|---|---| +| `variant-soft-primary` | `preset-tonal-primary` | +| `variant-soft-secondary` | `preset-tonal-secondary` | +| `variant-soft-warning` | `preset-tonal-warning` | +| `variant-soft-success` | `preset-tonal-success` | +| `variant-ghost-success` | `preset-ghost-success` | +| `variant-ghost-warning` | `preset-ghost-warning` | +| `variant-ringed-warning` | `preset-outlined-warning` | +| `variant-filled-primary` | `preset-filled-primary` | +| `variant-filled-warning` | `preset-filled-warning` | +| `rounded-container-token` | `rounded-xl` | +| `rounded-token` | `rounded-md` | +| `card` (standalone) | `card preset-tonal-surface` or surface div pattern | +| `badge` (standalone) | `badge preset-tonal-surface` | +| `chip` | `badge preset-tonal-*` | + +--- + +## 5. Transitions & Animation + +All interactive state changes must be smoothed — no hard pops. + +| Element | Classes | +|---|---| +| Table row | `transition-colors duration-200` on `` | +| List item card | `transition-colors duration-200` on `
  • ` | +| Link hover | `transition-colors duration-200` on `` | +| Info chips | `transition-colors duration-200` on `` | +| QR code toggle (size) | `transition-all duration-500` on `` | +| Collapsible sections | Use Skeleton `Accordion` or CSS `transition-all` — don't add custom unless needed | +| Buttons | Handled automatically by Skeleton preset classes | + +--- + +## 6. Loading / Skeleton States + +When `liveQuery` data is still resolving, show pulse placeholders instead of nothing: + +```svelte + +
    + + +
    + + +
    +``` + +Always wrap in `{#if $lq__obj}{...}{:else}...skeleton...{/if}` — **never** show real content structure before data exists. + +--- + +## 7. Dark Mode Rules + +- **Never write `dark:` overrides for background or text colors.** The Firefly theme handles both modes through CSS variables. Writing `dark:bg-gray-800` or `dark:text-gray-400` bypasses the theme and breaks if the user switches themes. +- **Exception allowed:** `dark:text-primary-300` and `dark:text-tertiary-300` in info chips are intentional — they reference theme variables that gracefully degrade. +- **Exception allowed:** `dark:border-surface-700` in fine-grained border work when `border-surface-200-800` isn't strong enough. + +--- + +## 8. Accessibility (Section 508 / WCAG 2.1 AA) + +| Requirement | Implementation | +|---|---| +| Decorative icons | `aria-hidden="true"` on all `` | +| Icon-only buttons | `aria-label="..."` or `title="..."` + visible context | +| Async content regions | `role="status" aria-live="polite"` on loading/empty sections | +| Focus indicators | `focus-visible:ring-2 focus-visible:ring-primary-500` on custom interactive elements | +| Interactive dialogs | `aria-haspopup="dialog"` on trigger buttons | +| Form inputs | Visible `