/* ============================================================================
   SwifLock — Design Tokens (single source of truth)
   ----------------------------------------------------------------------------
   Direction (set by Alex, 2026-07-22): the references are Apple / Google /
   Anthropic / Wispr Flow — LIGHT-FIRST, warm quiet neutrals, near-black text,
   ONE restrained deep-blue accent, soft real shadows. Explicitly NOT the
   dark+neon "vibe-coded" look: no cyan, no glows, no blue-black surfaces.

   Light is the default :root. Dark exists as a deliberate nighttime variant —
   warm graphite, desaturated accent — via prefers-color-scheme AND the manual
   [data-theme] hooks (data-theme always wins over the media query).

   After this file lands, NO screen hardcodes a design value that belongs here.
   ========================================================================== */

:root {
  color-scheme: light;

  /* ---- COLOR: surfaces (light — warm paper, white cards) ---- */
  --color-bg-0:          #F7F5F2; /* page ground: warm paper, not gray, not cream */
  --color-bg-1:          #FFFFFF; /* card / raised surface */
  --color-bg-2:          #EFECE7; /* hover / popover / subtle wells */
  --color-bg-3:          #FFFFFF; /* modal / bottom sheet */
  --color-border:        #E4E1DB; /* hairline divider */
  --color-border-strong: #8F897E; /* input / non-text outline, 3:1+ on bg-0 */

  /* ---- COLOR: text (warm graphite, never pure black) ---- */
  --color-text-primary:   #1F1D1A; /* ~15.9:1 on bg-0 (AAA) */
  --color-text-secondary: #57534B; /* ~7.1:1 on bg-0 (AAA) */
  /* [ST6] RAISED FROM #7A756B, the debt the ST5 fix report left open and two
     verifiers flagged (the Door history caption times on bg-0; the 1280 wall
     clock). Measured, not estimated — 12px meta text needs 4.5:1:
       was  4.21 on bg-0 (FAIL), 4.58 on bg-1, 3.89 on bg-2 (FAIL),
            4.58 on bg-3;
       now  5.01 on bg-0, 5.45 on bg-1, 4.63 on bg-2, 5.45 on bg-3.
     Every light surface passes AA now, not just the one the brief named: the
     bg-2 shortfall was the same debt one surface over, and fixing bg-0 alone
     would have left it sitting there behind a passing report.
     The three-step ink hierarchy survives the raise — primary 15.9, secondary
     7.03, tertiary 5.01 on bg-0 — so this is still visibly the quietest ink on
     the page and not a second secondary. Restated verbatim in the
     [data-theme="light"] block below for the same reason the dark fix was: a
     landlord who CHOSE Light lands on that branch, and a fix applied only here
     would pass an emulated audit and ship the failure to the person who picked
     the theme. The DARK token is deliberately untouched (see below). */
  --color-text-tertiary:  #6E6960;

  /* ---- COLOR: accent + semantic (one deep slate blue; calm semantics) ---- */
  --color-accent:      #2D5F8A; /* deep slate blue — 6.1:1 on bg-0 as text */
  --color-accent-fg:   #FFFFFF; /* white ink on filled accent, 6.4:1 */
  --color-success:     #1E7A4E; /* calm green, 5.0:1 on bg-0 */
  --color-success-fg:  #FFFFFF;
  --color-warning:     #92600A; /* 5.4:1 on bg-0 */
  --color-danger:      #B3382E; /* 5.4:1 on bg-0 */
  --color-danger-fg:   #FFFFFF;

  /* Flat status tints (pills/badges/soft rings) — a flat mix, never a blur,
     never an outer glow. */
  --tint-accent:  color-mix(in srgb, var(--color-accent)  10%, transparent);
  --tint-success: color-mix(in srgb, var(--color-success) 12%, transparent);
  --tint-warning: color-mix(in srgb, var(--color-warning) 12%, transparent);
  --tint-danger:  color-mix(in srgb, var(--color-danger)  10%, transparent);
  --tint-neutral: color-mix(in srgb, var(--color-text-tertiary) 12%, transparent);

  /* "Unlocked" emphasis. Kept as a variable for compatibility, but it is now a
     SOFT FLAT TINT for ring treatments (0 0 0 Npx), NOT a luminous glow.
     Pages must not use it as a blurred outer glow. */
  --glow-success: color-mix(in srgb, var(--color-success) 16%, transparent);

  /* ---- SPACING (4px base grid) ---- */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* ---- RADIUS ---- */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius-md:   12px;
  --radius-lg:   16px;
  --radius-xl:   28px;
  --radius-full: 999px;

  /* ---- TYPE SCALE ---- */
  --font-family: -apple-system, "SF Pro Text", "Segoe UI", Roboto, system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Roboto Mono", monospace;
  --text-display: 700 34px/1.15 var(--font-family);
  --text-title:   700 22px/1.25 var(--font-family);
  --text-heading: 600 17px/1.3  var(--font-family);
  --text-body:    400 15px/1.45 var(--font-family);
  --text-label:   500 13px/1.3  var(--font-family);
  --text-caption: 400 12px/1.3  var(--font-family);

  /* ---- MOTION: durations ---- */
  --dur-instant: 100ms;
  --dur-fast:    150ms;
  --dur-base:    250ms;
  --dur-medium:  350ms;
  --dur-slow:    450ms;
  --dur-door:    600ms;

  /* ---- MOTION: easing ---- */
  --ease-standard:         cubic-bezier(0.2, 0, 0, 1);
  --ease-standard-decel:   cubic-bezier(0, 0, 0, 1);
  --ease-standard-accel:   cubic-bezier(0.3, 0, 1, 1);
  --ease-emphasized-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
  --ease-emphasized-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
  --ease-spring-press:     cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ---- ELEVATION (soft, warm, physical — shadows, never glows) ---- */
  --elevation-0: none;
  --elevation-1: 0 1px 2px rgba(31, 29, 26, 0.06);
  --elevation-2: 0 4px 12px rgba(31, 29, 26, 0.08);
  --elevation-3: 0 16px 40px rgba(31, 29, 26, 0.14);

  /* ---- BRAND LOCKUP: WHICH ARTWORK, PER THEME ----------------------------
     Alex's SwifLock lockup exists as TWO pieces of artwork, and picking the
     wrong one does not look slightly off — it makes the logo disappear. The
     navy original measures 15.2:1 on this light ground and 1.10:1 on the dark
     one; the light variant measures 11.0:1 on dark and 1.48:1 on white. Each
     is invisible on the other's ground.

     SO THE CHOICE LIVES HERE, beside --color-bg-0, IN THE SAME THREE RULE
     BLOCKS. That is the whole point: there is exactly one notion of "what
     theme is this", the `[data-theme]` attribute over a `prefers-color-scheme`
     fallback, and the logo reads it through the same cascade the page
     background does. A `<picture media=...>` would have keyed off the OS only
     and shown the navy artwork on a dark ground to every landlord who picked
     Dark in Account — invisible, on the sign-in page.

     Filenames say WHICH GROUND THE ARTWORK SITS ON, not what colour it is, so
     an inverted wiring is legible in the diff rather than only on screen.

     The two variants are normalised onto ONE canvas aspect ratio (1166x241)
     with the wordmark scaled to a common text height, so the swap never
     reflows and the type reads the same size in both themes. Artwork itself is
     untouched — cropped, scaled and centred, never recoloured. */
  --brand-lockup-ar: 1166 / 241;
  --brand-lockup: image-set(
    url("/brand/swiflock-lockup-on-light-240.png") 1x,
    url("/brand/swiflock-lockup-on-light-480.png") 2x);
  --brand-lockup-sm: image-set(
    url("/brand/swiflock-lockup-on-light-168.png") 1x,
    url("/brand/swiflock-lockup-on-light-336.png") 2x);
}

