/* ==========================================================================
   salam-portfolio — design tokens
   theme/salam-portfolio/assets/css/tokens.css

   THE SINGLE CANONICAL SOURCE FOR EVERY DESIGN VALUE.

   theme.json does not restate any literal from this file. Its colour palette,
   font sizes and spacing presets all reference these custom properties with
   var(), so a token has exactly one definition and the editor, the front end
   and dark mode cannot drift apart. See docs/ARCHITECTURE.md section 2.

   Carried over from the classic theme's token file, which was measured against
   the source site in Phase 1. The classic theme keeps its own frozen copy as a
   rollback target; this file is canonical from here on.
   --------------------------------------------------------------------------
   LAYER 1  --c-*   raw ramp. Theme-independent. Declared once. Never
                    redefined by a theme block. Swapping the brand hue means
                    editing the --c-brand-* block and nothing else. Enforced by
                    scripts/check-no-literals.mjs, which fails if a brand hex
                    appears anywhere outside its own declaration.
   LAYER 2  --sn-*  semantic aliases. Light on bare :root. ONLY the 26 colour
                    tokens are redefined in the two dark blocks.
   LAYER 3  scopes  .sn-invert and [data-band] re-point Layer-2 tokens.
                    No component CSS may name a colour literal.

   Every ratio in the comments was measured with the WCAG 2.x relative
   luminance formula. Do not change a value without re-measuring.
   ========================================================================== */

/* --------------------------------------------------------------------------
   LAYER 1 — raw ramp
   -------------------------------------------------------------------------- */
:root {
  color-scheme: light dark;

  /* Neutrals. Slight blue cast so they sit with the brand rather than
     fighting it. Replaces five different legacy near-blacks
     (#181818 #1E1E1E #1E0C0C #030B0F #170303) and four greys
     (#636363 #686868 #8F949D #AEAEAE). */
  --c-n-000: #FFFFFF;
  --c-n-005: #FBFAF7;   /* warm paper — ink 17.28:1 · ink-2 7.63:1 · brand 11.75:1 */
  --c-n-020: #E9EBF4;
  --c-n-025: #F5F6FB;
  --c-n-050: #E9EBF7;
  --c-n-100: #D6D9E6;
  --c-n-200: #C9CEDD;
  --c-n-300: #AFB5C9;
  --c-n-350: #A7AEC2;
  --c-n-400: #8C93A8;
  --c-n-450: #6B7284;
  --c-n-500: #6E7488;
  --c-n-600: #5F6577;
  --c-n-700: #4C5262;
  --c-n-750: #3C4356;
  --c-n-800: #1E2231;
  --c-n-850: #151824;
  --c-n-900: #14161F;
  --c-n-950: #0D0F16;

  /* Brand. #E7E8F9, #4054B2 and #1114AB are measured legacy values kept in
     the roles they already perform. The rest are derived.
     TODO(owner): confirm blue over cluster B purple #A34CBF or the
     cluster C navy+gold pairing. Changing hue = these eight lines only. */
  --c-brand-050: #F2F3FC;
  --c-brand-100: #E7E8F9;   /* legacy, 98 uses — tint band            */
  --c-brand-200: #C6CDFF;   /* derived — dark hover ink, selection    */
  --c-brand-300: #A9B5FF;   /* derived — dark brand ink               */
  --c-brand-600: #4054B2;   /* legacy, 28 uses — large fill           */
  --c-brand-750: #2A3160;   /* derived — dark selection ground        */
  --c-brand-800: #1114AB;   /* legacy, 239 uses — links, headings     */
  --c-brand-900: #0B0D7B;   /* derived — hover / active               */
  --c-brand-tint-dk: #1B2040;

  /* Front-page field. These are brand-family blues, so they live in the brand
     ramp rather than being invented at the semantic layer. That is what keeps
     a hue change to this one block. */
  --c-brand-250: #BFC4EE;   /* echo on the field, light  — 7.21:1 on field */
  --c-brand-275: #AEB4E8;   /* echo on the field, dark   — 8.58:1 on field */
  --c-brand-350: #A8AEE6;   /* rail on the field, light  — 5.76:1 on field */
  --c-brand-375: #9AA1E0;   /* rail on the field, dark   — 6.99:1 on field */
  --c-brand-950: #0A0B5E;   /* the field itself, dark    — white on it 17.18:1 */

  /* Accent. #D7A150 is a measured legacy value and is GRAPHIC ONLY on light
     (2.31:1 on white). --c-accent-800 is its text-safe counterpart. */
  --c-accent-300: #E3B76C;
  --c-accent-500: #D7A150;
  --c-accent-800: #8A5411;

  /* Signal. #00CE1B (legacy, 2.13:1) and #D31A1A (4.50:1 on the deepest
     tint) are both replaced. */
  --c-red-300:   #FF9A9A;
  --c-red-700:   #B4141A;
  --c-green-300: #5FD08A;
  --c-green-800: #0B6E2B;

  /* Band tints. Replace ten arbitrary legacy alpha hexes. */
  --c-band-brand-lt:  #EDEFF9;
  --c-band-brand-dk:  #161A2A;
  --c-band-accent-lt: #FAF3E8;
  --c-band-accent-dk: #221C12;

  /* White alphas for rules drawn on the field. */
  --c-white-a35: rgb(255 255 255 / 0.35);
  --c-white-a28: rgb(255 255 255 / 0.28);
}

