/* platform.css — the universal theme, served centrally by platform-api at
   /platform.css (one copy for every site, mirrors /analytics.js). ADR 008 pattern.

   THE design system is the jameslcowan system (Apple neutral palette, SF Pro
   stacks, --theme-* semantic layer with system light/dark + data-theme override,
   accent scale, spacing/radius/motion/blur/tracking). Its single source of truth
   is sites/jameslcowan/design/tokens.json; that repo's build generates
   static/tokens.css, and scripts/sync-platform-theme.mjs copies it verbatim into
   the marked block below. Never hand-edit inside the markers.

   Three cascade layers, low to high:
     platform.reset  — box model, margin, media, form normalization
     platform.tokens — the jameslcowan token set (synced) + platform additions
                        (z-index, safe-area) + a legacy compat block kept until
                        every site is converted off the old panax-era names.
     platform.interaction — the global transparent-interaction fixes (tap
                        highlight, touch delay, text-size-adjust, focus ring,
                        reduced motion) applied ONCE instead of per-element.
     platform.components — the universal control layer (ADR 015): every control
                        with its whole state matrix, skinned entirely by --ui-*
                        tokens. A menu, not a mandate: see docs/UI-LAYER.md.

   Everything here is layered. A site's own (unlayered) CSS always beats a layered
   rule, so this is a floor other stylesheets build on, never a ceiling that fights
   them. Sites override the accent slot (--accent-*) with their brand hue.
   Load it FIRST in <head>, before any site stylesheet. */

@layer platform.reset, platform.tokens, platform.interaction, platform.components;

/* ---------------------------------------------------------------- reset ---- */
@layer platform.reset {
  *, *::before, *::after { box-sizing: border-box; }

  html {
    -webkit-text-size-adjust: 100%;
    -moz-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scrollbar-gutter: stable;
  }

  body { margin: 0; min-height: 100svh; }

  /* Remove default margins; sites set their own rhythm via the spacing scale. */
  h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol { margin: 0; }
  ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }

  /* Media behaves like a block that never overflows its column. */
  img, svg, video, canvas, audio, iframe, embed, object { display: block; max-width: 100%; }
  img, video { height: auto; }

  /* Forms inherit type; buttons look like buttons only when a site says so. */
  input, button, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
  button { background: none; border: 0; padding: 0; cursor: pointer; }
  a { color: inherit; text-decoration: inherit; }

  /* Predictable text wrapping for headings and prose. */
  h1, h2, h3, h4 { text-wrap: balance; }
  p, li { text-wrap: pretty; }
}

/* --------------------------------------------------------------- tokens ---- */
@layer platform.tokens {
  /* BEGIN jameslcowan-tokens (synced by scripts/sync-platform-theme.mjs; do not hand-edit) */
/* Generated from design/tokens.json - do not edit manually */
/* Pantone 2026: System blue (vivid) + Apple neutral (custom) */

:root {
    color-scheme: light dark;

    /* Accent scale */
    --accent-50: #EBF4FF;
    --accent-100: #D6EAFF;
    --accent-200: #A8D4FF;
    --accent-300: #6BB5FF;
    --accent-400: #3399FF;
    --accent-500: #0A84FF;
    --accent-600: #006FE6;
    --accent-700: #0059C2;
    --accent-800: #004099;
    --accent-900: #002E6E;
    --accent-950: #001A42;

    /* Light theme */
    --light-bg: #FFFFFF;
    --light-bg-subtle: #F5F5F7;
    --light-bg-elevated: #FFFFFF;
    --light-bg-raised: #EFEFF4;
    --light-bg-surface: #E8E8ED;
    --light-bg-muted: #DCDCE2;
    --light-bg-soft: #C7C7CC;
    --light-bg-strong: #AEAEB2;
    --light-bg-emphasis: #8E8E93;
    --light-bg-trans-tint: #FFFFFF;
    --light-bg-trans-light: #F5F5F7;
    --light-bg-trans: #EFEFF4;
    --light-bg-trans-dark: #E8E8ED;
    --light-color: #1D1D1F;
    --light-color-dim: #6E6E73;
    --light-color-muted: #86868B;
    --light-border: #D2D2D7;
    --light-border-nav: #DFDFDF;
    --light-border-strong: #AEAEB2;
    --light-border-accent: #0A84FF;

    /* Dark theme */
    --dark-bg: #000000;
    --dark-bg-subtle: #1C1C1E;
    --dark-bg-elevated: #2C2C2E;
    --dark-bg-raised: #3A3A3C;
    --dark-bg-surface: #48484A;
    --dark-bg-muted: #636366;
    --dark-bg-soft: #8E8E93;
    --dark-bg-strong: #AEAEB2;
    --dark-bg-emphasis: #C7C7CC;
    --dark-bg-trans-tint: #000000;
    --dark-bg-trans-light: #1C1C1E;
    --dark-bg-trans: #2C2C2E;
    --dark-bg-trans-dark: #3A3A3C;
    --dark-color: #F5F5F7;
    --dark-color-dim: #98989D;
    --dark-color-muted: #AEAEB2;
    --dark-border: #38383A;
    --dark-border-nav: #202020;
    --dark-border-strong: #48484A;
    --dark-border-accent: #3399FF;

    /* Typography */
    --font-body: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;
    --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", system-ui, sans-serif;
    --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "Segoe UI Mono", monospace;
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.0625rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;
    --leading-tight: 1.2;
    --leading-normal: 1.47;
    --leading-relaxed: 1.6;
    --weight-normal: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;
    --tracking-tight: -0.022em;
    --tracking-normal: 0;
    --tracking-wide: 0.04em;
    --tracking-wider: 0.06em;
    --tracking-widest: 0.12em;

    /* Spacing */
    --space-xs: 0.25rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2rem;
    --space-2xl: 3rem;
    --space-3xl: 4rem;

    /* Radius */
    --radius-2xs: 2px;
    --radius-xs: 4px;
    --radius-sm: 6px;
    --radius-chip: 8px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 18px;
    --radius-2xl: 24px;
    --radius-tile: 22.37%;

    /* Motion */
    --motion-duration-short-1: 50ms;
    --motion-duration-short-2: 100ms;
    --motion-duration-short-3: 150ms;
    --motion-duration-short-4: 200ms;
    --motion-duration-medium-1: 250ms;
    --motion-duration-medium-2: 300ms;
    --motion-duration-medium-3: 350ms;
    --motion-duration-medium-4: 400ms;
    --motion-duration-long-1: 450ms;
    --motion-duration-long-2: 500ms;
    --motion-duration-long-3: 550ms;
    --motion-duration-long-4: 600ms;
    --motion-duration-extra-long-1: 700ms;
    --motion-duration-extra-long-2: 800ms;
    --motion-easing-standard: cubic-bezier(0.2, 0, 0, 1);
    --motion-easing-standard-decelerate: cubic-bezier(0, 0, 0, 1);
    --motion-easing-standard-accelerate: cubic-bezier(0.3, 0, 1, 1);
    --motion-easing-emphasized: cubic-bezier(0.2, 0, 0, 1);
    --motion-easing-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
    --motion-easing-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
    --motion-press: var(--motion-duration-short-2) var(--motion-easing-standard);
    --motion-hover: var(--motion-duration-short-3) var(--motion-easing-standard);
    --motion-state: var(--motion-duration-medium-1) var(--motion-easing-standard);
    --motion-enter: var(--motion-duration-short-4) var(--motion-easing-emphasized-decelerate);
    --motion-exit: var(--motion-duration-short-3) var(--motion-easing-emphasized-accelerate);
    --motion-sheet: var(--motion-duration-medium-4) var(--motion-easing-emphasized-decelerate);
    --motion-sheet-exit: var(--motion-duration-medium-1) var(--motion-easing-emphasized-accelerate);
    --motion-fast: var(--motion-hover);
    --motion-normal: var(--motion-state);
    --motion-slow: var(--motion-duration-medium-2) var(--motion-easing-standard);

    /* Blur */
    --blur-xs: 8px;
    --blur-sm: 12px;
    --blur-md: 20px;
    --blur-lg: 28px;
    --blur: 20px;

    /* Icon sizes (from iconify-icon.pl-icon and --pl-profile-section-icon-size) */
    --icon-size-inline: 1.25em;
    --icon-size-section: 1.75rem;
}

/* Active theme (html[data-theme] overrides system preference) */
:root {
    --theme-bg: var(--light-bg);
    --theme-bg-subtle: var(--light-bg-subtle);
    --theme-bg-elevated: var(--light-bg-elevated);
    --theme-bg-raised: var(--light-bg-raised);
    --theme-bg-surface: var(--light-bg-surface);
    --theme-bg-muted: var(--light-bg-muted);
    --theme-bg-soft: var(--light-bg-soft);
    --theme-bg-strong: var(--light-bg-strong);
    --theme-color: var(--light-color);
    --theme-color-dim: var(--light-color-dim);
    --theme-color-muted: var(--light-color-muted);
    --theme-border: var(--light-border);
    --theme-border-nav: var(--light-border-nav);
    --theme-border-strong: var(--light-border-strong);
    --theme-border-card: var(--light-border);
    --theme-accent-emphasis: var(--accent-500);
    --theme-focus-ring: rgba(10, 132, 255, 0.32);
    --theme-shadow-sm: rgba(11, 20, 31, 0.08);
    --theme-shadow-md: rgba(11, 20, 31, 0.12);
    --theme-shadow-lg: rgba(11, 20, 31, 0.16);
    --theme-nav-blur: var(--blur-lg);
    --theme-shell-bg: transparent;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --theme-bg: var(--dark-bg);
    --theme-bg-subtle: var(--dark-bg-subtle);
    --theme-bg-elevated: var(--dark-bg-elevated);
    --theme-bg-raised: var(--dark-bg-raised);
    --theme-bg-surface: var(--dark-bg-surface);
    --theme-bg-muted: var(--dark-bg-muted);
    --theme-bg-soft: var(--dark-bg-soft);
    --theme-bg-strong: var(--dark-bg-strong);
    --theme-color: var(--dark-color);
    --theme-color-dim: var(--dark-color-dim);
    --theme-color-muted: var(--dark-color-muted);
    --theme-border: var(--dark-border);
    --theme-border-nav: var(--dark-border-nav);
    --theme-border-strong: var(--dark-border-strong);
    --theme-border-card: var(--dark-border-accent);
    --theme-accent-emphasis: var(--accent-400);
    --theme-focus-ring: rgba(51, 153, 255, 0.42);
    --theme-shadow-sm: rgba(0, 0, 0, 0.35);
    --theme-shadow-md: rgba(0, 0, 0, 0.45);
    --theme-shadow-lg: rgba(0, 0, 0, 0.55);
    --theme-nav-blur: var(--blur-xs);
    --theme-shell-bg: var(--dark-bg);
  }
}