/* ---- DARK: the deliberate nighttime variant. Warm graphite (never blue-
   black), desaturated accent (never cyan), same soft-shadow physics. ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --color-bg-0:          #151412;
    --color-bg-1:          #1D1C19;
    --color-bg-2:          #242320;
    --color-bg-3:          #2A2926;
    --color-border:        #34322E;
    --color-border-strong: #6E6A61;

    --color-text-primary:   #F1EFEA;
    --color-text-secondary: #ABA79E;
    /* [ST5-FIX] RAISED FROM #817D74, WHICH FAILED AA ON EVERY DARK SURFACE.
       [ST6-FIX] RAISED AGAIN, FROM #8E8A81, BECAUSE THE REASON THE LAST
       SHORTFALL WAS ACCEPTED WAS NOT TRUE.
       Measured, not estimated (12px caption ink needs 4.5:1):
         #817D74  4.49 bg-0 · 4.15 bg-1 · 3.83 bg-2 · 3.55 bg-3  (ST5-FIX found)
         #8E8A81  5.35 bg-0 · 4.95 bg-1 · 4.57 bg-2 · 4.23 bg-3  (ST5-FIX left)
         #938F86  5.71 bg-0 · 5.29 bg-1 · 4.87 bg-2 · 4.51 bg-3  (now — all AA)
       WHAT WAS FALSE. Both ST5-FIX and [ST6] wrote that bg-3 could stay under
       the bar because "the sheet/drawer grounds carry label and value ink,
       never tertiary". The ST6 design verifier rendered the app in dark at
       375px and found tertiary ink on bg-3 in nine places: the guest drawer's
       `.action-group__label` (GUEST LINK / CONTACT / THIS GUEST / KEYS), its
       `.contact-row__k` (EMAIL / PHONE), both "Not given" values
       (`.contact-row__v--none`), the share-sheet caption (`.handoff__cap`) and
       the add-unit sheet's `.field__help` ("Whatever you call it yourself.").
       The sweep that produced the claim had only walked the Units tab. A
       comment is not a measurement, which is why test/st6-contrast.test.js now
       computes all four dark surfaces off this file and requires all four to
       clear AA — there is no "recorded shortfall" left to record.
       WHY #938F86 AND NOT MORE. It is the smallest step that clears bg-3, the
       darkest-grounded surface, and it keeps the three inks visibly three:
       primary 12.66, secondary 6.06, tertiary 4.51 on that same ground.
       Light's two shortfalls (4.21 on bg-0, 3.89 on bg-2) were closed by [ST6]
       at #6E6960 and are untouched here. */
    --color-text-tertiary:  #938F86;

    --color-accent:      #8FB4D6; /* desaturated slate — reads calm, not neon */
    --color-accent-fg:   #10202E;
    --color-success:     #58B287;
    --color-success-fg:  #0C1F16;
    --color-warning:     #D2A45A;
    --color-danger:      #E06C62;
    --color-danger-fg:   #240807;

    --glow-success: color-mix(in srgb, var(--color-success) 18%, transparent);

    --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.35);
    --elevation-2: 0 4px 12px rgba(0, 0, 0, 0.4);
    --elevation-3: 0 16px 40px rgba(0, 0, 0, 0.5);

    /* The LIGHT artwork, because this block is the DARK ground. */
    --brand-lockup: image-set(
      url("/brand/swiflock-lockup-on-dark-240.png") 1x,
      url("/brand/swiflock-lockup-on-dark-480.png") 2x);
    --brand-lockup-sm: image-set(
      url("/brand/swiflock-lockup-on-dark-168.png") 1x,
      url("/brand/swiflock-lockup-on-dark-336.png") 2x);
  }
}