/* --------------------------------------------------------------------------
   LAYER 2a — semantic colour, LIGHT (the default)
   -------------------------------------------------------------------------- */
:root {
  --sn-canvas:            var(--c-n-000);
  --sn-surface:           var(--c-n-025);
  --sn-surface-2:         var(--c-n-050);

  --sn-ink:               var(--c-n-900);   /* 18.04:1 on canvas */
  --sn-ink-2:             var(--c-n-700);   /*  7.80:1 on canvas */
  --sn-ink-3:             var(--c-n-600);   /*  5.81:1 on canvas */

  --sn-brand:             var(--c-brand-800);  /* 12.27:1 on canvas */
  --sn-brand-hover:       var(--c-brand-900);  /* 15.47:1 on canvas */
  --sn-brand-fill:        var(--c-brand-600);  /* white on it = 6.71:1 */
  --sn-brand-tint:        var(--c-brand-100);  /* ink on it = 14.87:1 */
  --sn-on-brand:          var(--c-n-000);      /* 12.27:1 on --sn-brand */
  --sn-on-brand-fill:     var(--c-n-000);      /*  6.71:1 on --sn-brand-fill */

  --sn-accent:            var(--c-accent-800); /*  6.26:1 on canvas */
  --sn-accent-graphic:    var(--c-accent-500); /*  2.31:1 — GRAPHIC ONLY */
  --sn-on-accent-graphic: var(--c-n-900);      /*  7.82:1 on the gold */

  --sn-danger:            var(--c-red-700);    /*  6.87:1 on canvas */
  --sn-on-danger:         var(--c-n-000);      /*  6.87:1 on --sn-danger */
  --sn-success:           var(--c-green-800);  /*  6.40:1 on canvas */
  --sn-on-success:        var(--c-n-000);      /*  6.40:1 on --sn-success */

  --sn-line:              var(--c-n-100);   /* 1.41:1 — DECORATIVE ONLY */
  --sn-line-strong:       var(--c-n-300);   /* 2.04:1 — DECORATIVE ONLY */
  --sn-line-input:        var(--c-n-500);   /* 4.65:1 — every UI boundary */

  --sn-focus:             var(--c-brand-800);
  --sn-focus-halo:        var(--c-n-000);
  --sn-selection-bg:      var(--c-brand-200);
  --sn-selection-ink:     var(--c-n-900);   /* 11.66:1 */

  --sn-band-brand:        var(--c-band-brand-lt);
  --sn-band-accent:       var(--c-band-accent-lt);
  --sn-band-neutral:      var(--c-n-025);

  --sn-overlay:           rgb(13 15 22 / 0.62);
  --sn-shadow-rgb:        17 20 171;
  --sn-shadow-a1:         0.06;
  --sn-shadow-a2:         0.10;
  --sn-shadow-a3:         0.16;
  --sn-shadow-ring:       0 0 0 0 transparent;  /* no-op in light; becomes a
                                    visible hairline in dark, where a shadow
                                    alone is invisible */
}