:root[data-theme="dark"] {
    --theme-bg: var(--dark-bg);
    --theme-bg-subtle: var(--dark-bg-subtle);
    --theme-bg-elevated: var(--dark-bg-elevated);
    --theme-bg-raised: var(--dark-bg-raised);
    --theme-bg-surface: var(--dark-bg-surface);
    --theme-bg-muted: var(--dark-bg-muted);
    --theme-bg-soft: var(--dark-bg-soft);
    --theme-bg-strong: var(--dark-bg-strong);
    --theme-color: var(--dark-color);
    --theme-color-dim: var(--dark-color-dim);
    --theme-color-muted: var(--dark-color-muted);
    --theme-border: var(--dark-border);
    --theme-border-nav: var(--dark-border-nav);
    --theme-border-strong: var(--dark-border-strong);
    --theme-border-card: var(--dark-border-accent);
    --theme-accent-emphasis: var(--accent-400);
    --theme-focus-ring: rgba(51, 153, 255, 0.42);
    --theme-shadow-sm: rgba(0, 0, 0, 0.35);
    --theme-shadow-md: rgba(0, 0, 0, 0.45);
    --theme-shadow-lg: rgba(0, 0, 0, 0.55);
    --theme-nav-blur: var(--blur-xs);
    --theme-shell-bg: var(--dark-bg);
}

:root[data-theme="light"] {
    --theme-bg: var(--light-bg);
    --theme-bg-subtle: var(--light-bg-subtle);
    --theme-bg-elevated: var(--light-bg-elevated);
    --theme-bg-raised: var(--light-bg-raised);
    --theme-bg-surface: var(--light-bg-surface);
    --theme-bg-muted: var(--light-bg-muted);
    --theme-bg-soft: var(--light-bg-soft);
    --theme-bg-strong: var(--light-bg-strong);
    --theme-color: var(--light-color);
    --theme-color-dim: var(--light-color-dim);
    --theme-color-muted: var(--light-color-muted);
    --theme-border: var(--light-border);
    --theme-border-nav: var(--light-border-nav);
    --theme-border-strong: var(--light-border-strong);
    --theme-border-card: var(--light-border);
    --theme-accent-emphasis: var(--accent-500);
    --theme-focus-ring: rgba(10, 132, 255, 0.32);
    --theme-shadow-sm: rgba(11, 20, 31, 0.08);
    --theme-shadow-md: rgba(11, 20, 31, 0.12);
    --theme-shadow-lg: rgba(11, 20, 31, 0.16);
    --theme-nav-blur: var(--blur-lg);
    --theme-shell-bg: transparent;
}
  /* END jameslcowan-tokens */

  /* Platform additions the jameslcowan set does not carry. */
  :root {
    /* Stacking order — shared so headers/menus/modals never collide */
    --z-base: 1;
    --z-header: 100;
    --z-menu: 200;
    --z-overlay: 500;
    --z-modal: 1000;
    --z-toast: 1500;

    /* Safe-area insets (notches / home indicators) */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);

    --tap-highlight: transparent;
  }

  /* LEGACY COMPAT — panax-era structural names still consumed by site CSS.
     Values unchanged from before the jameslcowan adoption so unconverted pages
     render identically. Remove each alias once no site references it. */
  :root {
    --radius: 12px;
    --radius2: 8px;
    --radius-pill: 999px;
    --space-1: 6px;
    --space-2: 10px;
    --space-3: 14px;
    --space-4: 20px;
    --space-5: 28px;
    --space-6: 36px;
    --space-7: 48px;
    --space-8: 64px;
    --text-md: 1.0625rem;
    --leading-body: 1.65;
    --prose-gap: var(--space-4);
    --prose-gap-lg: var(--space-5);
    --dur-fast: 120ms;
    --dur: 200ms;
    --dur-slow: 320ms;
    --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --focus-ring: var(--theme-focus-ring, color-mix(in srgb, currentColor 40%, transparent));
  }
}

/* ---------------------------------------------------------- interaction ---- */
@layer platform.interaction {
  /* The universal transparent-interaction fix, in ONE place instead of ~40
     per-element copies. No grey/blue flash on tap; no 300ms delay or
     double-tap zoom on controls; no accidental text selection dragging a button. */
  html { -webkit-tap-highlight-color: var(--tap-highlight, transparent); }

  a, button, label, summary, select,
  [role="button"], [role="tab"], [role="menuitem"], [tabindex] {
    -webkit-tap-highlight-color: var(--tap-highlight, transparent);
    touch-action: manipulation;
  }

  button, summary, [role="button"], [role="tab"] {
    -webkit-user-select: none;
    user-select: none;
  }

  /* Disabled controls read as disabled everywhere. */
  :disabled, [aria-disabled="true"] { cursor: not-allowed; }

  /* Keyboard focus is always visible; pointer focus never leaves a stuck ring. */
  :focus:not(:focus-visible) { outline: none; }
  :focus-visible {
    outline: 2px solid var(--theme-focus-ring, currentColor);
    outline-offset: 2px;
    border-radius: var(--radius-sm, 6px);
  }

  /* Respect users who ask for less motion. */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.001ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.001ms !important;
      scroll-behavior: auto !important;
    }
  }
}

