/* ============================================================================
   SAH design tokens
   Source of truth: ../artifacts/branding/sah-brand-spec.md (repo-external; see
   team/reports/sah-brand-foundation.md for the implementable copy + the
   contrast table below, computed).

   Two neutrals + five accents, full stop (spec §1):
     --sah-ink #21103A · --sah-cream #FFF4DC
     --sah-pink #FF3D81 · --sah-green #5BD37A · --sah-yellow #FFC531 ·
     --sah-blue #4CC9F0 · --sah-violet #7C3AED

   Every --c-* / --font-* name below is UNCHANGED from the old "Sahra" file —
   another agent is building the host screen against these names right now.
   Only the *values* moved: each is now the --sah-* token (or a color-mix()/
   rgb()-alpha tint of one, never a new hex) that plays the same semantic
   role. Text-safe rule (spec §1): bright fills (pink/green/yellow/blue) take
   --sah-ink text; dark fills (violet, ink-as-background) take --sah-cream
   text. Game screens (phone + TV) are dark mode: ink ground, cream text,
   accents at ~20% (spec §1 dark-mode ratio).

   Semantic mapping (documented per the brief, since one var can only hold
   one color and pink/yellow both plausibly read as "primary"):
     amber slot     -> --sah-yellow   (primary · brand · score · crown · code)
     aqua slot       -> --sah-green    (success · submitted · selected · safe)
     rummen slot     -> --sah-pink     (urgency · error · critical · destructive)
     jac slot        -> --sah-violet   (decorative field only, never text;
                                          also the 18+ marker)
     jac-lt slot      -> violet lightened toward cream via color-mix(), so it
                          IS safe as text (the old --c-jac comment forbade
                          raw violet as text; this is that "text-safe violet").
   Pink is primary AND the error-adjacent "rummen" accent lived in the old
   file too, but nothing here reuses pink for both roles: primary took
   yellow instead, so pink is free to mean error/urgent everywhere, no
   icon-disambiguation hack needed.

   Contrast (WCAG 2.1, computed against the actual composited color; see
   team/reports/sah-brand-foundation.md for the full table):
     --c-text        cream/ink................. 16.02:1
     --c-text-2      cream-on-ink @ 80%......... 10.50:1
     --c-text-dim    cream-on-ink @ 65%......... 7.28:1   (phone only)
     --c-text-disabled cream-on-ink @ 55%....... 5.54:1   (phone only; WCAG
                                                    exempts disabled controls,
                                                    this clears AA anyway)
     --c-line-loud   cream-on-ink @ 45%......... 4.12:1 vs ink / 3.38:1 vs
                                                    --c-surface (control
                                                    borders need >=3:1, met)
     --c-line        cream-on-ink @ 10%......... 1.29:1  (DECORATIVE ONLY,
                                                    same "barely there"
                                                    intent as the old 1.7:1)
     --c-jac-lt      violet+cream @ 55/45%...... 6.67:1  (text-safe violet)
     ink text on pink/green/yellow/blue......... 5.20 / 9.20 / 11.07 / 9.10:1
     cream text on violet....................... 5.22:1
   All >= 4.5:1 except --c-line, which is explicitly decorative (a hairline
   separator, never carries text or meaning on its own — see its comment).

   FONTS are now self-hosted (assets/fonts/*.woff2 + OFL-*.txt), not linked
   from Google Fonts at runtime: the CSP is font-src 'self' (server/
   security.js) and the product runs offline on a LAN/.exe. --font-display
   is Lalezar (spec §2: display/headline font, one family covers Arabic +
   Latin). --font-ui / body is Readex Pro, same rule. Rubik (900) and
   Original Surfer are NOT general-purpose stacks — spec §3/§4 scope them to
   the literal "SAH" wordmark and "Silly Arab Humor" tagline only, so they
   are not exposed as --font-* variables at all; see .sah-wordmark* and
   .sah-tagline below. --font-mono drops the old JetBrains Mono (not part of
   the 4-font SAH system, and self-hosting a 5th family for room-code digits
   alone wasn't worth it) in favour of the system monospace stack; room
   codes keep .num for tabular figures.

   DELETED: the "Sahra"/carreaux tile motif on .tv::after. It was purely
   decorative Sahra identity (a jacaranda/cement-floor pattern) with no SAH
   equivalent in the brand spec — removed rather than re-skinned.
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }

/* ── FONTS — self-hosted, see header note. ─────────────────────────────── */
@font-face {
  font-family: 'Lalezar';
  src: url('/assets/fonts/lalezar-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lalezar';
  src: url('/assets/fonts/lalezar-400-arabic.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E;
}
@font-face {
  font-family: 'Readex Pro';
  src: url('/assets/fonts/readexpro-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Readex Pro';
  src: url('/assets/fonts/readexpro-400-arabic.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E;
}
@font-face {
  font-family: 'Readex Pro';
  src: url('/assets/fonts/readexpro-700-latin.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Readex Pro';
  src: url('/assets/fonts/readexpro-700-arabic.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200E;
}
/* Reserved for .sah-wordmark* only — the literal word "SAH" (spec §3). */
@font-face {
  font-family: 'Rubik';
  src: url('/assets/fonts/rubik-900-latin.woff2') format('woff2');
  font-weight: 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F;
}
/* Reserved for .sah-tagline only — the literal phrase "Silly Arab Humor" (spec §4). */
@font-face {
  font-family: 'Original Surfer';
  src: url('/assets/fonts/originalsurfer-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F;
}

:root {
  /* ── SAH BRAND TOKENS — spec §1. Never edit a value without recomputing
     every ratio in the header comment above. ─────────────────────────── */
  --sah-ink:    #21103A; /* Makdous Ink */
  --sah-cream:  #FFF4DC; /* Tahini Cream */
  --sah-pink:   #FF3D81; /* Lfet Pink */
  --sah-green:  #5BD37A; /* Khiyar Green */
  --sah-yellow: #FFC531; /* Limoun Yellow */
  --sah-blue:   #4CC9F0; /* Zjaj Blue */
  --sah-violet: #7C3AED; /* Batinjan Violet — also the 18+ marker */

  /* ── SURFACES — dark mode: ink ground, cream text, accents ~20%. ────── */
  --c-bg:          var(--sah-ink);  /* phone page base                            */
  --c-bg-tv:       var(--sah-ink);  /* TV page base — never pure black            */
  --c-surface:     color-mix(in srgb, var(--sah-ink) 92%, var(--sah-cream) 8%);  /* cards */
  --c-surface-2:   color-mix(in srgb, var(--sah-ink) 82%, var(--sah-cream) 18%); /* raised / hover / controller strip */
  --c-line:        color-mix(in srgb, var(--sah-ink) 90%, var(--sah-cream) 10%); /* DECORATIVE separators only (1.29:1) */
  --c-line-loud:   color-mix(in srgb, var(--sah-ink) 55%, var(--sah-cream) 45%); /* control border (4.12:1 / >=3:1 vs surface) */

  /* ── TEXT — see contrast table in the header comment. ────────────────── */
  --c-text:          var(--sah-cream); /* 16.02:1 on ink                          */
  --c-text-2:        color-mix(in srgb, var(--sah-cream) 80%, var(--sah-ink) 20%); /* 10.50:1 */
  --c-text-dim:      color-mix(in srgb, var(--sah-cream) 65%, var(--sah-ink) 35%); /*  7.28:1 — PHONE ONLY */
  --c-text-disabled: color-mix(in srgb, var(--sah-cream) 55%, var(--sah-ink) 45%); /*  5.54:1 — PHONE ONLY */
  --c-ink:           var(--sah-ink);   /* label on any bright-bucket fill         */

  /* ── ACCENTS — one var, one SAH accent, documented above. ────────────── */
  --c-amber:        var(--sah-yellow); /* brand · primary · score · crown · code  */
  --c-amber-bright: var(--sah-yellow); /* winner / podium 1st — same accent, lift
                                           it with glow/scale, not a new hue      */
  --c-aqua:         var(--sah-green);  /* success · submitted · selected · safe   */
  --c-rummen:       var(--sah-pink);   /* urgency · error · critical · destructive */
  --c-jac:          var(--sah-violet); /* DECORATIVE FIELD ONLY. Never text.      */
  --c-jac-lt:       color-mix(in srgb, var(--sah-violet) 55%, var(--sah-cream) 45%); /* the text-safe violet, 6.67:1 */

  /* Tints — surfaces behind accent text. Alpha over --c-surface.          */
  --c-amber-tint:  rgb(255 197  49 / 0.14);
  --c-aqua-tint:   rgb( 91 211 122 / 0.14);
  --c-rummen-tint: rgb(255  61 129 / 0.14);

  /* ── QR — deliberately unthemed. Never invert. Exempt from the 7-colour
     rule by design (spec has no opinion on QR modules).                   */
  --c-qr-module: #111111;
  --c-qr-paper:  #FFFFFF;

  /* ── FONT STACKS — see header note on Rubik / Original Surfer scoping.  */
  --font-display: 'Lalezar', system-ui, sans-serif;
  --font-ui:      'Readex Pro', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:    ui-monospace, 'Cascadia Mono', Consolas, monospace;

  /* ── PHONE SCALE — 30 cm. 1rem floor on inputs is not aesthetic. ────── */
  --p-2xs: 0.8125rem;  --p-xs: 0.875rem;  --p-sm: 1rem;
  --p-md:  1.0625rem;  --p-lg: 1.3125rem; --p-xl: 1.75rem;
  --p-2xl: 2.25rem;    --p-3xl: 3rem;

  /* ── TV SCALE — 3 m. max() floors it on 720p, keeps angular size at 4K. */
  --h-xs:   max(32px,  3vmin);
  --h-sm:   max(38px,  3.6vmin);
  --h-md:   max(46px,  4.4vmin);
  --h-lg:   max(58px,  5.6vmin);
  --h-xl:   max(78px,  7.6vmin);
  --h-2xl:  max(108px, 10.4vmin);
  --h-code: max(160px, 16vmin);

  /* ── SPACE ──────────────────────────────────────────────────────────── */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px;
  --sv-1: 1vmin; --sv-2: 2vmin; --sv-3: 3vmin; --sv-4: 4vmin; --sv-6: 6vmin;

  /* ── RADII — generous. Nothing here is a form. ──────────────────────── */
  --r-sm: 10px; --r-md: 18px; --r-lg: 28px; --r-xl: 40px; --r-pill: 999px;
  --rv-md: 2vmin; --rv-lg: 3vmin;

  /* ── ELEVATION ──────────────────────────────────────────────────────── */
  --shadow-card: 0 8px 24px rgb(0 0 0 / 0.42);
  --shadow-pop:  0 18px 52px rgb(0 0 0 / 0.55);
  --shadow-tv:   0 2vmin 6vmin rgb(0 0 0 / 0.55);
  --ring-focus:  0 0 0 3px var(--c-bg), 0 0 0 6px var(--c-amber);

  /* ── MOTION ─────────────────────────────────────────────────────────── */
  --ease-pop:    cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-linear: linear;

  --dur-micro: 100ms; --dur-fast: 180ms; --dur-swap: 220ms;
  --dur-enter: 400ms; --dur-flip: 500ms; --dur-slow: 800ms;
  --dur-beat: 1500ms; --dur-cele: 1400ms;

  --stagger-tv: 80ms; --stagger-phone: 50ms;

  /* ── Z ──────────────────────────────────────────────────────────────── */
  --z-base: 0; --z-raised: 10; --z-strip: 60; --z-sheet: 70;
  --z-banner: 80; --z-toast: 90; --z-modal: 100;
}

/* ── ROOT SCOPES ──────────────────────────────────────────────────────── */

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 400;
  background: var(--c-bg);
  color: var(--c-text);
  line-height: 1.5;
  letter-spacing: 0;               /* §3.6 rule 3 — never letter-space       */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* PHONE root */
.phone {
  min-block-size: 100dvh;          /* NOT 100vh — iOS chrome eats the button */
  overscroll-behavior-y: contain;  /* pull-to-refresh must not nuke an answer */
  padding-inline: var(--s-4);
  padding-block-start: var(--s-4);
  padding-block-end: calc(var(--s-6) + env(safe-area-inset-bottom, 0px));
  font-size: var(--p-md);
}
.phone--has-strip { padding-block-end: calc(104px + env(safe-area-inset-bottom, 0px)); }

/* DISPLAY root */
.tv {
  inline-size: 100vw;
  block-size: 100dvh;
  overflow: hidden;                /* it never scrolls. If it doesn't fit,
                                      the content is wrong, not the box.     */
  padding: var(--sv-4);            /* TV overscan still exists                */
  background: var(--c-bg-tv);
  font-size: var(--h-md);
  position: relative;
  isolation: isolate;
}

/* The SAH field: ink ground + two soft accent glows at dark-mode's ~20%
   accent budget. Static. One layer. Composited. TV only. The old carreaux
   tile motif was Sahra-specific decoration with no SAH equivalent and has
   been removed rather than reskinned (see header comment).                */
.tv::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(120vmin 80vmin at 78% -10%, rgb(124 58 237 / 0.20), transparent 62%),
    radial-gradient( 90vmin 70vmin at  8% 108%, rgb(91 211 122 / 0.10), transparent 60%),
    var(--c-bg-tv);
}

/* ── TYPE HELPERS ─────────────────────────────────────────────────────── */

.display  { font-family: var(--font-display); font-weight: 400; line-height: 1.18; }
.display--heavy { font-weight: 400; } /* Lalezar ships one weight (400) — see spec §2 */
.num      { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

/* The "SAH" wordmark lockup — Rubik 900, scoped to the literal word "SAH"
   only (spec §3). Never used as a system font. Shadow is two flat,
   hard-edged offset copies, pink layered in front of blue. */
.sah-wordmark-hero {
  font-family: 'Rubik', sans-serif;
  font-weight: 900;
  font-size: 60px;
  color: var(--sah-ink);
  text-shadow: 2px 1.5px 0 var(--sah-pink), 4px 3px 0 var(--sah-blue);
}
.sah-wordmark-small {
  font-family: 'Rubik', sans-serif;
  font-weight: 900;
  font-size: 32px;
  color: var(--sah-ink); /* on a light/white ground */
  text-shadow: 1px 0.75px 0 var(--sah-pink), 2px 1.5px 0 var(--sah-blue);
}
.sah-wordmark-small--on-ink {
  color: var(--sah-cream); /* same lockup, flipped base colour, ink ground */
}
.sah-wordmark-display {
  font-family: 'Rubik', sans-serif;
  font-weight: 900;
  font-size: 180px;
  color: var(--sah-ink);
  text-shadow: 5px 4px 0 var(--sah-pink), 11px 8px 0 var(--sah-blue);
}

/* The "Silly Arab Humor" tagline — Original Surfer, scoped to this exact
   phrase only (spec §4). Flat, no shadow — explicitly rejected in review. */
.sah-tagline {
  font-family: 'Original Surfer', cursive;
  font-weight: 700; /* single-weight font; this triggers intentional synthetic bold */
  font-size: 34px;
  color: var(--sah-pink);
}

/* User-generated text. Every answer, every name, every lie. */
.user-content {
  unicode-bidi: plaintext;         /* one Latin word must not flip an Arabic
                                      sentence's punctuation                  */
  text-align: start;
  overflow-wrap: anywhere;         /* unbroken Arabizi WILL happen            */
  letter-spacing: 0;
}

/* Arabic renders optically smaller and needs more leading. §3.6 rules 1 & 2.
   The platform is English-first (LTR page chrome); this still applies to
   any inline Arabic content (the صح mark, Arabizi in prompts) wherever it
   appears without flipping the surrounding layout. */
[dir="rtl"] { line-height: 1.75; font-size: 1.08em; }

/* Things that do not mirror: time, and Latin tokens. */
.ltr-lock { direction: ltr; unicode-bidi: isolate; }

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

:where(button, a, input, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--ring-focus);
}

/* ── KEYFRAMES ────────────────────────────────────────────────────────── */

@keyframes pop-in {
  from { opacity: 0; transform: scale(0.84); }
  60%  { opacity: 1; transform: scale(1.06); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes fade-in       { from { opacity: 0 } to { opacity: 1 } }
@keyframes flip-reveal   { from { transform: rotateY(90deg) } to { transform: rotateY(0) } }
@keyframes shake {
  0%, 100% { transform: translateX(0) }
  20% { transform: translateX(-8px) } 40% { transform: translateX(8px) }
  60% { transform: translateX(-8px) } 80% { transform: translateX(8px) }
}
@keyframes idle-float {
  from { transform: translateY(-4px) } to { transform: translateY(4px) }
}
@keyframes pulse-attention {
  0%, 100% { transform: scale(1) } 50% { transform: scale(1.04) }
}
@keyframes dot-fill {
  0% { transform: scale(1) } 55% { transform: scale(1.34) } 100% { transform: scale(1.15) }
}
@keyframes drain-bar     { from { transform: scaleX(1) } to { transform: scaleX(0) } }
@keyframes sheet-up      { from { transform: translateY(100%) } to { transform: translateY(0) } }
@keyframes banner-drop   { from { transform: translateY(-100%) } to { transform: translateY(0) } }
@keyframes stamp {
  0%   { opacity: 0; transform: scale(3) }
  70%  { opacity: 1; transform: scale(0.92) }
  100% { opacity: 1; transform: scale(1) }
}
@keyframes wipe {
  0%   { transform: translateX(-110%) skewX(-8deg) }
  100% { transform: translateX(110%)  skewX(-8deg) }
}
@keyframes ring-spin { to { transform: rotate(360deg) } }

/* ── REDUCED MOTION — three tiers. See §4.5. ──────────────────────────── */

@media (prefers-reduced-motion: reduce) {

  /* Reset everything... */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* ── TIER 1 — INFORMATION. The animation IS the data. Restore it.
        Without this block a reduced-motion user is the only person in the
        room who cannot see how much time is left.                        */
  .timer-ring__fill,
  .timer-bar__fill,
  .btn__countdown,
  .dot--filling {
    animation-duration: var(--anim-dur, 1s) !important;
    animation-iteration-count: 1 !important;
    transition-duration: var(--anim-dur, 1s) !important;
  }
  /* NOTE: in this build the timer ring and the timer bar are driven from JS
     (shared/timer.js writes stroke-dashoffset / transform every frame from
     deadlineAt - serverNow). That is deliberately immune to any CSS
     animation reset — a frozen timer is a correctness bug, not a taste
     question — and the block above keeps the declarative path correct too.  */

  /* count-up is JS-driven; it checks the media query itself and KEEPS
     tweening. A score that snaps is a payoff that never happened.          */

  /* ── TIER 2 — TRANSITION. Collapse to a plain 120 ms opacity fade.
        The state change must still be perceptible.                        */
  .card, .answer-card, .ballot-option, .score-row, .avatar,
  .banner, .toast, .sheet, .ctrl-strip__label, .qr-panel {
    animation: fade-in 120ms var(--ease-smooth) both !important;
    transform: none !important;
  }

  /* ── TIER 3 — DECORATIVE. Gone. Large-field motion at wall size makes
        people genuinely nauseous and they will not say so.                */
  .avatar--float,
  .pulse,
  .confetti,
  .parallax { animation: none !important; }

  /* pulse-attention's job (timer critical) is carried statically instead:  */
  .timer-ring.is-critical { filter: none; }
}