/* --------------------------------------------------------------------------
   LAYER 2b — semantic colour, DARK
   Two blocks, identical bodies. 26 tokens. Nothing else is redefined.
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --sn-canvas:        var(--c-n-950);
    --sn-surface:       var(--c-n-850);
    --sn-surface-2:     var(--c-n-800);
    --sn-ink:           var(--c-n-020);        /* 16.09:1 */
    --sn-ink-2:         var(--c-n-350);        /*  8.64:1 */
    --sn-ink-3:         var(--c-n-400);        /*  6.25:1 */
    --sn-brand:         var(--c-brand-300);    /*  9.79:1 */
    --sn-brand-hover:   var(--c-brand-200);    /* 12.38:1 */
    --sn-brand-fill:    var(--c-brand-300);
    --sn-brand-tint:    var(--c-brand-tint-dk);
    --sn-on-brand:      var(--c-n-950);        /*  9.79:1 on --sn-brand */
    --sn-on-brand-fill: var(--c-n-950);
    --sn-accent:        var(--c-accent-300);   /* 10.26:1 */
    --sn-danger:        var(--c-red-300);      /*  9.43:1 */
    --sn-on-danger:     var(--c-n-950);
    --sn-success:       var(--c-green-300);    /*  9.91:1 */
    --sn-on-success:    var(--c-n-950);
    --sn-line:          var(--c-n-800);
    --sn-line-strong:   var(--c-n-750);
    --sn-line-input:    var(--c-n-450);        /*  3.98:1 */
    --sn-focus:         var(--c-brand-300);
    --sn-focus-halo:    var(--c-n-950);
    --sn-selection-bg:  var(--c-brand-750);
    --sn-selection-ink: var(--c-n-020);        /* 10.34:1 */
    --sn-band-brand:    var(--c-band-brand-dk);
    --sn-band-accent:   var(--c-band-accent-dk);
    --sn-band-neutral:  var(--c-n-850);
    --sn-overlay:       rgb(5 6 10 / 0.72);
    --sn-shadow-rgb:    0 0 0;
    --sn-shadow-a1:     0.40;
    --sn-shadow-a2:     0.50;
    --sn-shadow-a3:     0.60;
    --sn-shadow-ring:   0 0 0 1px var(--sn-line);
  }
}

:root[data-theme="dark"] {
  --sn-canvas:        var(--c-n-950);
  --sn-surface:       var(--c-n-850);
  --sn-surface-2:     var(--c-n-800);
  --sn-ink:           var(--c-n-020);
  --sn-ink-2:         var(--c-n-350);
  --sn-ink-3:         var(--c-n-400);
  --sn-brand:         var(--c-brand-300);
  --sn-brand-hover:   var(--c-brand-200);
  --sn-brand-fill:    var(--c-brand-300);
  --sn-brand-tint:    var(--c-brand-tint-dk);
  --sn-on-brand:      var(--c-n-950);
  --sn-on-brand-fill: var(--c-n-950);
  --sn-accent:        var(--c-accent-300);
  --sn-danger:        var(--c-red-300);
  --sn-on-danger:     var(--c-n-950);
  --sn-success:       var(--c-green-300);
  --sn-on-success:    var(--c-n-950);
  --sn-line:          var(--c-n-800);
  --sn-line-strong:   var(--c-n-750);
  --sn-line-input:    var(--c-n-450);
  --sn-focus:         var(--c-brand-300);
  --sn-focus-halo:    var(--c-n-950);
  --sn-selection-bg:  var(--c-brand-750);
  --sn-selection-ink: var(--c-n-020);
  --sn-band-brand:    var(--c-band-brand-dk);
  --sn-band-accent:   var(--c-band-accent-dk);
  --sn-band-neutral:  var(--c-n-850);
  --sn-overlay:       rgb(5 6 10 / 0.72);
  --sn-shadow-rgb:    0 0 0;
  --sn-shadow-a1:     0.40;
  --sn-shadow-a2:     0.50;
  --sn-shadow-a3:     0.60;
  --sn-shadow-ring:   0 0 0 1px var(--sn-line);
}

