/* ============================================================================
   ForiForeign design tokens · P0 (Clear Sky, approved 2026-09-06)
   Source of truth: public/src/tokens.css. The build inlines this at the top of
   the shell stylesheet. Three blocks:
     1. CANONICAL  Clear Sky values. Nothing in the app reads these until P1.
     2. LANG       per-script type stacks. Inert until <html lang> is set (P1).
     3. COMPAT     every legacy variable name at the exact value the app
                   computes today. This is what keeps P0 pixel-identical.
   Deliberately absent in P0: color-scheme (the app never sets it; adding it
   changes native control rendering), and --page / --dot (referenced but never
   defined; defining them would change rendering).
   ============================================================================ */

/* ---------- 0. FONTS · self-hosted Latin faces (P1.2). Non-Latin scripts load from Google Fonts by unicode-range. ---------- */
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:500 700;font-display:swap;src:url('/fonts/instrument-sans-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:400 600;font-display:swap;src:url('/fonts/ibm-plex-sans-var-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ---------- 1. CANONICAL · light (the P1+ default) ---------- */
:root{
  /* Ground is warm ivory, not cool grey-blue: it is what stops both the public
     site and the app reading as a default light theme, and it gives a white
     card an edge without needing a heavy border. Ink on it is 14.9:1. */
  --color-ground:#FBFAF7; --color-surface:#FFFFFF; --color-well:#F4F1EA; --color-ink-surface:#0B1B3A;
  --color-hair:#E8E3D9; --color-hair-2:#D8D1C3; --color-hair-brand:#B9D0F5; --color-edge:#7A889F;
  --color-text:#0B1B3A; --color-text-2:#3D4B66; --color-muted:#5A6B82; --color-text-inverse:#FFFFFF;
  --color-brand:#0B5ED7; --color-brand-strong:#0A4DB0; --color-brand-text:#0B5ED7; --color-brand-soft:#E8F0FE; --color-on-brand:#FFFFFF; --color-mark:#1683FF;
  --color-ok:#0B6F5A; --color-ok-soft:#E3F3EE; --color-warn:#9A5B00; --color-warn-soft:#FFF3DB; --color-bad:#B42318; --color-bad-soft:#FCEBEA; --color-info:#0B5ED7; --color-info-soft:#E8F0FE; --color-neutral:#4B5A73; --color-neutral-soft:#EEF1F6;
  --color-track:#E8ECF3; --color-paper:#FBFAF6;
  --font-display:"Instrument Sans","IBM Plex Sans",system-ui,sans-serif;
  --font-ui:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
  --font-data:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --fs-2xs:11px; --fs-xs:12px; --fs-sm:13px; --fs-md:14px; --fs-base:15px; --fs-lg:16px; --fs-xl:18px; --fs-2xl:20px; --fs-3xl:24px; --fs-4xl:28px; --fs-5xl:34px; --fs-6xl:44px;
  --fw-regular:400; --fw-medium:500; --fw-semibold:600; --fw-bold:700;
  --lh-tight:1.05; --lh-heading:1.2; --lh-ui:1.45; --lh-body:1.6;
  --ls-display:-.025em; --ls-heading:-.015em; --ls-eyebrow:.08em; --ls-data:.01em;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px; --sp-10:40px; --sp-12:48px; --sp-16:64px;
  --container-sm:640px; --container:920px; --container-lg:1100px; --container-xl:1280px; --measure:65ch; --gutter:16px; --grid-gap:16px; --tap-min:44px; --rail-w:240px; --nav-h:64px;
  --radius-xs:4px; --radius-sm:6px; --radius-md:8px; --radius-lg:12px; --radius-xl:16px; --radius-pill:999px;
  --shadow-sm:0 1px 2px rgba(11,27,58,.06); --shadow-md:0 4px 12px -4px rgba(11,27,58,.12); --shadow-lg:0 16px 40px -12px rgba(11,27,58,.22); --shadow-focus:0 0 0 3px rgba(11,94,215,.18);
  --z-world:0; --z-content:2; --z-header:3; --z-sticky:20; --z-nav:40; --z-rail:60; --z-overlay:75; --z-fab:79; --z-modal:80; --z-modal-2:81; --z-toast:99; --z-top:9999;
  --dur-1:120ms; --dur-2:180ms; --dur-3:280ms; --dur-4:600ms; --ease-out:cubic-bezier(.2,.7,.2,1); --ease-in-out:cubic-bezier(.4,0,.2,1);
  --focus-ring:2px solid #0A4DB0; --focus-offset:2px;
  --icon-sm:16px; --icon-md:20px; --icon-lg:24px; --icon-stroke:1.75;
  --route-stroke:2px; --route-color:#0B5ED7; --route-dot:8px;
}
/* ---------- 1. CANONICAL · dark (Mission Control palette; OS preference or an explicit .ff-dark on <html>) ---------- */
/* The OS-preference dark palette is gated behind .ff-auto-dark, which nothing sets yet.
   Reason: the app's own light mode is body.light, and from P1.1 its legacy aliases resolve
   through the canonical --color-* set. If this block applied on OS preference alone, a user
   whose system is dark would get dark values inside the app's LIGHT mode. The app's existing
   dark mode does not read these tokens (it uses the COMPAT literals below), so gating costs
   nothing today. Re-enable it in the phase that wires Clear Sky dark mode to the app. */
@media (prefers-color-scheme: dark){:root.ff-auto-dark:not(.ff-light){
  --color-ground:#0A0F1C; --color-surface:#121A2B; --color-well:#18223A; --color-ink-surface:#F3F6FC;
  --color-hair:#223050; --color-hair-2:#2C3B5E; --color-hair-brand:#2F4A80; --color-edge:#56709F;
  --color-text:#F3F6FC; --color-text-2:#B7C2D9; --color-muted:#8A98B5; --color-text-inverse:#0A0F1C;
  --color-brand:#2563EB; --color-brand-strong:#1D4ED8; --color-brand-text:#6EA8FF; --color-brand-soft:rgba(110,168,255,.14); --color-on-brand:#FFFFFF;
  --color-ok:#34D399; --color-ok-soft:rgba(52,211,153,.14); --color-warn:#FBBF24; --color-warn-soft:rgba(251,191,36,.14); --color-bad:#F87171; --color-bad-soft:rgba(248,113,113,.14); --color-info:#6EA8FF; --color-info-soft:rgba(110,168,255,.14); --color-neutral:#8A98B5; --color-neutral-soft:rgba(138,152,181,.14);
  --color-track:#1B2540;
  --shadow-sm:0 0 0 1px rgba(255,255,255,.03); --shadow-md:0 0 0 1px rgba(255,255,255,.04),0 8px 24px -12px rgba(0,0,0,.6); --shadow-lg:0 0 0 1px rgba(255,255,255,.05),0 24px 60px -16px rgba(0,0,0,.7); --shadow-focus:0 0 0 3px rgba(138,180,255,.22);
  --focus-ring:2px solid #8AB4FF; --route-color:#6EA8FF;
}}
:root.ff-dark{
  --color-ground:#0A0F1C; --color-surface:#121A2B; --color-well:#18223A; --color-ink-surface:#F3F6FC;
  --color-hair:#223050; --color-hair-2:#2C3B5E; --color-hair-brand:#2F4A80; --color-edge:#56709F;
  --color-text:#F3F6FC; --color-text-2:#B7C2D9; --color-muted:#8A98B5; --color-text-inverse:#0A0F1C;
  --color-brand:#2563EB; --color-brand-strong:#1D4ED8; --color-brand-text:#6EA8FF; --color-brand-soft:rgba(110,168,255,.14); --color-on-brand:#FFFFFF;
  --color-ok:#34D399; --color-ok-soft:rgba(52,211,153,.14); --color-warn:#FBBF24; --color-warn-soft:rgba(251,191,36,.14); --color-bad:#F87171; --color-bad-soft:rgba(248,113,113,.14); --color-info:#6EA8FF; --color-info-soft:rgba(110,168,255,.14); --color-neutral:#8A98B5; --color-neutral-soft:rgba(138,152,181,.14);
  --color-track:#1B2540;
  --shadow-sm:0 0 0 1px rgba(255,255,255,.03); --shadow-md:0 0 0 1px rgba(255,255,255,.04),0 8px 24px -12px rgba(0,0,0,.6); --shadow-lg:0 0 0 1px rgba(255,255,255,.05),0 24px 60px -16px rgba(0,0,0,.7); --shadow-focus:0 0 0 3px rgba(138,180,255,.22);
  --focus-ring:2px solid #8AB4FF; --route-color:#6EA8FF;
}

/* ---------- 2. LANG · per-script stacks (inert until <html lang> is set in P1) ---------- */
:lang(ur),:lang(ar){--font-display:"IBM Plex Sans Arabic","IBM Plex Sans",sans-serif;--font-ui:"IBM Plex Sans Arabic","IBM Plex Sans",sans-serif;--ls-display:0;--ls-heading:0;--ls-eyebrow:0;--lh-body:1.8;--lh-ui:1.6}
:lang(hi){--font-display:"IBM Plex Sans Devanagari","IBM Plex Sans",sans-serif;--font-ui:"IBM Plex Sans Devanagari","IBM Plex Sans",sans-serif;--ls-display:0;--ls-heading:0;--ls-eyebrow:0;--lh-body:1.7}
:lang(bn){--font-display:"Noto Sans Bengali","IBM Plex Sans",sans-serif;--font-ui:"Noto Sans Bengali","IBM Plex Sans",sans-serif;--ls-display:0;--ls-heading:0;--ls-eyebrow:0;--lh-body:1.75}

/* ---------- 3. COMPAT · legacy names at today's computed values (verbatim from the 2026-09-06 snapshot) ---------- */
:root{
  --ink:#0E1F42; --gold:#1683FF; --gold-soft:rgba(22,131,255,.16); --green:#0E7C66; --green-soft:#E6F5F1; --crimson:#C2415A; --crimson-soft:#FBEAEE;
  --blue:#2563EB; --blue-soft:#EAF1FE; --slate:#5A6B82; --line:rgba(120,180,255,.3); --soft:#F4F8FD; --panel:#FFFFFF; --bg:#F7FAFE;
  --ink2:#14295A; --line-hi:rgba(0,212,255,.6); --gold-2:#3D9BFF; --paper:#F5F1E8; --txt:#FFFFFF; --txt-2:#EAF2FF; --txt-3:#C7D9F6;
  --r-s:var(--radius-md); --r-m:var(--radius-lg); --r-l:var(--radius-xl);
  --sh-1:0 1px 2px rgba(2,8,20,.35),0 8px 24px rgba(2,8,20,.35); --sh-2:0 2px 4px rgba(2,8,20,.4),0 18px 50px rgba(2,8,20,.5);
  --ease:var(--ease-in-out); --cy:#00D4FF;
  --ff-radius:var(--radius-lg); --ff-radius-sm:var(--radius-md); --ff-gap:var(--sp-3); --ff-shadow:0 1px 2px rgba(3,10,30,.25),0 8px 24px -12px rgba(3,10,30,.45); --ff-ease:var(--ease-out);
  --ff-accent:#00D4FF; --ff-warm:#F5B841; --ff-ok:#4ade80; --ff-bad:#fb7185; --ff-text:#EAF2FF; --ff-muted:#8FA9CE;
  --surface:rgba(10,20,44,.72); --surface-2:rgba(14,31,66,.9); --hair:rgba(140,178,255,.16); --hair-2:rgba(140,178,255,.28);
  --st-grey:#8FA9CE; --st-blue:#00D4FF; --st-amber:#FFD070; --st-green:#4ade80; --st-red:#fb7185; --st-teal:#2dd4bf; --st-mint:#6EE7A8; --st-fade:#B4CDF0;
}
body.light{--surface:#FFFFFF; --surface-2:var(--color-well); --hair:var(--color-hair); --hair-2:var(--color-hair-2); --ff-text:var(--color-text); --ff-muted:var(--color-muted); --line:var(--color-hair); --line-hi:var(--color-hair-brand); --panel:var(--color-surface); --bg:var(--color-ground); --ink:var(--color-text); --ink2:var(--color-text-2); --slate:var(--color-muted); --soft:var(--color-well); --paper:var(--color-paper);
  --gold:var(--color-brand); --gold-2:var(--color-brand-strong); --gold-soft:var(--color-brand-soft); --blue:var(--color-brand-text); --blue-soft:var(--color-info-soft); --cy:var(--color-brand-strong); --ff-accent:var(--color-brand-strong);
  --green:var(--color-ok); --green-soft:var(--color-ok-soft); --crimson:var(--color-bad); --crimson-soft:var(--color-bad-soft); --ff-ok:var(--color-ok); --ff-bad:var(--color-bad); --ff-warm:var(--color-warn);
  --st-blue:var(--color-info); --st-amber:var(--color-warn); --st-green:var(--color-ok); --st-red:var(--color-bad); --st-grey:var(--color-neutral); --st-teal:#0F766E; --st-mint:#0B6F5A; --st-fade:var(--color-muted);
  --sh-1:var(--shadow-sm); --sh-2:var(--shadow-lg); --ff-shadow:var(--shadow-md);
}

:root{--ffx-motion-k:1;--ffx-section-space-sm:48px;--ffx-section-space-md:64px;--ffx-section-space-lg:96px;--ffx-hero-size-min:44px;--ffx-hero-size-max:56px;--ffx-hero-tracking:-0.025em;--ffx-route-stroke:2px;--ffx-route-draw-ms:600ms;--ffx-route-mark-scale:1;--ffx-route-mark-speed:1;--ffx-parallax-k:0.1;--ffx-img-x:50%;--ffx-img-y:40%;--ffx-img-zoom:1;--ffx-horizon-x:78%;--ffx-horizon-y:112%;--ffx-horizon-scale:1.35;--ffx-horizon-rot:-0.6rad;--ffx-reveal-rise:8px;--ffx-reveal-ms:600ms}
/* ============================================================================
   ForiForeign narrative layer (L4) · P1.0 infrastructure
   Inlined by the build after tokens.css. Every selector here is namespaced
   `ffn-` or keyed on a `data-scene` attribute, and nothing in the app or the
   marketing pages carries those names yet, so this file changes no rendered
   pixel until a later phase opts an element in. Values come from the --ffx-*
   custom properties the build generates from public/src/scenes.json; none are
   hard-coded here so every parameter stays independently adjustable.
   ============================================================================ */

/* ---------- section rhythm and hero type, driven by config ---------- */
.ffn-section{padding-block:var(--ffx-section-space-md)}
@media(max-width:640px){.ffn-section{padding-block:var(--ffx-section-space-sm)}}
@media(min-width:1100px){.ffn-section{padding-block:var(--ffx-section-space-lg)}}
.ffn-hero-h{font-family:var(--font-display);font-weight:var(--fw-bold);letter-spacing:var(--ffx-hero-tracking);line-height:var(--lh-heading);font-size:clamp(var(--ffx-hero-size-min),4.2vw + 1rem,var(--ffx-hero-size-max));text-wrap:balance}

/* ---------- reveal: visible at rest, animates only when JS marks the root ---------- */
html.ffn-js .ffn-reveal{opacity:0;transform:translateY(var(--ffx-reveal-rise))}
html.ffn-js .ffn-reveal.is-in{opacity:1;transform:none;transition:opacity calc(var(--ffx-reveal-ms) * var(--ffx-motion-k)) var(--ease-out),transform calc(var(--ffx-reveal-ms) * var(--ffx-motion-k)) var(--ease-out)}

/* ---------- the route: a line with waypoints and a travelling mark ---------- */
.ffn-route{--_c:var(--route-color);display:flex;align-items:center;position:relative}
.ffn-route .ffn-wp{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--sp-1h,6px);position:relative}
.ffn-route .ffn-wp::before{content:"";position:absolute;top:3px;inset-inline-start:50%;inset-inline-end:-50%;height:var(--ffx-route-stroke);background:var(--color-hair-2)}
.ffn-route .ffn-wp.is-done::before,.ffn-route .ffn-wp.is-now::before{background:var(--_c)}
.ffn-route .ffn-wp:last-child::before{display:none}
.ffn-route .ffn-wp i{width:var(--route-dot);height:var(--route-dot);border-radius:50%;background:var(--color-surface);border:2px solid var(--color-hair-2);position:relative;z-index:1}
.ffn-route .ffn-wp.is-done i{background:var(--_c);border-color:var(--_c)}
.ffn-route .ffn-wp.is-now i{border-color:var(--_c);box-shadow:0 0 0 4px var(--color-brand-soft)}
.ffn-route .ffn-wp b{font:var(--fw-semibold) var(--fs-xs) var(--font-ui);color:var(--color-muted)}
.ffn-route .ffn-wp.is-now b{color:var(--color-text)}
.ffn-route .ffn-wp span{font:var(--fw-medium) var(--fs-2xs) var(--font-data);letter-spacing:var(--ls-eyebrow);text-transform:uppercase;color:var(--color-muted)}