/* ---- Manual theme override hooks. data-theme wins over the media query. ---- */
:root[data-theme="dark"],
[data-theme="dark"] {
  color-scheme: dark;

  --color-bg-0:          #151412;
  --color-bg-1:          #1D1C19;
  --color-bg-2:          #242320;
  --color-bg-3:          #2A2926;
  --color-border:        #34322E;
  --color-border-strong: #6E6A61;

  --color-text-primary:   #F1EFEA;
  --color-text-secondary: #ABA79E;
  /* [ST5-FIX] RESTATED, NOT INHERITED — see the media-query block above for the
     measurements. This is the branch a landlord who chose Dark in Account lands
     on whatever the OS says, so a fix applied only up there would pass the
     emulated audit and ship the failure to the person who picked the theme.
     [ST6-FIX] Moved with it: #8E8A81 → #938F86, 4.23 → 4.51 on bg-3. */
  --color-text-tertiary:  #938F86;

  --color-accent:      #8FB4D6;
  --color-accent-fg:   #10202E;
  --color-success:     #58B287;
  --color-success-fg:  #0C1F16;
  --color-warning:     #D2A45A;
  --color-danger:      #E06C62;
  --color-danger-fg:   #240807;

  --glow-success: color-mix(in srgb, var(--color-success) 18%, transparent);

  --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.35);
  --elevation-2: 0 4px 12px rgba(0, 0, 0, 0.4);
  --elevation-3: 0 16px 40px rgba(0, 0, 0, 0.5);

  /* The LIGHT artwork, because this block is the DARK ground. This is the
     branch a landlord who chose Dark in Account lands on whatever the OS
     says, and it is the one a media-query-only switch would have missed. */
  --brand-lockup: image-set(
    url("/brand/swiflock-lockup-on-dark-240.png") 1x,
    url("/brand/swiflock-lockup-on-dark-480.png") 2x);
  --brand-lockup-sm: image-set(
    url("/brand/swiflock-lockup-on-dark-168.png") 1x,
    url("/brand/swiflock-lockup-on-dark-336.png") 2x);
}