/* --------------------------------------------------------------------------
   LAYER 2c — non-colour tokens. Declared once. Never redefined by a theme.
   -------------------------------------------------------------------------- */
:root {
  /* Type families ------------------------------------------------------- */
  --sn-font-sans: "IBM Plex Sans", "IBM Plex Sans Arabic", ui-sans-serif,
                  system-ui, -apple-system, "Segoe UI", "Noto Sans Arabic",
                  Arial, sans-serif;
  --sn-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo,
                  Consolas, monospace;

  /* Script compensation. Overridden by the :lang() blocks below.
     These are baked into every --sn-fs-* and --sn-lh-* below; a component
     must NEVER multiply by them again. */
  --sn-script-scale:   1;
  --sn-script-leading: 0;
  --sn-track-scale:    1;

  /* Fluid type scale — 390px to 1440px, verified at both endpoints.
     Every step is rem-led so text-only zoom still scales the page.
     --*--raw holds the script-neutral geometry; the final token is aliased
     here and REDECLARED in the :lang() blocks. It must be redeclared there
     rather than multiplied here: var() inside a custom property resolves on
     the element that DECLARES it, so a multiplier referenced on :root would
     always resolve against :root's value and never see :lang(ar). */
  --sn-fs-2xs--raw: clamp(0.7500rem, 0.7268rem + 0.0952vw, 0.8125rem);
  --sn-fs-xs--raw:  clamp(0.8125rem, 0.7893rem + 0.0952vw, 0.8750rem);
  --sn-fs-sm--raw:  clamp(0.8750rem, 0.8286rem + 0.1905vw, 1.0000rem);
  --sn-fs-md--raw:  clamp(1.0000rem, 0.9536rem + 0.1905vw, 1.1250rem);
  --sn-fs-lg--raw:  clamp(1.1250rem, 1.0554rem + 0.2857vw, 1.3125rem);
  --sn-fs-xl--raw:  clamp(1.2500rem, 1.1571rem + 0.3810vw, 1.5000rem);
  --sn-fs-2xl--raw: clamp(1.4375rem, 1.2750rem + 0.6667vw, 1.8750rem);
  --sn-fs-3xl--raw: clamp(1.6250rem, 1.3464rem + 1.1429vw, 2.3750rem);
  --sn-fs-4xl--raw: clamp(1.8750rem, 1.4571rem + 1.7143vw, 3.0000rem);
  --sn-fs-5xl--raw: clamp(2.1250rem, 1.6143rem + 2.0952vw, 3.5000rem);
  --sn-fs-6xl--raw: clamp(2.3750rem, 1.6786rem + 2.8571vw, 4.2500rem);

  --sn-fs-2xs: var(--sn-fs-2xs--raw);
  --sn-fs-xs:  var(--sn-fs-xs--raw);
  --sn-fs-sm:  var(--sn-fs-sm--raw);
  --sn-fs-md:  var(--sn-fs-md--raw);
  --sn-fs-lg:  var(--sn-fs-lg--raw);
  --sn-fs-xl:  var(--sn-fs-xl--raw);
  --sn-fs-2xl: var(--sn-fs-2xl--raw);
  --sn-fs-3xl: var(--sn-fs-3xl--raw);
  --sn-fs-4xl: var(--sn-fs-4xl--raw);
  --sn-fs-5xl: var(--sn-fs-5xl--raw);
  --sn-fs-6xl: var(--sn-fs-6xl--raw);

  /* Line height — --*--raw is the Latin figure; :lang(ar) adds
     --sn-script-leading to each. Same redeclaration rule as above. */
  --sn-lh-tight--raw:   1.08;
  --sn-lh-snug--raw:    1.18;
  --sn-lh-heading--raw: 1.28;
  --sn-lh-normal--raw:  1.50;
  --sn-lh-body--raw:    1.65;
  --sn-lh-loose--raw:   1.75;

  --sn-lh-tight:   var(--sn-lh-tight--raw);
  --sn-lh-snug:    var(--sn-lh-snug--raw);
  --sn-lh-heading: var(--sn-lh-heading--raw);
  --sn-lh-normal:  var(--sn-lh-normal--raw);
  --sn-lh-body:    var(--sn-lh-body--raw);
  --sn-lh-loose:   var(--sn-lh-loose--raw);

  /* Weight */
  --sn-wt-light:    300;
  --sn-wt-regular:  400;
  --sn-wt-medium:   500;
  --sn-wt-semibold: 600;
  --sn-wt-bold:     700;

  /* Tracking — :lang(ar) multiplies every one by --sn-track-scale: 0, so
     negative letter-spacing on Arabic is structurally impossible.
     Same redeclaration rule as above. */
  --sn-track-tight--raw: -0.02em;
  --sn-track-snug--raw:  -0.01em;
  --sn-track-wide--raw:   0.04em;

  --sn-track-tight: var(--sn-track-tight--raw);
  --sn-track-snug:  var(--sn-track-snug--raw);
  --sn-track-none:  0em;
  --sn-track-wide:  var(--sn-track-wide--raw);

  /* Space — fixed below 16px, fluid above */
  --sn-space-3xs: 0.25rem;
  --sn-space-2xs: 0.50rem;
  --sn-space-xs:  0.75rem;
  --sn-space-sm:  1.00rem;
  --sn-space-md:  clamp(1.1250rem, 0.9857rem + 0.5714vw, 1.5000rem);
  --sn-space-lg:  clamp(1.5000rem, 1.3143rem + 0.7619vw, 2.0000rem);
  --sn-space-xl:  clamp(2.0000rem, 1.6286rem + 1.5238vw, 3.0000rem);
  --sn-space-2xl: clamp(2.5000rem, 1.9429rem + 2.2857vw, 4.0000rem);
  --sn-space-3xl: clamp(3.0000rem, 2.2571rem + 3.0476vw, 5.0000rem);
  --sn-space-4xl: clamp(3.5000rem, 2.3857rem + 4.5714vw, 6.5000rem);
  --sn-gutter:    clamp(1.2500rem, 0.7857rem + 1.9048vw, 2.5000rem);

  /* Containers */
  --sn-w-prose:   min(68ch, 44rem);
  --sn-w-text:    46rem;
  --sn-w-content: 72rem;
  --sn-w-wide:    84rem;
  --sn-w-full:    100%;

  /* Radii */
  --sn-radius-0:    0;
  --sn-radius-xs:   4px;
  --sn-radius-sm:   6px;
  --sn-radius-md:   10px;
  --sn-radius-lg:   14px;
  --sn-radius-xl:   20px;
  --sn-radius-full: 999px;

  /* Borders */
  --sn-border-hair:   1px;
  --sn-border-thick:  2px;
  --sn-border-accent: 6px;

  /* Shadows — colour and alpha are theme tokens, geometry is not */
  --sn-shadow-1:
    var(--sn-shadow-ring),
    0 1px 2px rgb(var(--sn-shadow-rgb) / var(--sn-shadow-a1));
  --sn-shadow-2:
    var(--sn-shadow-ring),
    0 2px 4px rgb(var(--sn-shadow-rgb) / var(--sn-shadow-a1)),
    0 8px 20px -6px rgb(var(--sn-shadow-rgb) / var(--sn-shadow-a2));
  --sn-shadow-3:
    var(--sn-shadow-ring),
    0 4px 8px rgb(var(--sn-shadow-rgb) / var(--sn-shadow-a1)),
    0 24px 48px -12px rgb(var(--sn-shadow-rgb) / var(--sn-shadow-a3));

  /* Motion */
  --sn-dur-1: 120ms;
  --sn-dur-2: 180ms;
  --sn-dur-3: 260ms;
  --sn-dur-4: 420ms;
  --sn-dur-5: 640ms;
  --sn-stagger: 60ms;
  --sn-ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --sn-ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --sn-ease-in:       cubic-bezier(0.7, 0, 0.84, 0);
  --sn-ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
  --sn-ease-emphasis: cubic-bezier(0.34, 1.4, 0.64, 1);

  /* Layers */
  --sn-z-below:      -1;
  --sn-z-base:        0;
  --sn-z-raised:      1;
  --sn-z-sticky:     10;
  --sn-z-header:    100;
  --sn-z-progress:  200;
  --sn-z-popover:   300;
  --sn-z-affordance:400;
  --sn-z-backdrop:  500;
  --sn-z-drawer:    600;
  --sn-z-dialog:    700;
  --sn-z-toast:     800;
  --sn-z-skiplink:  900;

  /* Direction. See LAYER 3 for the single [dir="rtl"] carve-out. */
  --sn-flip:  1;
  --sn-start: left;
  --sn-end:   right;
}