/* SVG route: draw with dashoffset; the mark follows an offset-path where supported */
.ffn-route-svg .ffn-line{fill:none;stroke:var(--route-color);stroke-width:var(--ffx-route-stroke);stroke-linecap:round}
html.ffn-js .ffn-route-svg .ffn-line{stroke-dasharray:var(--_len,1000);stroke-dashoffset:var(--_len,1000)}
html.ffn-js .ffn-route-svg.is-in .ffn-line{stroke-dashoffset:0;transition:stroke-dashoffset calc(var(--ffx-route-draw-ms) * var(--ffx-motion-k)) var(--ease-out)}
.ffn-route-svg .ffn-mark{fill:var(--route-color);transform:scale(var(--ffx-route-mark-scale));transform-box:fill-box;transform-origin:center}
@supports (offset-path: path("M0 0")){html.ffn-js .ffn-route-svg.is-in .ffn-mark{offset-path:var(--_path,none);offset-rotate:auto;animation:ffn-travel calc(var(--ffx-route-draw-ms) * var(--ffx-motion-k) / var(--ffx-route-mark-speed)) var(--ease-out) forwards}}
@keyframes ffn-travel{from{offset-distance:0%}to{offset-distance:100%}}

/* ---------- typed document: measured widths, steps() timing, class-driven ---------- */
.ffn-typed .ffn-line{white-space:nowrap;overflow:hidden}
.ffn-typed .ffn-line>.ffn-inner{display:inline-block;white-space:nowrap}
html.ffn-js .ffn-typed:not(.is-done) .ffn-line:not(.is-typed)>.ffn-inner{width:0}
.ffn-typed .ffn-stamp{opacity:0;transform:translateY(4px)}
.ffn-typed .ffn-line.is-typed .ffn-stamp,.ffn-typed.is-done .ffn-stamp{opacity:1;transform:none;transition:opacity calc(180ms * var(--ffx-motion-k)) var(--ease-out),transform calc(180ms * var(--ffx-motion-k)) var(--ease-out)}