:root[data-theme="light"],
[data-theme="light"] {
  color-scheme: light;

  --color-bg-0:          #F7F5F2;
  --color-bg-1:          #FFFFFF;
  --color-bg-2:          #EFECE7;
  --color-bg-3:          #FFFFFF;
  --color-border:        #E4E1DB;
  --color-border-strong: #8F897E;

  --color-text-primary:   #1F1D1A;
  --color-text-secondary: #57534B;
  /* [ST6] RESTATED, NOT INHERITED — see the :root block at the top of this file
     for the measurements. This is the branch a landlord who chose Light in
     Account lands on whatever the OS says. */
  --color-text-tertiary:  #6E6960;

  --color-accent:      #2D5F8A;
  --color-accent-fg:   #FFFFFF;
  --color-success:     #1E7A4E;
  --color-success-fg:  #FFFFFF;
  --color-warning:     #92600A;
  --color-danger:      #B3382E;
  --color-danger-fg:   #FFFFFF;

  --glow-success: color-mix(in srgb, var(--color-success) 16%, transparent);

  --elevation-1: 0 1px 2px rgba(31, 29, 26, 0.06);
  --elevation-2: 0 4px 12px rgba(31, 29, 26, 0.08);
  --elevation-3: 0 16px 40px rgba(31, 29, 26, 0.14);

  /* RESTATED, NOT INHERITED, for the same reason every colour above is. This
     selector also matches a nested element (styleguide.html paints a light
     PANEL inside whatever the root is). Under a dark OS the root gets the
     dark block, so a panel that overrode only the colours would keep the
     dark-ground artwork and render the light wordmark on white — 1.48:1,
     which is the invisible case. */
  --brand-lockup: image-set(
    url("/brand/swiflock-lockup-on-light-240.png") 1x,
    url("/brand/swiflock-lockup-on-light-480.png") 2x);
  --brand-lockup-sm: image-set(
    url("/brand/swiflock-lockup-on-light-168.png") 1x,
    url("/brand/swiflock-lockup-on-light-336.png") 2x);
}

/* ---- REDUCED MOTION: collapse durations; kill overshoot. ---- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 1ms;
    --dur-fast:    1ms;
    --dur-base:    120ms;
    --dur-medium:  120ms;
    --dur-slow:    150ms;
    --dur-door:    200ms;

    --ease-spring-press:     ease;
    --ease-emphasized-decel: ease;
    --ease-emphasized-accel: ease;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