/* --------------------------------------------------------------------------
   Script compensation. :lang() not [lang] — :lang(ar) matches ar-YE and
   :lang(en) matches the en-GB this site actually emits.
   The :lang(en) rule is a reset for BLOCKS of English inside Arabic
   documents (page 328 carries 14 English portfolio cards in an RTL page).
   -------------------------------------------------------------------------- */
:lang(ar) {
  --sn-script-scale:   1.075;  /* +7.5% optical size            */
  --sn-script-leading: 0.14;   /* +0.14 line-height everywhere  */
  --sn-track-scale:    0;      /* all tracking resolves to 0em  */

  --sn-fs-2xs: calc(var(--sn-fs-2xs--raw) * var(--sn-script-scale));
  --sn-fs-xs:  calc(var(--sn-fs-xs--raw)  * var(--sn-script-scale));
  --sn-fs-sm:  calc(var(--sn-fs-sm--raw)  * var(--sn-script-scale));
  --sn-fs-md:  calc(var(--sn-fs-md--raw)  * var(--sn-script-scale));
  --sn-fs-lg:  calc(var(--sn-fs-lg--raw)  * var(--sn-script-scale));
  --sn-fs-xl:  calc(var(--sn-fs-xl--raw)  * var(--sn-script-scale));
  --sn-fs-2xl: calc(var(--sn-fs-2xl--raw) * var(--sn-script-scale));
  --sn-fs-3xl: calc(var(--sn-fs-3xl--raw) * var(--sn-script-scale));
  --sn-fs-4xl: calc(var(--sn-fs-4xl--raw) * var(--sn-script-scale));
  --sn-fs-5xl: calc(var(--sn-fs-5xl--raw) * var(--sn-script-scale));
  --sn-fs-6xl: calc(var(--sn-fs-6xl--raw) * var(--sn-script-scale));

  --sn-lh-tight:   calc(var(--sn-lh-tight--raw)   + var(--sn-script-leading));
  --sn-lh-snug:    calc(var(--sn-lh-snug--raw)    + var(--sn-script-leading));
  --sn-lh-heading: calc(var(--sn-lh-heading--raw) + var(--sn-script-leading));
  --sn-lh-normal:  calc(var(--sn-lh-normal--raw)  + var(--sn-script-leading));
  --sn-lh-body:    calc(var(--sn-lh-body--raw)    + var(--sn-script-leading));
  --sn-lh-loose:   calc(var(--sn-lh-loose--raw)   + var(--sn-script-leading));

  --sn-track-tight: calc(var(--sn-track-tight--raw) * var(--sn-track-scale));
  --sn-track-snug:  calc(var(--sn-track-snug--raw)  * var(--sn-track-scale));
  --sn-track-wide:  calc(var(--sn-track-wide--raw)  * var(--sn-track-scale));

  hyphens: none;
  word-spacing: 0.02em;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
}