/* ---------- count-up: final value always present in markup as data-final ---------- */
.ffn-count{font-variant-numeric:tabular-nums}

/* ---------- parallax: two layers at most, transform only, strength from config ---------- */
.ffn-parallax{position:relative;overflow:hidden}
.ffn-parallax [data-layer]{will-change:transform;transform:translate3d(0,calc(var(--_scroll,0px) * var(--ffx-parallax-k) * var(--_depth,1) * -1),0)}
@media(pointer:coarse){.ffn-parallax [data-layer]{transform:none;will-change:auto}}

/* ---------- image slots: crop and zoom are config, never layout ---------- */
.ffn-img{display:block;width:100%;height:100%;object-fit:cover;object-position:var(--ffx-img-x) var(--ffx-img-y);transform:scale(var(--ffx-img-zoom));transform-origin:var(--ffx-img-x) var(--ffx-img-y)}
.ffn-slot{position:relative;overflow:hidden;background:var(--color-well)}
.ffn-slot[data-ratio="3:2"]{aspect-ratio:3/2}.ffn-slot[data-ratio="4:5"]{aspect-ratio:4/5}.ffn-slot[data-ratio="16:9"]{aspect-ratio:16/9}.ffn-slot[data-ratio="1:1"]{aspect-ratio:1/1}