/* ----------------------------------------------------------- components ---- */
/* The universal control layer (ADR 015 and its amendment). Every control the
   house uses, defined ONCE with its whole state matrix: default, hover,
   active, focus-visible, disabled, loading, selected, invalid. Promoted from
   sites/nascen-ai/css/components.css (707 lines, verified across 436
   controls) and generalised: every value now comes from a --ui-* custom
   property with a literal fallback, so a site skins the whole layer by
   redefining tokens and never by overriding a rule. docs/UI-LAYER.md is the
   adoption guide and the token reference.

   Class names carry the `ui-` prefix on purpose. Sites already ship their own
   `.btn`, `.card`, `.row` and `.input`, and this file reaches all of them the
   moment it is served: a prefix makes adoption opt in per control and makes a
   collision impossible. State classes only ever appear compounded with a
   `ui-` class (`.ui-btn.is-loading`), never bare.

   Behaviour (menus, tabs, accordions, dialogs) lives in /components.js and
   keys off `data-ui-*` attributes. The CSS here stands alone; the JS needs the
   CSS only for the hidden/visible popover rule.

   Rules that hold for every control below:
   - one focus ring, var(--ui-ring) at var(--ui-ring-off), never removed for
     the mouse. A field's focus is its own edge instead, because a ring 2px
     outside a 1px edge reads as two rings with a gap.
   - hover changes the ground, never the size.
   - :active is a 1px optical press (a transform), so nothing reflows.
   - disabled is var(--ui-disabled) opacity plus pointer-events: none.
   - every transition runs var(--ui-t-hover) on var(--ui-ease), and the
     reduced-motion block at the end of the layer zeroes all of them.
   - the coarse-pointer block gives every target var(--ui-touch).
   - nothing here is mandatory. Every selector stays at class specificity,
     nothing uses !important, and the whole layer sits in a cascade layer, so a
     site's own unlayered CSS beats any rule below on any control. Take the
     buttons and not the fields, or take everything and redefine the scale. */