/* Reset for BLOCKS of English inside an Arabic document. page-328 carries
   14 English portfolio cards inside an RTL page; those get <div lang="en">.
   NOTE: font-size and line-height inherit as COMPUTED values, so a nested
   block only picks this up if it re-asserts font-size / line-height from a
   token. base.css does exactly that on .sn-prose, .sn-project-row, headings
   and every type utility. */
:lang(en) {
  --sn-script-scale:   1;
  --sn-script-leading: 0;
  --sn-track-scale:    1;

  --sn-fs-2xs: var(--sn-fs-2xs--raw);
  --sn-fs-xs:  var(--sn-fs-xs--raw);
  --sn-fs-sm:  var(--sn-fs-sm--raw);
  --sn-fs-md:  var(--sn-fs-md--raw);
  --sn-fs-lg:  var(--sn-fs-lg--raw);
  --sn-fs-xl:  var(--sn-fs-xl--raw);
  --sn-fs-2xl: var(--sn-fs-2xl--raw);
  --sn-fs-3xl: var(--sn-fs-3xl--raw);
  --sn-fs-4xl: var(--sn-fs-4xl--raw);
  --sn-fs-5xl: var(--sn-fs-5xl--raw);
  --sn-fs-6xl: var(--sn-fs-6xl--raw);

  --sn-lh-tight:   var(--sn-lh-tight--raw);
  --sn-lh-snug:    var(--sn-lh-snug--raw);
  --sn-lh-heading: var(--sn-lh-heading--raw);
  --sn-lh-normal:  var(--sn-lh-normal--raw);
  --sn-lh-body:    var(--sn-lh-body--raw);
  --sn-lh-loose:   var(--sn-lh-loose--raw);

  --sn-track-tight: var(--sn-track-tight--raw);
  --sn-track-snug:  var(--sn-track-snug--raw);
  --sn-track-wide:  var(--sn-track-wide--raw);

  hyphens: manual;
  word-spacing: normal;
}