/* ---------- scene mounts: reserved boxes, still image is the truth ---------- */
[data-scene]{position:relative;overflow:hidden;contain:layout paint}
[data-scene] .ffn-still{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;object-position:var(--ffx-horizon-x) var(--ffx-horizon-y);transform:scale(var(--ffx-horizon-scale)) rotate(var(--ffx-horizon-rot));transform-origin:var(--ffx-horizon-x) var(--ffx-horizon-y)}
[data-scene] canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
[data-scene].is-live .ffn-still{visibility:hidden}

/* ---------- reduced motion: one rule for the whole layer ---------- */
@media (prefers-reduced-motion:reduce){
  html.ffn-js .ffn-reveal,html.ffn-js .ffn-reveal.is-in{opacity:1!important;transform:none!important;transition:none!important}
  html.ffn-js .ffn-route-svg .ffn-line{stroke-dashoffset:0!important;transition:none!important}
  html.ffn-js .ffn-route-svg .ffn-mark{animation:none!important;offset-distance:100%}
  html.ffn-js .ffn-typed .ffn-line>.ffn-inner{width:auto!important}
  .ffn-typed .ffn-stamp{opacity:1!important;transform:none!important}
  .ffn-parallax [data-layer]{transform:none!important}
  [data-scene].is-live .ffn-still{visibility:visible}
}
