/* ---------------------------------------------------------------------------
 * Self-hosted subset webfonts (T16 · D9). Built by scripts/build-fonts.sh,
 * committed under src/assets/fonts/, served from this origin. No Google Fonts
 * CDN and no third-party asset host: that would hand every visitor to this
 * campaign site to a third party, and add a dependency that can disappear.
 *
 * Two families, three scripts. Heebo is a Hebrew companion to Roboto's Latin,
 * so one family carries both Hebrew and Latin and the English edition inherits
 * the same Latin voice as the Hebrew one. Only Arabic needs a second family.
 *
 * The `unicode-range` descriptors are what stop a Hebrew page downloading the
 * Arabic face. THEY MUST STAY DISJOINT, and they must stay inside the ranges
 * scripts/build-fonts.sh actually put in the files. `npm run ship` runs
 * scripts/check-font-coverage.mjs, which proves both — and fails if the built
 * HTML uses a Hebrew, Arabic or Latin character no shipped subset can draw.
 *
 * The invisible joining and bidi controls (U+200C-200F) are claimed by the
 * LATIN face on purpose. They live in all three files, so this is only about
 * which file a page is made to fetch, and Latin is fetched by every page in
 * every locale anyway. Claiming them for Arabic instead would make a Hebrew
 * page carrying one LRM pull 30 KB of Arabic.
 *
 * `swap`, not `block` or `optional`: the fallback stack below is a real stack,
 * so the text is readable from the first paint on a slow connection, which is
 * the baseline this site is judged on (D16). The primary face for the locale is
 * preloaded in the layout, so the swap window is short.
 * ------------------------------------------------------------------------- */