@layer platform.components {
  /* --- The token slots a site redefines. Defaults read the theme layer above,
     so an unskinned site already looks like the house; a site that sets its own
     --ui-* values (unlayered, so they win) reskins every control at once. --- */
  :root {
    /* Grounds, low to high. --ui-hover is the hover ground, --ui-pressed the
       held one; a control never changes size to show either. */
    --ui-ground: var(--theme-bg, #ffffff);
    --ui-rail: var(--theme-bg-subtle, #f5f5f7);
    --ui-raised: var(--theme-bg-elevated, #ffffff);
    --ui-hover: var(--theme-bg-raised, #efeff4);
    --ui-pressed: var(--theme-bg-surface, #e8e8ed);

    /* Ink. --ui-ink-inverse is the label on a solid (ink ground) control. */
    --ui-ink: var(--theme-color, #1d1d1f);
    --ui-ink-muted: var(--theme-color-dim, #6e6e73);
    --ui-ink-faint: var(--theme-color-muted, #86868b);
    --ui-ink-inverse: var(--theme-bg, #ffffff);

    /* Hairlines. */
    --ui-line: var(--theme-border, #d2d2d7);
    --ui-line-strong: var(--theme-border-strong, #aeaeb2);

    /* The one accent, used sparingly: the accent control, the selected ring,
       the focused field edge. */
    --ui-accent: var(--theme-accent-emphasis, #0a84ff);
    --ui-accent-hover: var(--accent-600, #006fe6);
    --ui-accent-ink: #ffffff;

    /* One focus ring for the whole layer. */
    --ui-ring-w: 2px;
    --ui-ring-off: 2px;
    --ui-ring-color: var(--theme-focus-ring, currentColor);
    --ui-ring: var(--ui-ring-w) solid var(--ui-ring-color);

    /* The control scale: three heights, one field height, one row height,
       one coarse-pointer floor. */
    --ui-h-sm: 28px;
    --ui-h-md: 32px;
    --ui-h-lg: 40px;
    --ui-field-h: var(--ui-h-lg);
    --ui-row-h: 36px;
    --ui-touch: 44px;

    /* Shape. The defaults are the house ones (4px on a control, 8px on a
       card, 2px on a mark) because the token set assumes them; a site that
       wants 12px cards or fully round controls sets these three and the whole
       layer follows. */
    --ui-radius: var(--radius-xs, 4px);
    --ui-radius-card: var(--radius-chip, 8px);
    --ui-radius-mark: var(--radius-2xs, 2px);

    /* Rhythm inside a control. */
    --ui-gap: 8px;
    --ui-pad: 12px;
    --ui-pad-sm: 10px;
    --ui-pad-lg: 18px;
    --ui-pad-card: 16px;

    /* State constants. */
    --ui-press: 1px;
    --ui-disabled: .55;

    /* Type. The layer sets size, line height and weight only; the family is
       whatever the site set on body. */
    --ui-text: var(--text-sm, 14px);
    --ui-leading: 20px;
    --ui-text-sm: 13px;
    --ui-text-lg: 15px;
    --ui-text-label: var(--text-xs, 12px);
    --ui-leading-label: 16px;
    --ui-text-figure: var(--text-xl, 20px);
    --ui-leading-figure: 28px;
    --ui-weight: 500;

    /* Motion. --ui-t-hover is every state change, --ui-t-struct a structural
       move (a sheet arriving, a rail collapsing). */
    --ui-t-hover: var(--motion-duration-short-3, 150ms);
    --ui-t-struct: var(--motion-duration-short-4, 240ms);
    --ui-ease: var(--motion-easing-standard, cubic-bezier(.2, 0, 0, 1));

    /* Depth. A card's own shadow, a floating panel's, a modal sheet's. */
    --ui-shadow: 0 1px 2px var(--theme-shadow-sm, rgba(11, 20, 31, .08));
    --ui-shadow-float: 0 1px 2px var(--theme-shadow-sm, rgba(11, 20, 31, .08)),
      0 8px 24px var(--theme-shadow-md, rgba(11, 20, 31, .12));
    --ui-shadow-sheet: 0 8px 32px var(--theme-shadow-lg, rgba(11, 20, 31, .16));
    --ui-scrim: rgba(0, 0, 0, .4);

    /* Panel widths. */
    --ui-menu-w: 244px;
    --ui-sheet-w: 480px;

    /* Identity tints for the avatar square (four, plus the ink on each). */
    --ui-tint-1: #f3e2d6; --ui-tint-1-ink: #7a4526;
    --ui-tint-2: #e0e8dc; --ui-tint-2-ink: #3d5a36;
    --ui-tint-3: #dee6ee; --ui-tint-3-ink: #34506b;
    --ui-tint-4: #e7e0ee; --ui-tint-4-ink: #5a4472;

    /* Stacking inside the layer, on the platform ladder. */
    --ui-z-menu: var(--z-menu, 200);
    --ui-z-scrim: var(--z-overlay, 500);
    --ui-z-sheet: var(--z-modal, 1000);
  }

  /* The dark side of the tints and the scrim only; every other value above
     already follows the theme layer's light/dark swap. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --ui-tint-1: #3d2c22; --ui-tint-1-ink: #ecc9b3;
      --ui-tint-2: #2a352a; --ui-tint-2-ink: #c5d9bd;
      --ui-tint-3: #25303c; --ui-tint-3-ink: #bfd0e2;
      --ui-tint-4: #31283a; --ui-tint-4-ink: #d3c5e0;
      --ui-scrim: rgba(0, 0, 0, .55);
    }
  }
  :root[data-theme="dark"] {
    --ui-tint-1: #3d2c22; --ui-tint-1-ink: #ecc9b3;
    --ui-tint-2: #2a352a; --ui-tint-2-ink: #c5d9bd;
    --ui-tint-3: #25303c; --ui-tint-3-ink: #bfd0e2;
    --ui-tint-4: #31283a; --ui-tint-4-ink: #d3c5e0;
    --ui-scrim: rgba(0, 0, 0, .55);
  }

  /* --- Motion the controls share. Prefixed names, so a site's own `spin` or
     `reveal` keyframes are never shadowed. --- */
  @keyframes ui-reveal { from { opacity: 0; transform: translateY(4px); } }
  @keyframes ui-spin { to { transform: rotate(360deg); } }
  @keyframes ui-skel { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

  /* --- Visually hidden, still announced. --- */
  .ui-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* --- Button: solid, accent, line, text, on three heights --------------- */

  /* One solid button per surface, line for the alternative, text for the
     escape. The layer ships no red variant: a destructive action reads well as
     a text control that confirms inline, and a site that wants a danger button
     adds one in its own CSS. */
  .ui-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ui-gap, 8px);
    height: var(--ui-h-md, 32px);
    padding: 0 var(--ui-pad, 12px);
    border: 1px solid transparent;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
    font-weight: var(--ui-weight, 500);
    white-space: nowrap;
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-btn.sm { height: var(--ui-h-sm, 28px); padding: 0 var(--ui-pad-sm, 10px); font-size: var(--ui-text-sm, 13px); }
  .ui-btn.lg { height: var(--ui-h-lg, 40px); padding: 0 var(--ui-pad-lg, 18px); font-size: var(--ui-text-lg, 15px); }

  .ui-btn.solid { background: var(--ui-ink, #1d1d1f); color: var(--ui-ink-inverse, #ffffff); }
  .ui-btn.solid:hover, .ui-btn.solid.is-hover { background: var(--ui-ink-muted, #6e6e73); }
  .ui-btn.accent { background: var(--ui-accent, #0a84ff); color: var(--ui-accent-ink, #ffffff); }
  .ui-btn.accent:hover, .ui-btn.accent.is-hover { background: var(--ui-accent-hover, #006fe6); }
  .ui-btn.line { border-color: var(--ui-line-strong, #aeaeb2); color: var(--ui-ink, #1d1d1f); }
  .ui-btn.line:hover, .ui-btn.line.is-hover { background: var(--ui-hover); border-color: var(--ui-ink-muted, #6e6e73); }
  .ui-btn.text { color: var(--ui-ink-muted, #6e6e73); padding: 0 var(--ui-gap, 8px); }
  .ui-btn.text.sm { padding: 0 6px; }
  .ui-btn.text:hover, .ui-btn.text.is-hover { background: var(--ui-hover); color: var(--ui-ink, #1d1d1f); }

  .ui-btn:active:not(:disabled):not(.is-loading),
  .ui-btn.is-press { transform: translateY(var(--ui-press, 1px)); }
  .ui-btn:focus-visible, .ui-btn.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  /* Selected: a line or text button used as a toggle, and the same ground
     while a button holds its menu open. */
  .ui-btn[aria-pressed="true"]:not(.solid):not(.accent),
  .ui-btn[aria-haspopup][aria-expanded="true"]:not(.solid):not(.accent),
  .ui-btn.is-selected:not(.solid):not(.accent) {
    background: var(--ui-hover);
    border-color: var(--ui-line-strong, #aeaeb2);
    color: var(--ui-ink, #1d1d1f);
  }
  /* Loading: the label stays, the control stops taking input, one spinner. */
  .ui-btn.is-loading { pointer-events: none; cursor: progress; }
  .ui-btn.is-loading::before {
    content: "";
    width: 14px;
    height: 14px;
    flex: none;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    opacity: .7;
    animation: ui-spin 700ms linear infinite;
  }
  .ui-btn:disabled, .ui-btn.is-disabled, .ui-btn[aria-disabled="true"] {
    opacity: var(--ui-disabled, .55);
    pointer-events: none;
  }

  /* --- Icon button: the same three heights, square ----------------------- */

  .ui-iconbtn {
    --ui-ib: var(--ui-h-md, 32px);
    width: var(--ui-ib);
    height: var(--ui-ib);
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink-muted, #6e6e73);
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease),
      opacity var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-iconbtn.sm { --ui-ib: var(--ui-h-sm, 28px); }
  .ui-iconbtn.lg { --ui-ib: var(--ui-h-lg, 40px); }
  .ui-iconbtn:hover, .ui-iconbtn.is-hover { background: var(--ui-hover); color: var(--ui-ink, #1d1d1f); }
  /* The solid and accent icon buttons are the committing control (a composer's
     send square, a sheet's confirm): ink by default, the accent once armed. */
  .ui-iconbtn.solid { background: var(--ui-ink, #1d1d1f); color: var(--ui-ink-inverse, #ffffff); }
  .ui-iconbtn.solid:hover, .ui-iconbtn.solid.is-hover { background: var(--ui-ink-muted, #6e6e73); }
  .ui-iconbtn.accent, .ui-iconbtn.solid.is-armed {
    background: var(--ui-accent, #0a84ff);
    color: var(--ui-accent-ink, #ffffff);
  }
  .ui-iconbtn.accent:hover, .ui-iconbtn.accent.is-hover,
  .ui-iconbtn.solid.is-armed:hover { background: var(--ui-accent-hover, #006fe6); }
  .ui-iconbtn:active:not(:disabled), .ui-iconbtn.is-press { transform: translateY(var(--ui-press, 1px)); }
  .ui-iconbtn:focus-visible, .ui-iconbtn.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  /* A trigger holding its menu open keeps the hover ground. Only a menu
     trigger: aria-expanded also describes a rail, which is not pressed. */
  .ui-iconbtn[aria-haspopup][aria-expanded="true"]:not(.solid):not(.accent),
  .ui-iconbtn[aria-pressed="true"]:not(.solid):not(.accent),
  .ui-iconbtn.is-selected:not(.solid):not(.accent) { background: var(--ui-hover); color: var(--ui-ink, #1d1d1f); }
  .ui-iconbtn.is-loading { pointer-events: none; cursor: progress; }
  .ui-iconbtn:disabled, .ui-iconbtn.is-disabled, .ui-iconbtn[aria-disabled="true"] {
    opacity: var(--ui-disabled, .55);
    pointer-events: none;
  }
  /* Idle: a committing control with nothing to commit yet. Dimmer than
     disabled, because it is about to become live. */
  .ui-iconbtn.is-idle { opacity: .35; pointer-events: none; }

  /* --- Link ------------------------------------------------------------- */

  .ui-link {
    border: 0;
    padding: 0;
    background: transparent;
    font: inherit;
    color: var(--ui-ink, #1d1d1f);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    text-decoration-color: var(--ui-line-strong, #aeaeb2);
    cursor: pointer;
    border-radius: var(--ui-radius-mark, 2px);
    transition:
      text-decoration-color var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-link:hover, .ui-link.is-hover { text-decoration-color: currentColor; }
  .ui-link:active, .ui-link.is-press { color: var(--ui-ink-muted, #6e6e73); }
  .ui-link:focus-visible, .ui-link.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  /* The quiet link carries no rule until it is asked for. */
  .ui-link.quiet { color: var(--ui-ink-muted, #6e6e73); text-decoration: none; }
  .ui-link.quiet:hover {
    color: var(--ui-ink, #1d1d1f);
    text-decoration: underline;
    text-decoration-color: var(--ui-line-strong, #aeaeb2);
  }
  .ui-link.is-disabled, .ui-link[aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* --- Fields: input, textarea, select, unit, file, drop target ---------- */

  .ui-field { display: flex; flex-direction: column; gap: 6px; }
  .ui-label {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
  }

  .ui-input {
    height: var(--ui-field-h, 40px);
    width: 100%;
    padding: 0 var(--ui-pad, 12px);
    border: 1px solid var(--ui-line-strong, #aeaeb2);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-raised);
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    transition:
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      box-shadow var(--ui-t-hover, 150ms) var(--ui-ease),
      background var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-input.sm { height: var(--ui-h-md, 32px); padding: 0 var(--ui-pad-sm, 10px); }
  .ui-input::placeholder { color: var(--ui-ink-faint, #86868b); }
  .ui-input:hover:not(:disabled):not([readonly]), .ui-input.is-hover { border-color: var(--ui-ink-muted, #6e6e73); }
  /* A field's focus is its own edge, stepped up to the accent and doubled in
     weight. A 2px ring outside a 1px edge reads as two rings with a gap. It is
     never taken away for the mouse: a browser treats a text field as
     focus-visible however it was reached, and both paths land here. */
  .ui-input:focus, .ui-input:focus-visible, .ui-input.is-focus {
    border-color: var(--ui-accent, #0a84ff);
    box-shadow: 0 0 0 1px var(--ui-accent, #0a84ff);
    outline: none;
  }
  /* Invalid is the full ink on the edge with the reason in words underneath. */
  .ui-input.is-invalid, .ui-input[aria-invalid="true"] {
    border-color: var(--ui-ink, #1d1d1f);
    box-shadow: 0 0 0 1px var(--ui-ink, #1d1d1f);
  }
  .ui-input[readonly] { color: var(--ui-ink-muted, #6e6e73); background: var(--ui-rail); cursor: default; }
  .ui-input:disabled { color: var(--ui-ink-muted, #6e6e73); opacity: var(--ui-disabled, .55); pointer-events: none; }

  textarea.ui-input {
    height: auto;
    min-height: var(--ui-field-h, 40px);
    padding: var(--ui-pad-sm, 10px) var(--ui-pad, 12px);
    line-height: var(--ui-leading, 20px);
    resize: vertical;
  }
  textarea.ui-input.sm { min-height: var(--ui-h-md, 32px); padding: 6px var(--ui-pad-sm, 10px); }
  select.ui-input {
    appearance: none;
    -webkit-appearance: none;
    background-image: none;
    padding-right: 32px;
    cursor: pointer;
  }
  .ui-select { position: relative; display: block; }
  .ui-select > svg {
    position: absolute;
    right: var(--ui-pad, 12px);
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    color: var(--ui-ink-muted, #6e6e73);
  }
  .ui-select:has(select:disabled) > svg { opacity: var(--ui-disabled, .55); }

  /* A unit sits inside the field's right edge and never takes a click. */
  .ui-unit { position: relative; display: block; }
  .ui-unit .ui-input { padding-right: 40px; }
  .ui-unit > span {
    position: absolute;
    right: var(--ui-pad, 12px);
    top: 0;
    height: var(--ui-field-h, 40px);
    display: inline-flex;
    align-items: center;
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text-sm, 13px);
    pointer-events: none;
  }
  .ui-unit:has(.ui-input.sm) > span { height: var(--ui-h-md, 32px); }

  /* The file control: a named button with the chosen file beside it (the real
     input stays visually hidden), and the drop target for an upload sheet. */
  .ui-file { display: flex; align-items: center; gap: var(--ui-pad, 12px); min-width: 0; }
  .ui-file__name {
    font-size: var(--ui-text-sm, 13px);
    line-height: var(--ui-leading, 20px);
    color: var(--ui-ink-muted, #6e6e73);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ui-file:has(input:focus-visible) .ui-btn { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  .ui-file.is-disabled { opacity: var(--ui-disabled, .55); pointer-events: none; }

  .ui-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ui-pad-sm, 10px);
    min-height: 112px;
    padding: var(--ui-pad-card, 16px);
    border: 1px solid var(--ui-line-strong, #aeaeb2);
    border-radius: var(--ui-radius-card, 8px);
    background: var(--ui-rail);
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
    text-align: center;
    cursor: pointer;
    transition:
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      background var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-drop:hover, .ui-drop.is-hover, .ui-drop.is-over {
    border-color: var(--ui-ink, #1d1d1f);
    background: var(--ui-pressed);
  }
  .ui-drop:active { background: var(--ui-hover); }
  .ui-drop:focus-visible, .ui-drop:focus-within, .ui-drop.is-focus {
    border-color: var(--ui-accent, #0a84ff);
    box-shadow: 0 0 0 1px var(--ui-accent, #0a84ff);
    outline: none;
  }
  .ui-drop .ui-hint {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-faint, #86868b);
  }
  .ui-drop.is-invalid {
    border-color: var(--ui-ink, #1d1d1f);
    box-shadow: 0 0 0 1px var(--ui-ink, #1d1d1f);
  }
  .ui-drop.is-disabled { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* --- Segmented control and tab track ---------------------------------- */

  /* .ui-seg is the ink-selected track (a filter toolbar, a unit switch).
     .ui-tabs is the raised-segment track (a header's tab strip, a term
     switch), and it is what a [role="tablist"] wears. Both carry --ui-seg-h,
     so sizing the control sizes every segment. */
  .ui-seg {
    --ui-seg-h: var(--ui-field-h, 40px);
    display: inline-flex;
    height: var(--ui-seg-h);
    border: 1px solid var(--ui-line-strong, #aeaeb2);
    border-radius: var(--ui-radius, 4px);
    overflow: hidden;
  }
  .ui-seg.sm { --ui-seg-h: var(--ui-h-md, 32px); }
  .ui-seg > button, .ui-seg > a {
    height: 100%;
    padding: 0 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-left: 1px solid var(--ui-line-strong, #aeaeb2);
    background: transparent;
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text, 14px);
    font-weight: var(--ui-weight, 500);
    white-space: nowrap;
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-seg.sm > button, .ui-seg.sm > a { padding: 0 var(--ui-pad, 12px); font-size: var(--ui-text-sm, 13px); }
  .ui-seg > :first-child { border-left: 0; }
  .ui-seg > button:hover, .ui-seg > a:hover, .ui-seg > .is-hover {
    background: var(--ui-hover);
    color: var(--ui-ink, #1d1d1f);
  }
  .ui-seg > button:active, .ui-seg > a:active { background: var(--ui-pressed); }
  /* A segment's ring sits inside the track, so the track's own edge is not
     doubled by a ring drawn outside it. */
  .ui-seg > :focus-visible, .ui-seg > .is-focus {
    outline: var(--ui-ring);
    outline-offset: calc(0px - var(--ui-ring-off, 2px));
  }
  .ui-seg > .is-on,
  .ui-seg > [aria-pressed="true"],
  .ui-seg > [aria-checked="true"],
  .ui-seg > [aria-selected="true"] { background: var(--ui-ink, #1d1d1f); color: var(--ui-ink-inverse, #ffffff); }
  .ui-seg > .is-on:hover, .ui-seg > [aria-selected="true"]:hover { background: var(--ui-ink, #1d1d1f); }
  .ui-seg > button:disabled, .ui-seg > [aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  .ui-tabs {
    --ui-seg-h: var(--ui-h-md, 32px);
    display: inline-flex;
    align-items: center;
    height: var(--ui-seg-h);
    padding: 2px;
    gap: 2px;
    flex: none;
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-rail);
  }
  .ui-tabs.lg { --ui-seg-h: var(--ui-field-h, 40px); }
  .ui-tabs > a, .ui-tabs > button, .ui-tabs > span {
    height: calc(var(--ui-seg-h) - 6px);
    padding: 0 var(--ui-pad, 12px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text-sm, 13px);
    line-height: var(--ui-leading, 20px);
    font-weight: var(--ui-weight, 500);
    white-space: nowrap;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-tabs > a, .ui-tabs > button { cursor: pointer; }
  .ui-tabs.lg > a, .ui-tabs.lg > button, .ui-tabs.lg > span { padding: 0 var(--ui-pad-lg, 18px); font-size: var(--ui-text, 14px); }
  .ui-tabs > a:hover, .ui-tabs > button:hover, .ui-tabs > .is-hover {
    color: var(--ui-ink, #1d1d1f);
    background: var(--ui-hover);
  }
  .ui-tabs > a:active, .ui-tabs > button:active { background: var(--ui-pressed); }
  .ui-tabs > :focus-visible, .ui-tabs > .is-focus {
    outline: var(--ui-ring);
    outline-offset: calc(0px - var(--ui-ring-off, 2px));
  }
  .ui-tabs > .is-on,
  .ui-tabs > [aria-checked="true"],
  .ui-tabs > [aria-selected="true"] {
    background: var(--ui-raised);
    color: var(--ui-ink, #1d1d1f);
    border-color: var(--ui-line, #d2d2d7);
    box-shadow: var(--ui-shadow);
  }
  .ui-tabs > .is-on:hover, .ui-tabs > [aria-selected="true"]:hover { background: var(--ui-raised); }
  .ui-tabs > button:disabled, .ui-tabs > [aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* A tab panel. /components.js toggles `hidden` on the panels it controls;
     the panel takes the ring when a page moves focus into it on selection. */
  .ui-panel { padding-top: var(--ui-pad, 12px); }
  .ui-panel:focus-visible { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }

  /* --- Choice rows: one answer (radio) and many (checkbox) -------------- */

  /* The whole row is the target, so a coarse pointer never has to hit a 16px
     mark. One answer gets a round mark, many answers a squared one (.multi),
     the familiar distinction; both marks read their shape from a token. */
  .ui-choice {
    display: flex;
    align-items: center;
    gap: var(--ui-pad, 12px);
    min-height: var(--ui-touch, 44px);
    padding: 0 var(--ui-pad, 12px);
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius, 4px);
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-choice:hover, .ui-choice.is-hover { background: var(--ui-rail); }
  .ui-choice:active, .ui-choice.is-press { transform: translateY(var(--ui-press, 1px)); }
  .ui-choice:has(input:focus-visible), .ui-choice:focus-visible, .ui-choice.is-focus {
    outline: var(--ui-ring);
    outline-offset: var(--ui-ring-off, 2px);
  }
  .ui-choice input { position: absolute; opacity: 0; width: 0; height: 0; }
  .ui-choice .ui-dot {
    width: 16px;
    height: 16px;
    flex: none;
    border: 1.5px solid var(--ui-line-strong, #aeaeb2);
    border-radius: 50%;
    display: grid;
    place-items: center;
    transition: border-color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-choice.is-on, .ui-choice:has(input:checked) { border-color: var(--ui-ink, #1d1d1f); }
  .ui-choice.is-on .ui-dot, .ui-choice:has(input:checked) .ui-dot { border-color: var(--ui-ink, #1d1d1f); }
  .ui-choice.is-on .ui-dot::after, .ui-choice:has(input:checked) .ui-dot::after {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ui-ink, #1d1d1f);
  }
  .ui-choice.multi .ui-dot, .ui-choice.multi .ui-dot::after { border-radius: var(--ui-radius-mark, 2px); }
  .ui-choice.is-invalid, .ui-choice[aria-invalid="true"] {
    border-color: var(--ui-ink, #1d1d1f);
    box-shadow: 0 0 0 1px var(--ui-ink, #1d1d1f);
  }
  .ui-choice.is-disabled, .ui-choice:has(input:disabled) { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* --- Switch: a toggle shaped by the radius tokens -------------------- */

  /* Ours, not promoted: nascen had no switch. Track and knob both take
     their shape from the radius tokens (the track --ui-radius, the knob
     --ui-radius-mark), so it arrives squared like the rest of the layer and
     becomes the familiar rounded one by changing those two. State reads from the
     knob's position and the track's ground, not from a colour. */
  .ui-switch {
    --ui-sw-w: 40px;
    --ui-sw-h: 22px;
    position: relative;
    display: inline-flex;
    align-items: center;
    width: var(--ui-sw-w);
    height: var(--ui-sw-h);
    flex: none;
    padding: 2px;
    border: 1px solid var(--ui-line-strong, #aeaeb2);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-rail);
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      border-color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-switch::after {
    content: "";
    width: calc(var(--ui-sw-h) - 8px);
    height: calc(var(--ui-sw-h) - 8px);
    border-radius: var(--ui-radius-mark, 2px);
    background: var(--ui-ink-muted, #6e6e73);
    transform: translateX(0);
    transition:
      transform var(--ui-t-hover, 150ms) var(--ui-ease),
      background var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-switch:hover, .ui-switch.is-hover { background: var(--ui-hover); }
  .ui-switch:focus-visible, .ui-switch.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  .ui-switch[aria-checked="true"], .ui-switch.is-on {
    background: var(--ui-ink, #1d1d1f);
    border-color: var(--ui-ink, #1d1d1f);
  }
  .ui-switch[aria-checked="true"]::after, .ui-switch.is-on::after {
    background: var(--ui-ink-inverse, #ffffff);
    transform: translateX(calc(var(--ui-sw-w) - var(--ui-sw-h) - 2px));
  }
  .ui-switch:disabled, .ui-switch[aria-disabled="true"], .ui-switch.is-disabled {
    opacity: var(--ui-disabled, .55);
    pointer-events: none;
  }

  /* --- Chip (a filter that toggles) and badge (a label that does not) --- */

  .ui-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: var(--ui-h-md, 32px);
    padding: 0 14px;
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-ground);
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text, 14px);
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease),
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-chip.sm { height: var(--ui-h-sm, 28px); padding: 0 var(--ui-pad-sm, 10px); font-size: var(--ui-text-sm, 13px); }
  .ui-chip.lg { height: var(--ui-h-lg, 40px); padding: 0 var(--ui-pad-lg, 18px); }
  .ui-chip:hover, .ui-chip.is-hover { background: var(--ui-rail); color: var(--ui-ink, #1d1d1f); }
  .ui-chip:active, .ui-chip.is-press { transform: translateY(var(--ui-press, 1px)); }
  .ui-chip:focus-visible, .ui-chip.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  .ui-chip.is-on, .ui-chip[aria-pressed="true"], .ui-chip.is-selected {
    border-color: var(--ui-ink, #1d1d1f);
    color: var(--ui-ink, #1d1d1f);
    background: var(--ui-pressed);
  }
  .ui-chip:disabled, .ui-chip.is-disabled, .ui-chip[aria-disabled="true"] {
    opacity: var(--ui-disabled, .55);
    pointer-events: none;
  }

  /* A badge states a fact (a count, a status word). It is not a control, so it
     has no hover, no press and no focus. */
  .ui-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: var(--ui-h-sm, 28px);
    padding: 0 var(--ui-gap, 8px);
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-rail);
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    font-weight: var(--ui-weight, 500);
    white-space: nowrap;
  }
  .ui-badge.solid { background: var(--ui-ink, #1d1d1f); border-color: var(--ui-ink, #1d1d1f); color: var(--ui-ink-inverse, #ffffff); }
  .ui-badge.accent { background: var(--ui-accent, #0a84ff); border-color: var(--ui-accent, #0a84ff); color: var(--ui-accent-ink, #ffffff); }
  .ui-badge.quiet { background: transparent; }

  /* --- Rows: the rail row and the hairline list row --------------------- */

  /* A navigation row in a rail or a menu: one line, a hover ground, the ring
     drawn inside so it never overlaps the panel edge. */
  .ui-row {
    display: flex;
    align-items: center;
    gap: var(--ui-pad-sm, 10px);
    width: 100%;
    height: var(--ui-row-h, 36px);
    padding: 0 var(--ui-pad-sm, 10px);
    border: 0;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    transition: background var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-row:hover, .ui-row.is-active, .ui-row.is-hover { background: var(--ui-hover); }
  .ui-row:active { background: var(--ui-pressed); }
  .ui-row:focus-visible, .ui-row.is-focus {
    outline: var(--ui-ring);
    outline-offset: calc(0px - var(--ui-ring-off, 2px));
  }
  .ui-row > .ui-label-text { flex: 1; overflow: hidden; text-overflow: ellipsis; }
  .ui-row .ui-meta {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
  }
  .ui-row.quiet { color: var(--ui-ink-muted, #6e6e73); }
  .ui-row.is-selected { background: var(--ui-pressed); }
  .ui-row.is-disabled, .ui-row[aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* The hairline list row: a text stack, a trailing status word, a chevron
     when the row opens something, and actions revealed on hover or focus.
     A list keeps its own columns and heights in its own CSS. */
  .ui-list-row {
    display: flex;
    align-items: center;
    gap: var(--ui-pad, 12px);
    width: 100%;
    min-height: var(--ui-h-lg, 40px);
    padding: var(--ui-gap, 8px);
    border: 0;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
    text-align: left;
    outline-offset: calc(0px - var(--ui-ring-off, 2px));
    transition: background var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  a.ui-list-row, button.ui-list-row, .ui-list-row[tabindex] { cursor: pointer; }
  .ui-list-row:hover, .ui-list-row.is-hover, .ui-list-row.is-open, .ui-list-row:focus-within {
    background: var(--ui-pressed);
  }
  .ui-list-row:focus-visible, .ui-list-row.is-focus { outline: var(--ui-ring); }
  .ui-list-row.is-selected { background: var(--ui-hover); }
  .ui-list-row.is-disabled, .ui-list-row[aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }
  .ui-list-row + .ui-list-row { border-top: 1px solid var(--ui-line, #d2d2d7); }

  .ui-list-row .ui-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  .ui-list-row .ui-title {
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ui-list-row .ui-desc, .ui-list-row .ui-meta {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ui-list-row .ui-status {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
    flex: none;
  }
  .ui-list-row .ui-thumb {
    width: var(--ui-h-lg, 40px);
    height: var(--ui-h-lg, 40px);
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-ground);
    color: var(--ui-ink-muted, #6e6e73);
  }
  .ui-list-row .ui-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .ui-chev { color: var(--ui-ink-faint, #86868b); flex: none; display: inline-flex; }

  /* The revealed actions: small text controls in the row's own ink. They stay
     in the DOM (and reachable by tab, which reveals them through
     :focus-within), so a keyboard never loses an action a mouse can see. */
  .ui-ops { display: none; gap: 2px; flex: none; }
  .ui-list-row:hover .ui-ops,
  .ui-list-row.is-hover .ui-ops,
  .ui-list-row.is-open .ui-ops,
  .ui-list-row:focus-within .ui-ops { display: inline-flex; }
  .ui-ops > button {
    height: var(--ui-h-sm, 28px);
    padding: 0 var(--ui-gap, 8px);
    border: 0;
    border-radius: var(--ui-radius, 4px);
    background: transparent;
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text-sm, 13px);
    cursor: pointer;
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      color var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-ops > button:hover, .ui-ops > button.is-hover { background: var(--ui-hover); color: var(--ui-ink, #1d1d1f); }
  .ui-ops > button:active { transform: translateY(var(--ui-press, 1px)); }
  .ui-ops > button:focus-visible { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  .ui-ops > button:disabled { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* --- Card ------------------------------------------------------------- */

  /* The base card is a surface: a hairline, 8px, the page ground. Only a card
     that leads somewhere (a link, a button, one a page marks tappable) takes
     hover, press and focus. */
  .ui-card {
    --ui-card-ground: var(--ui-ground);
    display: flex;
    flex-direction: column;
    gap: var(--ui-pad, 12px);
    padding: var(--ui-pad-card, 16px);
    background: var(--ui-card-ground);
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius-card, 8px);
    color: var(--ui-ink, #1d1d1f);
    transition:
      background var(--ui-t-hover, 150ms) var(--ui-ease),
      border-color var(--ui-t-hover, 150ms) var(--ui-ease),
      box-shadow var(--ui-t-hover, 150ms) var(--ui-ease),
      transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  a.ui-card, button.ui-card, .ui-card[tabindex], .ui-card.is-tap { cursor: pointer; text-align: left; }
  a.ui-card:hover, button.ui-card:hover, .ui-card[tabindex]:hover, .ui-card.is-hover {
    --ui-card-ground: var(--ui-rail);
    border-color: var(--ui-line-strong, #aeaeb2);
    box-shadow: var(--ui-shadow);
  }
  a.ui-card:active, button.ui-card:active, .ui-card[tabindex]:active, .ui-card.is-press {
    transform: translateY(var(--ui-press, 1px));
  }
  .ui-card:focus-visible, .ui-card.is-focus { outline: var(--ui-ring); outline-offset: var(--ui-ring-off, 2px); }
  .ui-card.is-selected { border-color: var(--ui-accent, #0a84ff); }
  .ui-card.is-invalid { border-color: var(--ui-ink, #1d1d1f); }
  .ui-card.is-disabled, .ui-card[aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* What a card says: a title with a date at the right, a figure with its unit
     in the secondary ink. Anything below that (charts, lists) is the page's. */
  .ui-card .ui-card-top { display: flex; align-items: center; gap: 4px; }
  .ui-card .ui-card-title { font-size: var(--ui-text, 14px); line-height: var(--ui-leading, 20px); font-weight: var(--ui-weight, 500); }
  .ui-card .ui-card-when {
    margin-left: auto;
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
    font-variant-numeric: tabular-nums;
  }
  .ui-card .ui-card-value {
    font-size: var(--ui-text-figure, 20px);
    line-height: var(--ui-leading-figure, 28px);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .ui-card .ui-card-value .ui-unit-text {
    font-size: var(--ui-text-sm, 13px);
    font-weight: var(--ui-weight, 500);
    color: var(--ui-ink-muted, #6e6e73);
    margin-left: 3px;
  }
  .ui-card .ui-card-note {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
  }

  /* --- Dropdown menu (behaviour: /components.js, [data-ui-menu]) -------- */

  .ui-dropdown { position: relative; display: inline-flex; }
  /* The popover is the positioned wrapper the behaviour toggles; the menu is
     the panel. aria-hidden is the single source of truth for open state, so no
     class has to agree with it. */
  .ui-dropdown > [data-ui-popover] { position: absolute; top: calc(100% + 4px); left: 0; z-index: var(--ui-z-menu, 200); }
  .ui-dropdown > [data-ui-popover][data-align="end"] { left: auto; right: 0; }
  [data-ui-popover][aria-hidden="true"] { display: none; }
  .ui-menu {
    width: var(--ui-menu-w, 244px);
    max-width: calc(100vw - 2 * var(--ui-pad, 12px));
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: var(--ui-raised);
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius-card, 8px);
    box-shadow: var(--ui-shadow-float);
    animation: ui-reveal var(--ui-t-hover, 150ms) var(--ui-ease) both;
  }
  .ui-menu .ui-menu-head {
    padding: 6px var(--ui-pad-sm, 10px) var(--ui-gap, 8px);
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ui-menu .ui-menu-sep { height: 1px; background: var(--ui-line, #d2d2d7); margin: 4px; }
  /* A menu item is a rail row that also answers to the roving highlight the
     keyboard drives (aria-activedescendant + .is-active from /components.js),
     so mouse and keyboard show the same active item. */
  .ui-menu [role^="menuitem"] { position: relative; }
  .ui-menu [role^="menuitem"].is-active { background: var(--ui-hover); }
  .ui-menu [role^="menuitem"][aria-checked="true"]::after {
    content: "";
    width: 6px;
    height: 6px;
    flex: none;
    margin-left: auto;
    border-radius: var(--ui-radius-mark, 2px);
    background: var(--ui-ink, #1d1d1f);
  }
  .ui-menu [role^="menuitem"][aria-disabled="true"] { opacity: var(--ui-disabled, .55); pointer-events: none; }

  /* --- Accordion (behaviour: /components.js, [data-ui-accordion]) ------- */

  /* Native details and summary, so it works with the JS absent; the JS adds
     the exclusive-open rule and the disabled guard. */
  .ui-accordion { display: flex; flex-direction: column; }
  .ui-accordion > details { border-top: 1px solid var(--ui-line, #d2d2d7); }
  .ui-accordion > details:last-of-type { border-bottom: 1px solid var(--ui-line, #d2d2d7); }
  .ui-accordion > details > summary {
    display: flex;
    align-items: center;
    gap: var(--ui-pad, 12px);
    min-height: var(--ui-touch, 44px);
    padding: var(--ui-pad-sm, 10px) 0;
    color: var(--ui-ink, #1d1d1f);
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
    font-weight: var(--ui-weight, 500);
    cursor: pointer;
    list-style: none;
    transition: color var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-accordion > details > summary::-webkit-details-marker { display: none; }
  .ui-accordion > details > summary::after {
    content: "";
    width: 8px;
    height: 8px;
    flex: none;
    margin-left: auto;
    border-right: 1.5px solid var(--ui-ink-faint, #86868b);
    border-bottom: 1.5px solid var(--ui-ink-faint, #86868b);
    transform: rotate(45deg) translateY(-2px);
    transition: transform var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-accordion > details[open] > summary::after { transform: rotate(225deg) translateY(-2px); }
  .ui-accordion > details > summary:hover, .ui-accordion > details > summary.is-hover { color: var(--ui-ink, #1d1d1f); }
  .ui-accordion > details > summary:hover::after { border-color: var(--ui-ink, #1d1d1f); }
  .ui-accordion > details > summary:focus-visible, .ui-accordion > details > summary.is-focus {
    outline: var(--ui-ring);
    outline-offset: var(--ui-ring-off, 2px);
  }
  .ui-accordion > details > .ui-accordion-body {
    padding: 0 0 var(--ui-pad-card, 16px);
    color: var(--ui-ink-muted, #6e6e73);
    font-size: var(--ui-text, 14px);
    line-height: var(--ui-leading, 20px);
  }
  .ui-accordion > details[aria-disabled="true"] > summary,
  .ui-accordion > details > summary[aria-disabled="true"] { opacity: var(--ui-disabled, .55); cursor: not-allowed; }

  /* --- Dialog and sheet (behaviour: /components.js, [data-ui-dialog]) --- */

  /* A native <dialog>, opened with showModal() by the behaviour module, so the
     browser supplies the top layer, the inert background and the backdrop. The
     phone form is the bottom sheet with an M3 handle; the foot always names
     the escape, so no close square is needed at that width. */
  .ui-sheet {
    width: var(--ui-sheet-w, 480px);
    max-width: calc(100vw - 2 * var(--ui-pad-card, 16px));
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    padding: 20px 24px 24px;
    display: flex;
    flex-direction: column;
    gap: var(--ui-pad-card, 16px);
    margin: auto;
    background: var(--ui-raised);
    color: var(--ui-ink, #1d1d1f);
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius-card, 8px);
    box-shadow: var(--ui-shadow-sheet);
  }
  dialog.ui-sheet:not([open]) { display: none; }
  dialog.ui-sheet[open] { animation: ui-reveal var(--ui-t-struct, 240ms) var(--ui-ease) both; }
  dialog.ui-sheet::backdrop { background: var(--ui-scrim, rgba(0, 0, 0, .4)); }
  .ui-sheet:focus-visible { outline: none; }
  .ui-sheet .ui-sheet-handle { display: none; }
  .ui-sheet .ui-sheet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ui-pad, 12px);
    min-height: var(--ui-h-md, 32px);
    flex: none;
  }
  .ui-sheet .ui-sheet-head h2 { font-size: 16px; line-height: 24px; font-weight: var(--ui-weight, 500); margin: 0; }
  .ui-sheet .ui-sheet-foot { display: flex; gap: var(--ui-gap, 8px); justify-content: flex-end; padding-top: 4px; }

  /* The scrim for anything that is not a native dialog (a mobile rail). */
  .ui-scrim {
    position: fixed;
    inset: 0;
    z-index: var(--ui-z-scrim, 500);
    background: var(--ui-scrim, rgba(0, 0, 0, .4));
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--ui-t-hover, 150ms) var(--ui-ease);
  }
  .ui-scrim.is-on { opacity: 1; pointer-events: auto; }

  @media (max-width: 767px) {
    .ui-sheet {
      width: 100%;
      max-width: 100%;
      max-height: 88vh;
      margin: auto auto 0;
      gap: 14px;
      padding: var(--ui-gap, 8px) var(--ui-pad-card, 16px) calc(var(--ui-pad-card, 16px) + var(--safe-bottom, 0px));
      border-radius: var(--ui-radius-card, 8px) var(--ui-radius-card, 8px) 0 0;
      border-bottom: 0;
      box-shadow: none;
    }
    .ui-sheet .ui-sheet-head .ui-iconbtn { display: none; }
    .ui-sheet .ui-sheet-handle {
      display: block;
      width: 32px;
      height: 4px;
      flex: none;
      margin: 0 auto;
      border-radius: var(--ui-radius-mark, 2px);
      background: var(--ui-line-strong, #aeaeb2);
    }
    .ui-sheet .ui-sheet-foot .ui-btn { flex: 1; }
  }

  /* --- Forms ----------------------------------------------------------- */

  .ui-form { display: flex; flex-direction: column; gap: var(--ui-pad-card, 16px); }
  .ui-form-inline {
    margin: var(--ui-gap, 8px) 0 var(--ui-pad-card, 16px);
    padding: var(--ui-pad-card, 16px);
    display: flex;
    flex-direction: column;
    gap: 14px;
    border: 1px solid var(--ui-line, #d2d2d7);
    border-radius: var(--ui-radius-card, 8px);
  }
  .ui-form .ui-form-foot, .ui-form-inline .ui-form-foot {
    display: flex;
    gap: var(--ui-gap, 8px);
    justify-content: flex-end;
    align-items: center;
  }
  .ui-form .ui-form-foot { margin-top: var(--ui-gap, 8px); }
  .ui-form .ui-form-foot .ui-grow { flex: 1; }
  .ui-form.is-busy, .ui-form-inline.is-busy { pointer-events: none; opacity: var(--ui-disabled, .55); }

  /* --- Status and help text -------------------------------------------- */

  /* One helper line under a field, one status line under a form. An error is
     the same line in the full ink, never red: the words carry the failure. */
  .ui-help, .ui-status {
    font-size: var(--ui-text-label, 12px);
    line-height: var(--ui-leading-label, 16px);
    color: var(--ui-ink-muted, #6e6e73);
  }
  .ui-help.is-error, .ui-status.is-error,
  .ui-help[role="alert"], .ui-status[role="alert"] { color: var(--ui-ink, #1d1d1f); }
  .ui-help:empty, .ui-status:empty { display: none; }
  .ui-status.is-busy { display: inline-flex; align-items: center; gap: var(--ui-gap, 8px); }

  /* --- Skeleton and spinner -------------------------------------------- */

  /* Loading is a shape breathing on the quiet ground, never a gradient sweep;
     under reduced motion it stands still. */
  .ui-skeleton {
    background: var(--ui-pressed);
    border-radius: var(--ui-radius, 4px);
    animation: ui-skel 1.2s var(--ui-ease) infinite;
  }
  .ui-skeleton.line { height: 12px; }
  .ui-skeleton.line.short { width: 40%; }
  .ui-skeleton.block { height: 72px; border-radius: var(--ui-radius-card, 8px); }
  .ui-skeleton.square { width: 28px; height: 28px; flex: none; }
  .ui-spinner {
    width: 16px;
    height: 16px;
    flex: none;
    border: 2px solid var(--ui-line-strong, #aeaeb2);
    border-top-color: var(--ui-ink, #1d1d1f);
    border-radius: 50%;
    animation: ui-spin 700ms linear infinite;
  }
  .ui-spinner.lg { width: 24px; height: 24px; }

  /* --- Avatar: the identity square -------------------------------------- */

  .ui-avatar {
    width: 28px;
    height: 28px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: var(--ui-radius, 4px);
    background: var(--ui-tint-1);
    color: var(--ui-tint-1-ink);
    font-size: var(--ui-text-sm, 13px);
    font-weight: 600;
    user-select: none;
  }
  .ui-avatar.t2 { background: var(--ui-tint-2); color: var(--ui-tint-2-ink); }
  .ui-avatar.t3 { background: var(--ui-tint-3); color: var(--ui-tint-3-ink); }
  .ui-avatar.t4 { background: var(--ui-tint-4); color: var(--ui-tint-4-ink); }
  .ui-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }
  /* Selection is an accent ring with a 2px gap of whatever ground the square
     sits on: the focus ring's grammar in the accent. */
  .ui-avatar.is-selected { box-shadow: 0 0 0 2px var(--ui-accent, #0a84ff); }
  .ui-avatar.sm { width: 24px; height: 24px; font-size: var(--ui-text-label, 12px); }
  .ui-avatar.lg { width: 64px; height: 64px; font-size: 26px; }
  .ui-avatar.is-disabled { opacity: var(--ui-disabled, .55); }

  /* --- Touch: every target at least --ui-touch on a coarse pointer ----- */

  @media (pointer: coarse) {
    .ui-btn, .ui-chip { min-height: var(--ui-touch, 44px); }
    .ui-iconbtn { min-width: var(--ui-touch, 44px); min-height: var(--ui-touch, 44px); }
    .ui-ops > button { min-height: var(--ui-touch, 44px); padding: 0 var(--ui-pad, 12px); }
    .ui-row, .ui-list-row { min-height: var(--ui-touch, 44px); }
    .ui-row { height: auto; }
    .ui-input, .ui-input.sm { min-height: var(--ui-touch, 44px); }
    .ui-switch { --ui-sw-h: 26px; --ui-sw-w: 48px; }
    /* A segmented control's segments are adjacent, so the track is the target
       and every segment fills it. */
    .ui-seg, .ui-seg.sm, .ui-tabs, .ui-tabs.lg { --ui-seg-h: var(--ui-touch, 44px); }
    .ui-link { padding: 2px 0; }
  }

  /* --- Reduced motion -------------------------------------------------- */

  /* Every duration above is var(--ui-t-hover) or var(--ui-t-struct), and the
     platform.interaction layer collapses all of them (transition, animation
     and scroll) under prefers-reduced-motion for the whole page, so the layer
     needs no !important of its own. A site serving this layer without
     platform.css sets --ui-t-hover and --ui-t-struct to 0ms in its own
     reduced-motion block; a transitionend still fires either way. */
  @media (prefers-reduced-motion: reduce) {
    :root { --ui-t-hover: 0.001ms; --ui-t-struct: 0.001ms; }
  }
}