/* Inline Latin run that must return to Latin metrics inside Arabic prose.
   Rare — an inline Latin word should normally match the surrounding
   Arabic optical size. */
.sn-lat { font-size: calc(1em / var(--sn-script-scale, 1)); }

/* --------------------------------------------------------------------------
   LAYER 3 — scopes
   -------------------------------------------------------------------------- */

/* The ONLY [dir="rtl"] rule permitted in the codebase. It declares custom
   properties and nothing else. transform / translate / background-position /
   gradient direction / SVG have no logical equivalent; this is how they are
   handled. A second such rule is a design-review question, not a code change. */
/* stylelint-disable-next-line selector-disallowed-list */
[dir="rtl"] {
  --sn-flip:  -1;
  --sn-start: right;
  --sn-end:   left;
}

/* Inverted panel — deliberately ALWAYS dark, in both themes. Flipping it in
   dark mode would produce a white slab on a near-black page. In dark mode it
   only needs to separate from the ground, which is one token plus a hairline. */
.sn-invert {
  color-scheme: dark;
  --sn-canvas:        var(--c-n-950);
  --sn-surface:       var(--c-n-850);
  --sn-surface-2:     var(--c-n-800);
  --sn-ink:           var(--c-n-025);      /* 17.74:1 */
  --sn-ink-2:         var(--c-n-200);      /* 12.17:1 */
  --sn-ink-3:         var(--c-n-350);      /*  8.64:1 */
  --sn-brand:         var(--c-brand-300);  /*  9.79:1 */
  --sn-brand-hover:   var(--c-brand-200);
  --sn-brand-fill:    var(--c-brand-300);
  --sn-brand-tint:    var(--c-brand-tint-dk);
  --sn-on-brand:      var(--c-n-950);      /*  9.79:1 on --sn-brand */
  --sn-on-brand-fill: var(--c-n-950);
  --sn-accent:        var(--c-accent-300); /* 10.26:1 */
  --sn-danger:        var(--c-red-300);
  --sn-on-danger:     var(--c-n-950);
  --sn-success:       var(--c-green-300);
  --sn-on-success:    var(--c-n-950);
  --sn-line:          var(--c-n-800);
  --sn-line-strong:   var(--c-n-750);
  --sn-line-input:    var(--c-n-450);      /*  3.98:1 */
  --sn-focus:         var(--c-brand-300);
  --sn-focus-halo:    var(--c-n-950);
  --sn-selection-bg:  var(--c-brand-750);
  --sn-selection-ink: var(--c-n-020);
  --sn-band-brand:    var(--c-band-brand-dk);
  --sn-band-accent:   var(--c-band-accent-dk);
  --sn-band-neutral:  var(--c-n-850);
  --sn-shadow-rgb:    0 0 0;
  --sn-shadow-a1:     0.40;
  --sn-shadow-a2:     0.50;
  --sn-shadow-a3:     0.60;
  background-color: var(--sn-canvas);
  color: var(--sn-ink);
}