@font-face {
  font-family: "Heebo";
  src: url("/assets/fonts/heebo-latin-400.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+0304, U+0308, U+0329, U+2000-204E, U+2050-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Heebo";
  src: url("/assets/fonts/heebo-latin-700.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+0304, U+0308, U+0329, U+2000-204E, U+2050-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Heebo";
  src: url("/assets/fonts/heebo-hebrew-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0307, U+0590-05FF, U+20AA, U+FB1D-FB4F;
}
@font-face {
  font-family: "Heebo";
  src: url("/assets/fonts/heebo-hebrew-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0307, U+0590-05FF, U+20AA, U+FB1D-FB4F;
}
/* Assistant ExtraBold — the campaign headline face from the designer's package
 * (the operator, 2026-09-20), Hebrew only, one weight, for the hero name alone. The
 * package's other two faces do not ship as fonts: Open Sans Hebrew Bold sets
 * the small print in the artwork and is indistinguishable from Heebo 700 at
 * that size; and the hero's Arabic name is the lockup's own, traced to SVG
 * — 8.5 KB against a 48.6 KB subset of the package's Arabic face
 * (docs/FONTS.md). */
@font-face {
  font-family: "Assistant";
  src: url("/assets/fonts/assistant-hebrew-800.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
  unicode-range: U+0307, U+0590-05FF, U+20AA, U+FB1D-FB4F;
}
@font-face {
  font-family: "Noto Sans Arabic";
  src: url("/assets/fonts/noto-sans-arabic-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
                 U+0898-08E1, U+08E3-08FF, U+204F, U+2E41, U+FE70-FEFC;
}
@font-face {
  font-family: "Noto Sans Arabic";
  src: url("/assets/fonts/noto-sans-arabic-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
                 U+0898-08E1, U+08E3-08FF, U+204F, U+2E41, U+FE70-FEFC;
}
/* Cyrillic for the Russian edition (D50). Heebo carries no Cyrillic at all, so
   without these two faces every Russian page falls to a system font — which is
   what scripts/check-font-coverage.mjs failed the build over. Disjoint from the
   ranges above, so a Hebrew or Arabic page never fetches them. */
@font-face {
  font-family: "Noto Sans";
  src: url("/assets/fonts/noto-sans-cyrillic-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0400-052F, U+2116;
}
@font-face {
  font-family: "Noto Sans";
  src: url("/assets/fonts/noto-sans-cyrillic-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0400-052F, U+2116;
}

/* Design tokens — derived from the supplied logo (src/assets/img/logo-source.jpeg).
 *
 * ACCESSIBILITY NOTE, measured not guessed. The brand teal in the logo is
 * beautiful and it FAILS WCAG AA for body text:
 *
 *   white on #30a8a8  = 2.88:1   fails even large text
 *   white on #18909c  = 3.81:1   large text / UI only
 *   white on #0c849c  = 4.38:1   large text / UI only  (AA body needs 4.5)
 *   white on #0a6b7e  = 6.15:1   passes AA body
 *   white on #075565  = 8.41:1   passes comfortably
 *
 * So the brand gradient is for LARGE GRAPHICS ONLY — hero panels, the logo
 * lockup, decorative bands. Anything carrying text uses --c-teal-ink or darker.
 * IS 5568 / WCAG 2.0 AA is a legal requirement for this site, not a nicety.
 * Do not re-lighten these to "match the logo" without re-measuring.
 */

:root {
  /* Brand gradient, sampled from the logo. Decorative use only. */
  --c-teal-light: #30a8a8;
  --c-teal:       #18909c;
  --c-teal-deep:  #0c849c;
  --c-brand-gradient: linear-gradient(135deg, #0c849c 0%, #30a8a8 100%);
  /* The 2026-09-20 lockup's teal, flat — the wordmark's fill, sampled from
   * logo-lockup-source.png (its two most frequent opaque colours are #2aa2a9
   * and #27a3aa). Decorative only: 2.9:1 under white, and it carries no text.
   * The hero field is this colour so the page opens on the logo's own ground
   * (the operator, 2026-09-20). */
  --c-teal-logo:  #2aa2a9;

  /* Accessible teals. Text, links, buttons, any surface behind white text. */
  --c-teal-ink:    #0a6b7e;  /* 6.15:1 on white */
  --c-teal-inkest: #075565;  /* 8.41:1 on white */

  /* The stripe colours from the mark. Warm accents.
   * amber and orange are DECORATIVE ONLY (2.04:1 and 3.27:1 on white).
   * red-ink is the only warm tone safe for text on white (7.09:1). */
  --c-amber:   #f0a818;
  --c-orange:  #e8681a;
  --c-red:     #d0202a;
  --c-red-ink: #b0141c;
  /* The ribbon's faces (T62, the operator 2026-09-03): the mark's own vertical ramps,
   * measured by T29 off the logo — each a single-axis ramp between two
   * neighbouring values of one hue (DESIGN-DIRECTION §4), light at the top,
   * deep at the bottom. Fields, never behind text. The fold is the mark's dark. */
  --ramp-amber:  linear-gradient(180deg, #f9e337 0%, #f7ab0e 100%);
  --ramp-orange: linear-gradient(180deg, #f49802 0%, #ef6d11 100%);
  --ramp-red:    linear-gradient(180deg, #e30612 0%, #aa101c 100%);
  --ramp-teal:   linear-gradient(180deg, #0a6b7e 0%, #075565 100%);
  --c-fold:      #2b2c2c;
  --c-slate:   #262626;

  /* Neutrals */
  --c-ink:      #141414;
  --c-body:     #333333;
  --c-muted:    #5c5c5c;   /* 6.36:1 on white */
  --c-rule:     #d8dcde;
  --c-surface:  #f4f6f7;
  --c-surface-deep: #e6eaec;  /* the party rows' resting ground (the operator, 2026-09-03) */
  --c-bg:       #ffffff;

  /* Focus ring — TWO tones, and it has to be two (T56, D11, DESIGN-DIRECTION §5.5).
   *
   * No single colour in this palette clears 3:1 against every surface a control
   * can sit on, so a one-colour ring is unfixable rather than badly chosen. The
   * old warm ring `#b0141c` was picked to be "never the teal it may sit on" and
   * measured the opposite: 1.15:1 on --c-teal-ink, 1.62 on --c-teal-deep, and
   * 1.00 on --c-red-ink. It failed on 9 of the 15 surfaces in this file.
   *
   * Two tones fix it because the ring is visible if EITHER band contrasts.
   * Measured worst case across the whole palette: 4.38:1, on --c-teal-deep.
   *   white  wins on the dark fields  (6.15 on teal-ink, 15.13 on slate)
   *   ink    wins on the light fields (18.42 on white, 9.05 on amber)
   *
   * --c-focus is the OUTLINE and --c-focus-halo is a zero-blur box-shadow just
   * inside it. That split is deliberate: box-shadow is not painted in forced-
   * colors mode, so the outline is the half that must survive there, and it does.
   * scripts/check-focus-contrast.mjs re-proves all of this on every build. */
  --c-focus:      var(--c-ink);   /* outer band, the outline */
  --c-focus-halo: var(--c-bg);    /* inner band, the box-shadow */

  /* Type. Heebo and Noto Sans Arabic are self-hosted and subset above (D9).
   * Every stack names all the scripts the page can contain, not just its own:
   * a Hebrew page carries English, an English page will carry Arabic party
   * names, and the root language gate shows all three in one line. The
   * unicode-range descriptors above route each character to the right file.
   *
   * Everything after our two families is a REAL fallback, in order: the local
   * face a reader is most likely to already have, then the platform UI face,
   * then a generic. Roboto sits behind Heebo because Heebo *is* Roboto's Latin
   * with a Hebrew companion, so the substitution barely moves the line. */
  --font-he: "Heebo", "Noto Sans Arabic", "Assistant", "Arial Hebrew",
             system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --font-ar: "Noto Sans Arabic", "Heebo", "Geeza Pro", "Segoe UI",
             system-ui, Tahoma, Arial, sans-serif;
  --font-en: "Heebo", "Noto Sans Arabic", system-ui, -apple-system,
             "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* Russian: Noto Sans first because it is the only family here with Cyrillic;
     Heebo behind it keeps Latin identical to the other three editions. */
  --font-ru: "Noto Sans", "Heebo", system-ui, -apple-system, "Segoe UI",
             Roboto, Helvetica, Arial, sans-serif;

  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.94rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.13rem);
  --step-1:  clamp(1.25rem, 1.15rem + 0.5vw, 1.6rem);
  --step-2:  clamp(1.6rem, 1.4rem + 1vw, 2.4rem);
  --step-3:  clamp(2rem, 1.6rem + 2vw, 3.4rem);
  /* Display size: the hero name and the election date. Poster scale, used in
   * exactly those two places (T62). */
  --step-4:  clamp(2.75rem, 1.9rem + 4.4vw, 5.75rem);

  --measure: 68ch;
  --gutter: clamp(1rem, 0.6rem + 2vw, 2rem);
  --radius: 4px;

  /* Geometry inherited from the mark (DESIGN-DIRECTION §6, measured by T29 off
   * src/assets/img/logo-source.jpeg; first implemented by T31).
   *
   * The bars lean 3.4° from vertical, all three within a quarter of a degree,
   * so the angle is a constant the site inherits and not a style. ONE angle on
   * the whole site, and it NEVER MIRRORS: the logo is a fixed lockup that does
   * not flip for the English edition, and if derived geometry flipped, the
   * page's bars and the logo's bars would lean opposite ways on one screen.
   * This is the one physical value on a logical-property stylesheet. Do not
   * "fix" it with a direction-aware transform.
   *
   * Bar : gap = 1 : 0.6, also measured (32 px bars, 19 px gaps). Every bar in a
   * cluster shares the width, the gap and the angle and differs only in colour.
   * The COUNT of bars is content, never a layout constant — Q3 is open. */
  --lean: 4.1deg;   /* measured off the operator's animation-mockup.png (2026-09-07): 40 px over 560. Was 3.5deg, the mark's own 3.4°, then 4.5deg for his "a tiny bit more" (T62, eleventh round); the drawing says how much more. */
  /* The DEFAULT bar width. A cluster may set its own --bar (the hero sets a
   * poster-scale one, a heading marker an em-scale one); the gap is always
   * computed at the point of use as calc(var(--bar) * 0.6), so overriding --bar
   * on a cluster changes its gap with it. (A --bar-gap token resolved at :root
   * would NOT follow an override — that is why there is no such token.) */
  --bar: clamp(1.5rem, 1rem + 2.2vw, 2.75rem);

  /* Motion (D16 · D22 · DESIGN-DIRECTION §8: "bars arrive, then they stop").
   * One easing curve, one duration and one stagger, reused by everything that
   * arrives, so pages built by different sessions move like one site. A CSS
   * animation reads these directly; a Motion call reads them through
   * getComputedStyle(document.documentElement).getPropertyValue(...). The curve
   * as Motion's `ease` array: [0.2, 0.7, 0.1, 1]. transform and opacity only. */
  --ease-arrive: cubic-bezier(0.2, 0.7, 0.1, 1);
  --dur-arrive: 0.7s;
  --stagger-arrive: 0.09s;
  /* How far a bar travels as it arrives, along its own axis. Shared by the
   * hero's @keyframes and by reveal.js, so the two beats are one beat. */
  --travel-arrive: 28%;
}

/* Per-locale font binding. The template sets lang/dir; CSS does the rest,
 * so no template ever branches on language. */
:root:lang(he), [lang="he"] { --font-ui: var(--font-he); }
:root:lang(ar), [lang="ar"] { --font-ui: var(--font-ar); }
:root:lang(en), [lang="en"] { --font-ui: var(--font-en); }
:root:lang(ru), [lang="ru"] { --font-ui: var(--font-ru); }

/* ...and this line is what makes the three above do anything below the root.
 * `font-family` is declared once, on `body`. A descendant that redefines
 * --font-ui — the `<a lang="ar">` in the language gate, an English phrase
 * inside a Hebrew page — changes the custom property but inherits body's
 * already-computed font-family, so nothing switches. Re-declaring it wherever
 * `lang` is set fixes that. `:where()` keeps the specificity at zero so it
 * never outranks a component rule.
 *
 * With the subsets above this rarely changes which FILE is used — unicode-range
 * already routes per character — but it does decide the FALLBACK order if the
 * fonts fail to load, which is when getting it right matters most. */
:where([lang]) { font-family: var(--font-ui); }

@media (prefers-contrast: more) {
  :root { --c-body: #1a1a1a; --c-muted: #3d3d3d; --c-rule: #767676; }
}