/* Dark-theme delta for the inverted panel: ONE token plus a hairline, so it
   still reads as a distinct panel against a near-black page. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sn-invert {
    --sn-canvas: var(--c-n-800);           /* ink 14.65:1, brand 8.09:1 */
    /* --sn-line-input, not --sn-line-strong: this border is what separates the
       panel from the page (the two grounds are only 1.21:1 apart), so WCAG
       1.4.11 applies. #6B7284 = 3.29:1 vs panel, 3.98:1 vs page. */
    border: var(--sn-border-hair) solid var(--sn-line-input);
  }
}
:root[data-theme="dark"] .sn-invert {
  --sn-canvas: var(--c-n-800);
  border: var(--sn-border-hair) solid var(--sn-line-input);
}

/* Tinted bands. Replaces ten arbitrary legacy alpha hexes with three
   knowable grounds. All ink tokens clear 4.89:1 on every one. */
.sn-band                     { background-color: var(--sn-band-neutral); }
.sn-band[data-band="brand"]  { background-color: var(--sn-band-brand); }
.sn-band[data-band="accent"] { background-color: var(--sn-band-accent); }
.sn-band[data-band="invert"] { background-color: var(--sn-canvas); }

/* --------------------------------------------------------------------------
   Reduced motion. 1ms rather than 0s so transitionend/animationend still
   fire and JS that awaits them does not stall.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --sn-dur-1: 1ms;
    --sn-dur-2: 1ms;
    --sn-dur-3: 1ms;
    --sn-dur-4: 1ms;
    --sn-dur-5: 1ms;
    --sn-stagger: 0ms;
    --sn-ease-emphasis: linear;
  }
}

/* ==========================================================================
   Front-page field tokens. Appended after the base blocks so the cascade
   order (light -> system dark -> explicit dark) is preserved.

   Every value here REFERENCES the Layer 1 ramp. An earlier revision declared
   these as raw hexes at the semantic layer, which quietly broke the promise
   that a brand-hue change is confined to one block — the field would have
   stayed ultramarine while everything else moved. scripts/check-no-literals.mjs
   catches exactly that.
   ========================================================================== */
:root {
  /* Warm paper. Faintly warm so the ground reads as chosen, not defaulted. */
  --sn-canvas: var(--c-n-005);

  --sn-hero-field: var(--c-brand-800);  /* the site's own authored brand blue */
  --sn-hero-ink:   var(--c-n-000);      /* 12.27:1 on field */
  --sn-hero-echo:  var(--c-brand-250);  /*  7.21:1 on field */
  --sn-hero-rail:  var(--c-brand-350);  /*  5.76:1 on field */
  --sn-hero-rule:  var(--c-white-a35);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* On a dark page the field drops deeper so it still reads as a field
       rather than as a glowing panel. */
    --sn-hero-field: var(--c-brand-950);  /* 17.18:1 with white ink */
    --sn-hero-ink:   var(--c-n-000);
    --sn-hero-echo:  var(--c-brand-275);  /*  8.58:1 on field */
    --sn-hero-rail:  var(--c-brand-375);  /*  6.99:1 on field */
    --sn-hero-rule:  var(--c-white-a28);
  }
}

:root[data-theme="dark"] {
  --sn-hero-field: var(--c-brand-950);
  --sn-hero-ink:   var(--c-n-000);
  --sn-hero-echo:  var(--c-brand-275);
  --sn-hero-rail:  var(--c-brand-375);
  --sn-hero-rule:  var(--c-white-a28);
}
