/* Generated by scripts/fetch_fonts.py -- do not edit.
   Self-hosted so the first paint waits on no third-party origin.
   font-display:swap: text is readable in a fallback face immediately
   and reflows once, rather than being invisible while the font loads. */
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-400-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-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:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-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:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-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:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/rubik-500-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/rubik-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;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/rubik-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/rubik-700-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/rubik-700-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:'Rubik';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/rubik-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/rubik-900-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Rubik';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/rubik-900-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:'Rubik';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/rubik-900-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DESIGN TOKENS — the only file in this project that contains a raw value.

   Everything downstream (site.css, every template) composes from these. If a
   component declares `#F5F3EE` or `1.375rem` or `0 2px 6px rgba(...)`, that is
   a bug: the value has escaped the system and the next person to change the
   palette will miss it. site.css is checked for this — see `make design-lint`.

   Three layers, and the direction of dependency is one-way:

     1. PRIMITIVES   raw ramps. Never referenced by a component.
     2. SEMANTIC     what a thing is FOR. This is the only layer components use.
     3. CONTEXT      tokens re-bound per subtree (.b-busy sets --band).

   The reason for the middle layer: "the card background" and "the colour
   #FFFFFF" are different facts. When the palette moves, one changes and the
   other does not. Components that reference `--surface-raised` survive a
   re-theme; components that reference `--paper-0` do not.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ─── 1. PRIMITIVES ──────────────────────────────────────────────────────
     Ramps, numbered light → dark. No component may use these directly. */

  /* Warm neutral ground. This site is read in daylight by someone holding a
     suitcase; the warmth is the brand and the contrast is the accessibility. */
  --paper-0: #FFFFFF;
  --paper-1: #FBFCFE;
  --paper-2: #F6F8FC;
  --paper-3: #EDF1F8;
  --paper-4: #E3E9F4;

  --ink-0: #0B1533;      /* near-black, not a soft grey */
  --ink-1: #222E4D;
  --ink-2: #3F4A66;
  --ink-3: #5A6484;      /* 5.1:1 on --paper-2 */
  --ink-4: #8A93AB;      /* decorative only — never body text */

  /* Borders carry more weight on this palette than they did on the last one.
     A white card on the old warm page separated at 1.109:1; on this cooler
     ground it is 1.063, so the border IS the card edge rather than an accent on
     one. --border-subtle (= --line-1) is referenced 18 times in site.css --
     every card, the header rule, the subnav, each h2 underline. These three are
     tuned to the OLD design's visibility, and they are three distinct steps:
     1.09 / 1.26 / 1.47 against the page. Keep the gaps; collapsing 0 into 1
     turns a three-step ramp into a two-step one. */
  --line-0: #EBEEF4;     /* hairline, barely there  — 1.09:1 */
  --line-1: #D8DFEC;
  --line-2: #C8CFDC;

  /* Structure. Navy carries the interface; it is never a status. */
  --navy-0: #0B1533;
  --navy-1: #222E4D;
  --navy-tint: #E7ECF7;

  /* ─── the mark ───────────────────────────────────────────────────────────
     Identity ONLY — never a status, never a band, never a data colour.
     Any hue the signal ramp uses will read as a reading when it appears in the
     logo. This project learned that once already: the accent was #FF6B35 while
     the "busy" band was #EE6C1E, and the mark looked like a live status.
     Sky sits outside the current ramp (cyan against a magenta/violet top end),
     which is the property to preserve if either ever moves. */
  --sky-0: #38BDF8;
  --sky-1: #7FB3D9;

  /* ─── action ─────────────────────────────────────────────────────────────
     Reserved for things you can click that we want you to click.

     Named for the hue it IS. These were --flame-* through two palettes and
     stayed --flame-* when the value became an indigo, which is how a token
     starts lying: a reader reaches for --flame-0 expecting orange and ships a
     blue. Primitives carry hue names precisely so that mismatch is visible.

     Three values because one cannot do all three jobs — a hue dark enough to
     carry white text is too dark to be a bright mark, and a hue bright enough
     to be a mark fails behind white. The CTA once shipped at 3.55:1 by using
     one value for both. */
  --indigo-0: #436ADC;      /* 4.6:1 on --paper-2, 4.9:1 behind white — both roles */
  --indigo-hover: #3659B5;  /* 6.1:1 on --paper-2 */
  --indigo-1: #5A8FFF;      /* decorative ONLY — 3.1:1, never behind text. */
  --indigo-tint: #E9EEFD;

  /* ─── the signal ramp ────────────────────────────────────────────────────
     This is a SEQUENTIAL scale, not five equally-loud colours.

     The first version made every band a ~34% tint of its hue. That was wrong
     twice over. It looked washed out, because the heat grid is 168 cells and
     therefore the dominant colour surface on the site. And it failed AA on all
     five bands — the cell text measured 2.6:1 to 4.0:1 against its own fill.

     So visual weight now rises with the value, which is also what the data
     wants: "quiet" is not news and should not shout, "peak" is and should.
     Calm bands are tints with dark text; the two alarming bands are solid with
     white text. Every pair is >= 4.5:1. Re-run scripts/contrast_check.py if
     any of these move. */

  /* the base hue — bars, pips, gauge fills, the band word */
  --sig-quiet: #309E51;
  --sig-light: #A38A00;
  --sig-moderate: #CE7800;
  --sig-busy: #D93B15;
  --sig-peak: #9B1414;

  /* The heat-cell pair: background, and the text that sits on it.
     Ratios measured, not estimated — scripts/contrast_check.py re-checks every
     one of these on `make check`. The calm bands are tints (the hue blended
     toward white) rather than scaled channels: scaling clips to neon, which is
     bright but reads cheap.

     Green -> yellow -> orange -> orange-red -> red: the reading people
     already know, so the grid needs no legend to be understood.

     Note the lightness falls monotonically quiet -> peak. That is what keeps
     the ramp readable for a colourblind reader and in greyscale — hue is the
     reinforcement, never the only cue. Any future edit must preserve it. */
  --fill-quiet: #BFE2CA;     --on-quiet: #1A1A1A;     /* 12.4:1  L .70 */
  --fill-light: #E7C822;     --on-light: #1A1A1A;     /* 10.5:1  L .58 */
  --fill-moderate: #F08D02;  --on-moderate: #1A1A1A;  /*  7.1:1  L .38 */
  --fill-busy: #D43A14;      --on-busy: #FFFFFF;      /*  4.8:1  L .17 */
  --fill-peak: #981414;      --on-peak: #FFFFFF;      /*  8.6:1  L .07 */

  /* ─── type ───────────────────────────────────────────────────────────────
     Rubik and Assistant are both genuine Hebrew faces, drawn in Hebrew rather
     than extended into it. That is not a stylistic preference — it is why the
     Hebrew build looks designed rather than transliterated, and it rules out
     every Latin-only "display font" for this slot, permanently.

     The display face was Frank Ruhl Libre, a traditional high-contrast book
     serif, and it was the wrong tool: this slot sets `.status .word`, `.kpi .v`
     and `.result .time` — the index number and the band word, at step-6 and
     weight 900. Hebrew has no capitals and no descenders, so a heavy serif set
     large collapses into a dense block of ink, and the thin joins that make the
     face elegant at book sizes disappear on screen. A meter reads as an
     instrument, not a masthead. Rubik is a geometric sans with lining figures,
     which is what a number this size actually needs. */
  --font-display: "Rubik", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-text: "Assistant", ui-sans-serif, system-ui, -apple-system, sans-serif;
  /* ─── Hebrew optical corrections ─────────────────────────────────────────
     Hebrew has no capitals and no ascenders: its glyphs sit in a single band
     roughly the height of Latin's x-height, so at an identical font-size it
     reads visually smaller. These restore the balance rather than making
     Hebrew "bigger", and they live here because site.css may hold no raw
     value — `make design-lint` enforces that, and caught this. */
  --script-he-scale: 1.12em;
  --leading-he-h1: 1.18;
  --leading-he-h2: 1.35;
  /* Hebrew display runs one weight DOWN from Latin. Rubik 900 chokes the
     Hebrew counters — at the size .status .word uses, the samekh and the final
     mem close up into blobs — while Hebrew's naturally heavier stroke means 700
     already carries the same visual weight as Latin 900 beside it. Measured on
     rendered specimens, not assumed. */
  --weight-he-display: 700;

  --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

  /* Fluid scale, ratio ~1.125 at the small end opening to ~1.2 at the top.
     Every size on the site is one of these. The old stylesheet had .88, .9,
     .92, .93 and .95rem all in use — six sizes doing one job, which is what
     "unsystematic" looks like when you measure it. */
  --step--2: clamp(0.72rem, 0.70rem + 0.10vw, 0.78rem);
  --step--1: clamp(0.83rem, 0.81rem + 0.11vw, 0.90rem);
  --step-0:  clamp(0.97rem, 0.95rem + 0.12vw, 1.05rem);
  --step-1:  clamp(1.09rem, 1.05rem + 0.18vw, 1.20rem);
  --step-2:  clamp(1.22rem, 1.16rem + 0.28vw, 1.40rem);
  --step-3:  clamp(1.37rem, 1.28rem + 0.44vw, 1.65rem);
  --step-4:  clamp(1.54rem, 1.40rem + 0.68vw, 1.95rem);
  --step-5:  clamp(1.73rem, 1.52rem + 1.02vw, 2.35rem);
  --step-6:  clamp(1.95rem, 1.63rem + 1.55vw, 2.90rem);
  --step-7:  clamp(2.60rem, 1.95rem + 3.10vw, 4.40rem);   /* the band word only */

  --leading-tight: 1.08;
  --leading-snug: 1.28;
  --leading-normal: 1.6;
  --leading-loose: 1.72;

  --tracking-tight: -0.022em;
  --tracking-normal: 0;
  --tracking-wide: 0.07em;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semi: 600;
  --weight-bold: 700;
  --weight-black: 900;

  /* ─── space ──────────────────────────────────────────────────────────────
     4px base. Nothing between steps: if a gap needs 14px, the layout is wrong,
     not the scale. */
  --s-0: 0;
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 2.75rem;
  --s-8: 4rem;

  /* The sticky header's height, used to keep an anchor jump from landing
     underneath it. Measured: 66px on a wide viewport, 104px once the header
     wraps on a phone -- so it is two values, not one. */
  /* The loading shimmer. Built from the existing hairline ramp rather than a
     new grey, so a skeleton reads as "this surface is not ready yet" and not as
     a colour the design does not otherwise use. */
  --skeleton: linear-gradient(90deg,
              var(--line-0) 25%, var(--line-1) 37%, var(--line-0) 63%);

  --h-header: 4.5rem;
  --h-header-narrow: 7rem;
  --s-9: 6rem;
  --s-10: 8rem;

  /* ─── shape, depth, motion ───────────────────────────────────────────── */
  --r-1: 6px;
  --r-2: 10px;
  --r-3: 14px;
  --r-4: 20px;
  --r-full: 999px;

  /* Depth is rationed. Most grouping here is done with a hairline and space;
     a shadow means "this floats above the page", which is true of exactly two
     things (the search results and the language modal). */
  --shadow-0: none;
  --shadow-1: 0 1px 2px rgba(17, 21, 28, 0.045);
  --shadow-2: 0 1px 2px rgba(17, 21, 28, 0.05), 0 10px 24px -8px rgba(17, 21, 28, 0.09);
  --shadow-3: 0 2px 8px rgba(17, 21, 28, 0.07), 0 28px 56px -14px rgba(17, 21, 28, 0.16);

  --dur-1: 120ms;
  --dur-2: 200ms;
  --dur-3: 420ms;
  --ease: cubic-bezier(0.2, 0.8, 0.25, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* ─── measure ────────────────────────────────────────────────────────────
     THE fix for the biggest layout problem this design had: one 46rem column
     for everything, so a 24-column data grid and a paragraph of prose were
     given identical space, and a 1440px screen ran at 51% utilisation.

     Prose wants a measure. Data wants room. They are different tokens. */
  --w-prose: 34rem;      /* ~66 characters at --step-0 */
  --w-content: 60rem;    /* default: an answer plus its supporting evidence */
  --w-wide: 78rem;       /* tables, grids, boards, leaderboards */
  --gutter: clamp(1rem, 0.4rem + 2.4vw, 2.5rem);


  /* ─── 2. SEMANTIC ────────────────────────────────────────────────────────
     What components actually reference. Read these as sentences: "the surface
     of a raised thing", "the colour of secondary text". */

  --surface-page: var(--paper-2);
  --surface-sunken: var(--paper-3);
  --surface-card: var(--paper-0);
  --surface-inset: var(--paper-1);
  --surface-invert: var(--navy-0);
  --surface-accent: var(--indigo-tint);
  --surface-brand: var(--navy-tint);

  --text-primary: var(--ink-0);
  --text-secondary: var(--ink-2);
  --text-tertiary: var(--ink-3);
  --text-quiet: var(--ink-4);
  --text-invert: var(--paper-0);
  --text-brand: var(--navy-0);
  --text-action: var(--indigo-0);

  --border-hairline: var(--line-0);
  --border-subtle: var(--line-1);
  --border-strong: var(--line-2);
  --border-focus: var(--navy-0);

  /* ─── on dark ────────────────────────────────────────────────────────────
     The footer and the modal scrim invert the ground. These are the only
     places white-on-navy appears, and the tints are checked for AA there:
     --on-invert-action is LIGHTER than --indigo-1 because the action
     orange does not clear 4.5:1 on --navy-0. */
  --on-invert-strong: rgba(255, 255, 255, 0.92);
  --on-invert: rgba(255, 255, 255, 0.72);
  --on-invert-muted: rgba(255, 255, 255, 0.5);
  --on-invert-line: rgba(255, 255, 255, 0.14);
  --on-invert-action: #9FB6FF;

  --scrim: rgba(17, 21, 28, 0.42);
  --ring-hairline: rgba(17, 21, 28, 0.12);

  /* The select chevron. A data uri cannot read currentColor, so the one place
     a colour would otherwise be duplicated into markup lives here instead —
     keep it in sync with --ink-3 by hand if that ramp moves. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23626C7A' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");

  /* Paper grain. One texture, one opacity, declared once. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-opacity: 0.035;

  --focus-ring: 0 0 0 3px rgba(21, 42, 71, 0.16);

  /* ─── 3. CONTEXT ─────────────────────────────────────────────────────────
     --band is deliberately UNBOUND here. It is set per subtree by a .b-* class
     below, or inline by the live-update script, and every component that shows
     a busyness colour reads it rather than knowing which band it is. That is
     what lets one component render five states, and what lets the API change
     the state at runtime without re-rendering markup. */
  --band: var(--ink-3);
}

/* The band classes. Setting a custom property rather than a colour is what
   makes this one declaration instead of one per property per band. */
.b-quiet    { --band: var(--sig-quiet);    --band-fill: var(--fill-quiet);    --band-on-fill: var(--on-quiet); }
.b-light    { --band: var(--sig-light);    --band-fill: var(--fill-light);    --band-on-fill: var(--on-light); }
.b-moderate { --band: var(--sig-moderate); --band-fill: var(--fill-moderate); --band-on-fill: var(--on-moderate); }
.b-busy     { --band: var(--sig-busy);     --band-fill: var(--fill-busy);     --band-on-fill: var(--on-busy); }
.b-peak     { --band: var(--sig-peak);     --band-fill: var(--fill-peak);     --band-on-fill: var(--on-peak); }
.b-brand    { --band: var(--navy-0);       --band-fill: var(--navy-tint);     --band-on-fill: var(--navy-0); }

/* Delays reuse this same channel rather than getting their own ramp: on the
   punctuality pages the colour means "how late" instead of "how full", but
   pipeline/stats.py maps delay minutes onto these five band NAMES for exactly
   that reason — a reader should not have to learn a second colour scale. */

/* ─── the derived band values ───────────────────────────────────────────────
   These MUST be declared on the same element that sets --band, not on :root.

   A custom property is substituted at computed-value time on the element where
   it is DECLARED. Declaring `--band-fill: color-mix(..., var(--band), ...)` on
   :root therefore resolves it once, against :root's own --band, and every
   descendant inherits that one already-computed colour. The symptom is
   unmistakable and was exactly what shipped: a 168-cell heat grid rendered
   entirely in grey, while the legend beside it — which reads var(--band)
   directly rather than a derived token — showed all five colours correctly.

   [style*="--band"] catches the elements the live script paints at runtime. */
:root,
.b-quiet, .b-light, .b-moderate, .b-busy, .b-peak, .b-brand,
.board.good, .board.bad,
[style*="--band"] {
  /* a badge, a readout panel, a chip -- still a formula, still light */
  --band-tint: color-mix(in srgb, var(--band) 18%, var(--surface-card));
  --band-edge: color-mix(in srgb, var(--band) 34%, var(--border-subtle));
  /* label text ON PAPER (not on a fill), darkened until it clears AA at
     small sizes -- the raw signal hues only reach ~3.5:1 on warm paper */
  --band-text: color-mix(in srgb, var(--band) 78%, var(--ink-0));
}

/* The heat-cell pair falls back to a formula ONLY for a subtree that carries a
   --band without a named band class (the .board.good / .board.bad panels, and
   anything the live script paints inline).
   The named bands MUST NOT be in this selector list: they declare explicit
   fill/text pairs above, and this rule sits later in the file at identical
   specificity, so listing them here silently overrode all five back to a 20%
   tint. That is precisely the washed-out grid this ramp was written to fix. */
:root,
.board.good, .board.bad,
[style*="--band"] {
  --band-fill: color-mix(in srgb, var(--band) 20%, var(--surface-card));
  --band-on-fill: var(--band-text);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: 0ms; --dur-2: 0ms; --dur-3: 0ms; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTS.

   Every value here comes from tokens.css. There should be no hex colour, no
   raw shadow and no font size in this file — if you need one that does not
   exist, add it to the scale rather than writing it inline, or the next
   re-theme will miss it. `make design-lint` checks.

   The design: an instrument printed on paper. Not a dashboard, which is what
   every competitor in this niche looks like, and not an article, which is what
   this looked like before. The page is quiet, the ground is warm, structure is
   drawn with hairlines rather than boxes, and the only saturated colour on
   screen is the one carrying the answer.

   Logical properties throughout, so the Hebrew RTL build is correct by
   construction rather than by patching.
   ═══════════════════════════════════════════════════════════════════════════ */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-primary);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* One grain layer over the whole page. This is what makes "warm paper" read as
   a deliberate material rather than as an off-white background: at 3.5% it is
   invisible as texture and legible as intent. Fixed, inert, no repaint cost. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: var(--grain);
}
body > * { position: relative; z-index: 1; }

::selection { background: var(--band-tint); color: var(--text-primary); }

:where(a, button, select, input, [tabindex]):focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: var(--r-1);
}


/* ── layout ────────────────────────────────────────────────────────────────
   The fix for this design's biggest structural problem: it had ONE 46rem
   column, so a 24×7 data grid and a paragraph of prose were given identical
   room and a 1440px screen ran at half utilisation.

   Three widths now, and a block opts into the one it needs:
     .shell     the default measure — an answer and its supporting evidence
     .bleed     breaks out to --w-wide, for grids, boards and tables
     .measure   pulls in to --w-prose, for anything read as sentences
   ──────────────────────────────────────────────────────────────────────── */
.shell {
  inline-size: min(var(--w-content), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block-end: var(--s-9);
}

.bleed {
  inline-size: min(var(--w-wide), 100vw - var(--gutter) * 2);
  margin-inline: calc(50% - min(var(--w-wide), 100vw - var(--gutter) * 2) / 2);
}

.measure { max-inline-size: var(--w-prose); }


/* ── typography ────────────────────────────────────────────────────────── */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
  margin: 0;
}

h1 {
  font-size: var(--step-5);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  margin-block-end: var(--s-2);
}

/* Section headings sit ON a hairline rather than floating above their content.
   The rule is what groups the section; without it every h2 needed a large
   margin to read as a boundary, which is where the endless scroll came from. */
h2 {
  font-size: var(--step-2);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  margin-block: var(--s-7) var(--s-4);
  padding-block-end: var(--s-3);
  border-block-end: 1px solid var(--border-subtle);
}

h3 {
  font-size: var(--step-1);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  margin-block-end: var(--s-2);
}

p { margin-block: 0 var(--s-4); max-inline-size: var(--w-prose); }
p:last-child { margin-block-end: 0; }

a { color: var(--text-brand); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--text-action); }

.lede {
  font-size: var(--step-1);
  line-height: var(--leading-snug);
  color: var(--text-secondary);
  max-inline-size: var(--w-prose);
  margin-block-end: var(--s-5);
}

ul.plain { list-style: none; padding: 0; margin: 0 0 var(--s-4); }
ul.plain li {
  padding-block: var(--s-3);
  border-block-end: 1px solid var(--border-hairline);
  color: var(--text-secondary);
  max-inline-size: var(--w-prose);
}
ul.plain li:last-child { border-block-end: 0; }


/* Every in-page anchor -- the section nav, the footer links, and now the ids on
   each chart -- scrolls its target to the very top of the viewport, which is
   exactly where the sticky header is. The heading landed underneath it and the
   reader arrived at what looked like the middle of a section. scroll-padding
   belongs on the scroll container, so it goes here rather than as a
   scroll-margin repeated on every target. */
html {
  scroll-padding-block-start: calc(var(--h-header) + var(--s-3));
}
@media (max-width: 34rem) {
  html { scroll-padding-block-start: calc(var(--h-header-narrow) + var(--s-3)); }
}

/* ── the answer card, while it is still an unknown ──────────────────────────
   The build stamps a reading into the HTML and the live payload replaces it
   about half a second later. Measured on /en/tlv/: the page rendered 82 "Busy"
   and settled on 48 "Moderate" -- two bands out, in the wrong colour, stated as
   fact. Whatever the build knew, it did not know THIS minute, and the card's
   whole claim is "right now".

   So the markup keeps its number -- a crawler, and anyone without javascript,
   still gets a complete answer, and a failed fetch falls back to it -- and the
   script covers it the instant it starts asking for a fresher one.

   `color: transparent` rather than emptying the element: the text stays in
   flow, so the skeleton is exactly the size of the answer that replaces it and
   nothing moves when it does. */
.answer.is-loading { --band: var(--line-2); }
.answer.is-loading .word,
.answer.is-loading .advice,
.answer.is-loading .gauge-label,
.answer.is-loading .note {
  color: transparent;
  background: var(--skeleton);
  background-size: 200% 100%;
  border-radius: var(--r-1);
  animation: skeleton 1.4s ease-in-out infinite;
}
/* The bar would otherwise animate from a wrong width to the right one, which
   draws the eye to precisely the number we are saying we do not have yet. */
.answer.is-loading .gauge-fill { opacity: 0; }
.answer.is-loading .pip { opacity: .5; }

/* The terminal cards are the same claim at terminal granularity, refreshed from
   the same payload, so they wait with it rather than sitting there confidently
   showing the build's numbers while the card above them is admitting it does
   not know yet. */
.tcard.is-loading { --band: var(--line-2); }
.tcard.is-loading .name,
.tcard.is-loading .row {
  color: transparent;
  background: var(--skeleton);
  background-size: 200% 100%;
  border-radius: var(--r-1);
  animation: skeleton 1.4s ease-in-out infinite;
}
.tcard.is-loading .pip { opacity: 0; }
.tcard.is-loading .bar span { opacity: 0; }

/* The charts wait with the card above them, for the same reason: what the build
   drew is what the build knew, and the payload repaints every cell a moment
   later. One shimmer on the WRAPPER rather than 168 of them on the cells --
   independently animated cells read as static, and 168 running animations is
   real work on a phone. The cells keep their boxes so nothing moves when the
   colours arrive. */
.gridwrap.is-loading .cell,
.hours.is-loading i {
  color: transparent;
  --band: var(--line-1);
  --band-fill: var(--line-0);
  --band-on-fill: transparent;
}
.gridwrap.is-loading table.grid,
.hours.is-loading {
  position: relative;
  overflow: hidden;
}
.gridwrap.is-loading table.grid::after,
.hours.is-loading::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--skeleton);
  background-size: 200% 100%;
  animation: skeleton 1.4s ease-in-out infinite;
  opacity: .55;
  pointer-events: none;
}
.gridwrap.is-loading .cell.is-now { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .tcard.is-loading .name,
  .tcard.is-loading .row { animation: none; }
  .gridwrap.is-loading table.grid::after,
  .hours.is-loading::after { animation: none; }
}

@keyframes skeleton {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .answer.is-loading .word,
  .answer.is-loading .advice,
  .answer.is-loading .gauge-label,
  .answer.is-loading .note { animation: none; }
}

/* ── header ────────────────────────────────────────────────────────────────
   Sticky, hairline, translucent. It is chrome on a page whose whole job is one
   number, so it stays out of the way and never grows. */
.top {
  position: sticky;
  inset-block-start: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding-block: var(--s-3);
  margin-block-end: var(--s-5);
  border-block-end: 1px solid var(--border-subtle);
  background: color-mix(in srgb, var(--surface-page) 86%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
}

.mark { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--text-primary); text-decoration: none; flex: none; }
.mark svg { flex: none; display: block; }
.wordmark {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--step-1);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}


/* ── search ────────────────────────────────────────────────────────────── */
.search { position: relative; flex: 1 1 14rem; min-inline-size: 11rem; }
.search input {
  inline-size: 100%;
  background: var(--surface-card);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-4);
  font: inherit;
  font-size: var(--step--1);
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.search input::placeholder { color: var(--text-quiet); }
.search input:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring); }
.results {
  position: absolute;
  inset-block-start: calc(100% + var(--s-2));
  inset-inline: 0;
  z-index: 50;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  overflow: hidden;
  box-shadow: var(--shadow-3);
}
.results[hidden] { display: none; }
.results a {
  display: flex; align-items: baseline; gap: var(--s-2);
  padding: var(--s-3);
  text-decoration: none; color: var(--text-primary);
  border-block-end: 1px solid var(--border-hairline);
  font-size: var(--step--1);
}
.results a:last-child { border-block-end: none; }
.results a:hover, .results a:focus, .results a[aria-selected="true"] { background: var(--surface-inset); outline: none; }
.results .code { font-weight: var(--weight-bold); color: var(--text-action); flex: none; min-inline-size: 3.2ch; font-size: var(--step--2); }
.results .where {
  color: var(--text-tertiary); font-size: var(--step--2);
  margin-inline-start: auto; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-inline-size: 9rem;
}
.results .empty { padding: var(--s-3); color: var(--text-tertiary); font-size: var(--step--1); }


/* ── language switch ───────────────────────────────────────────────────── */
.langbtn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  flex: none; margin-inline-start: auto;
  font: inherit; font-size: var(--step--1);
  color: var(--text-secondary); cursor: pointer;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-3);
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.langbtn:hover { border-color: var(--border-focus); color: var(--text-brand); }

/* The header only fits on one row while there is room for three items. On a
   390px phone the mark (147px), the search field at its 11rem minimum (176px)
   and the language button (102px) need 450px against 358px of shell, so the
   language button wrapped -- and because it sets margin-inline-start:auto it
   landed alone against the right edge of a second row. That reads as a layout
   accident, and it cost a whole row of vertical space above the fold to say one
   word.

   So below 34rem the two rows are deliberate rather than emergent: identity and
   language together on the first, search spanning the second. `order` does the
   arranging so the DOM keeps its reading order for a screen reader -- the mark
   is still the first thing announced. */
@media (max-width: 34rem) {
  .top {
    gap: var(--s-2) var(--s-3);
    padding-block: var(--s-2);
    margin-block-end: var(--s-4);
  }
  .langbtn { order: 2; }
  .search  { order: 3; flex: 1 0 100%; min-inline-size: 0; }
}

/* A language is not a country, so the flag is decoration beside the name and
   never the label itself. */
.flag { flex: none; display: block; object-fit: cover; border-radius: 2px; box-shadow: 0 0 0 1px var(--ring-hairline); }
.langbtn .flag { inline-size: 20px; block-size: 14px; }
.langlist .flag { inline-size: 26px; block-size: 18px; }
.footer-col .flag {
  inline-size: 18px; block-size: 13px;
  display: inline-block; vertical-align: -2px;
  margin-inline-end: var(--s-2);
  box-shadow: 0 0 0 1px var(--on-invert-line);
}

/* Pinned to the VIEWPORT, not the document. A <dialog> defaults to
   position:absolute, so opening it from halfway down the page put the box at
   document coordinates the reader could not see -- and the browser, moving
   focus into it, scrolled the whole page to reach it. From 679px down, opening
   the picker jumped you to the top of the airport page. inset:0 + margin:auto
   is the centring the modal was relying on the UA to do for it. */
.langmodal[open], .langmodal:modal {
  position: fixed; inset: 0; margin: auto;
}
.langmodal {
  border: 0; border-radius: var(--r-3); padding: 0;
  inline-size: min(24rem, calc(100% - var(--s-6)));
  background: var(--surface-card); color: var(--text-primary);
  box-shadow: var(--shadow-3);
}
.langmodal::backdrop { background: var(--scrim); backdrop-filter: blur(3px); }
.langmodal-head {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4) var(--s-5) var(--s-3);
  border-block-end: 1px solid var(--border-subtle);
}
.langmodal-head h2 { margin: 0; padding: 0; border: 0; font-size: var(--step-1); font-weight: var(--weight-semi); }
.langmodal-head button {
  margin-inline-start: auto; border: 0; background: transparent; cursor: pointer;
  font-size: var(--step-3); line-height: 1; color: var(--text-tertiary); padding: 0 var(--s-1);
}
.langmodal-head button:hover { color: var(--text-primary); }
.langlist { padding: var(--s-2); }
.langlist a {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3); border-radius: var(--r-2);
  text-decoration: none; color: var(--text-primary);
  transition: background-color var(--dur-1) var(--ease);
}
.langlist a:hover, .langlist a:focus { background: var(--surface-inset); outline: none; }
.langlist .endonym { color: var(--text-tertiary); font-size: var(--step--1); }
.langlist .tick { margin-inline-start: auto; color: var(--text-brand); font-weight: var(--weight-bold); }


/* ── breadcrumbs + section nav ─────────────────────────────────────────── */
.crumbs { margin-block-end: var(--s-4); font-size: var(--step--1); color: var(--text-tertiary); }
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-2); }
.crumbs li { display: flex; align-items: center; gap: var(--s-2); min-inline-size: 0; }
.crumbs li + li::before { content: "/"; color: var(--border-strong); flex: none; }
.crumbs a { color: var(--text-tertiary); text-decoration: none; }
.crumbs a:hover { color: var(--text-primary); text-decoration: underline; }
.crumbs [aria-current] { color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The section nav is the page's spine, so it reads as an underlined tab strip
   rather than a row of buttons: it belongs to the airport, not to the site. */
.subnav {
  display: flex; gap: var(--s-1); flex-wrap: nowrap;
  margin-block: var(--s-5) var(--s-6);
  overflow-x: auto; scrollbar-width: none;
  border-block-end: 1px solid var(--border-subtle);
}
.subnav::-webkit-scrollbar { display: none; }
.subnav a {
  white-space: nowrap; text-decoration: none;
  font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-tertiary);
  padding: var(--s-2) var(--s-3) var(--s-3);
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.subnav a:hover { color: var(--text-primary); }
.subnav a[aria-current] { color: var(--text-primary); font-weight: var(--weight-semi); border-block-end-color: var(--text-primary); }


/* ── the answer ────────────────────────────────────────────────────────────
   The instrument. Everything else on the page is supporting evidence.

   Horizontal from 44rem up, so the band word, the advice and the number all
   sit above the fold on a laptop. It used to be a ~340px-tall white box
   holding one word. */
.answer {
  display: grid;
  gap: var(--s-4) var(--s-6);
  align-items: center;
  padding: var(--s-5) 0 var(--s-6);
  border-block: 1px solid var(--border-subtle);
  margin-block-end: var(--s-2);
}
@media (min-width: 44rem) {
  .answer {
    grid-template-columns: minmax(min-content, max-content) minmax(0, 1fr);
    column-gap: var(--s-7);
    padding-block: var(--s-6);
  }
}
.answer-body { min-inline-size: 0; }
/* The provenance chips are hidden until the live script has something to say.
   Without this the row still reserved its height, leaving a band of empty
   paper under the gauge on every page where the data was fresh. */
.answer .provenance:not(:has(> :not([hidden]))) { display: none; }

.status { display: flex; align-items: center; gap: var(--s-3); min-inline-size: 0; }
.status .pip {
  inline-size: 0.55em; block-size: 0.55em; border-radius: 50%;
  background: var(--band); flex: none;
  box-shadow: 0 0 0 0.26em color-mix(in srgb, var(--band) 18%, transparent);
}
.status .word {
  font-family: var(--font-display);
  font-size: var(--step-6);
  font-weight: var(--weight-black);
  line-height: 0.92;
  white-space: nowrap;
  letter-spacing: var(--tracking-tight);
  color: var(--band);
}

.answer .advice { font-size: var(--step-2); line-height: var(--leading-snug); color: var(--text-primary); margin: 0; text-wrap: pretty; max-inline-size: none; }
.answer .note { font-size: var(--step--1); color: var(--text-tertiary); margin: var(--s-2) 0 0; }

.gauge { display: flex; align-items: center; gap: var(--s-3); margin-block-start: var(--s-3); flex-wrap: wrap; }
.gauge-track { flex: 0 1 17rem; block-size: 8px; background: var(--surface-sunken); border-radius: var(--r-full); overflow: hidden; }
.gauge-fill {
  block-size: 100%; inline-size: var(--pct, 0%);
  background: var(--band); border-radius: var(--r-full);
  transition: inline-size var(--dur-3) var(--ease-out);
}
.gauge-label { font-size: var(--step--1); color: var(--text-tertiary); font-variant-numeric: tabular-nums; flex: none; }


/* ── city + code ───────────────────────────────────────────────────────── */
.place {
  display: flex; align-items: center; gap: var(--s-2) var(--s-3); flex-wrap: wrap;
  margin: 0 0 var(--s-5);
  color: var(--text-tertiary); font-size: var(--step--1);
}
.place .sep { color: var(--border-strong); }
.place .iata {
  font-weight: var(--weight-bold); font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  color: var(--text-brand); background: var(--surface-brand);
  padding: 2px var(--s-2); border-radius: var(--r-1);
}


/* ── cards ─────────────────────────────────────────────────────────────────
   One card component for terminals, airports and weekdays. Hairline plus a
   band edge rather than a shadow: at eight per screen, shadows turn a page
   into rubble. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 17rem)); gap: var(--s-3); margin-block-end: var(--s-4); }
/* On a phone the capped track leaves a ragged edge; one card per row is both
   tidier and a bigger tap target. */
@media (max-width: 30rem) { .cards { grid-template-columns: 1fr; } }
.tcard {
  display: block; text-decoration: none; color: var(--text-primary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  /* The home page's cards carry no band -- they are a directory of the
     airports we cover, not a live reading. An undefined var() would make
     this declaration invalid and the edge would fall back to currentColor,
     i.e. a 3px near-black stripe. The fallback keeps it a hairline. */
  border-inline-start: 3px solid var(--band, var(--border-subtle));
  border-radius: var(--r-2);
  padding: var(--s-4);
  transition: border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
a.tcard:hover { border-color: var(--band-edge); border-inline-start-color: var(--band); transform: translateY(-1px); }
.tcard .name { font-weight: var(--weight-semi); font-size: var(--step-0); }
.tcard .city { color: var(--text-tertiary); font-size: var(--step--2); margin-block-start: 2px; }
.tcard .row { display: flex; align-items: center; gap: var(--s-2); color: var(--band-text); font-size: var(--step--1); font-weight: var(--weight-medium); margin-block-start: var(--s-2); }
.tcard .pip { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--band); flex: none; }
.tcard .bar { block-size: 4px; background: var(--surface-sunken); border-radius: var(--r-full); overflow: hidden; margin-block-start: var(--s-3); }
.tcard .bar span { display: block; block-size: 100%; background: var(--band); inline-size: var(--pct, 0%); border-radius: var(--r-full); }


/* ── segmented controls ────────────────────────────────────────────────── */
.controls { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-block-end: var(--s-4); }
.seg { display: inline-flex; background: var(--surface-sunken); border-radius: var(--r-full); padding: 3px; }
.seg.spacer { margin-inline-start: auto; }
.seg button {
  font: inherit; font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-tertiary); background: transparent; border: 0; cursor: pointer;
  padding: var(--s-2) var(--s-4); border-radius: var(--r-full);
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.seg button:hover { color: var(--text-primary); }
.seg button[aria-pressed="true"] { background: var(--surface-card); color: var(--text-primary); font-weight: var(--weight-semi); box-shadow: var(--shadow-1); }
.seg[hidden] { display: none; }


/* ── hour × day grid ───────────────────────────────────────────────────────
   The densest thing on the site: 24 rows × 7 days, three times over on a
   two-terminal airport. It is a heat table, so the cell IS the datum — colour
   carries the value and the word confirms it. */
.gridwrap { margin-block-end: var(--s-4); }
table.grid {
  inline-size: 100%;
  border-collapse: separate; border-spacing: 3px;
  font-size: var(--step--2);
  table-layout: fixed;
  background: none; border: 0; border-radius: 0; overflow: visible;
}
table.grid th {
  padding: 0 0 var(--s-2);
  font-family: var(--font-text); font-size: var(--step--2); font-weight: var(--weight-semi);
  color: var(--text-tertiary); text-align: center;
  border: 0; text-transform: none; letter-spacing: var(--tracking-normal);
}
table.grid th.hour {
  inline-size: 3.2rem; text-align: end;
  padding-inline-end: var(--s-2); padding-block: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-quiet); font-weight: var(--weight-normal);
}
table.grid th small { display: block; font-weight: var(--weight-normal); color: var(--text-quiet); }
table.grid td { padding: 0; border: 0; }

.cell {
  display: block;
  padding-block: var(--s-2);
  border-radius: var(--r-1);
  text-align: center;
  background: var(--band-fill);
  color: var(--band-on-fill);
  font-weight: var(--weight-semi);
  font-size: var(--step--2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cell.empty { background: var(--surface-sunken); color: var(--text-quiet); font-weight: var(--weight-normal); }
/* Night hours are de-emphasised by desaturating the CELL, not by fading it:
   opacity dropped the tinted bands below AA on their own text. */
tr.rest .cell { filter: saturate(0.72); }
.cell[tabindex] { cursor: pointer; transition: box-shadow var(--dur-1) var(--ease); }
.cell[tabindex]:hover, .cell[tabindex]:focus { box-shadow: 0 0 0 2px var(--surface-card), 0 0 0 3px var(--band); position: relative; z-index: 2; outline: none; }
.cell[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--surface-card), 0 0 0 3px var(--text-primary); }


/* ── bar charts ────────────────────────────────────────────────────────── */
.forecast { margin-block-end: var(--s-4); }
.strip { display: flex; gap: 3px; align-items: flex-end; block-size: 5.5rem; }
.strip i {
  flex: 1 1 0; min-inline-size: 0;
  border-radius: var(--r-1) var(--r-1) 1px 1px;
  background: var(--band); min-block-size: 3px;
  animation: grow var(--dur-3) var(--ease-out) backwards;
}
.strip i.is-now { outline: 2px solid var(--text-primary); outline-offset: 1px; }
@keyframes grow { from { block-size: 3px !important; opacity: 0; } }

.hours { display: flex; gap: 3px; align-items: flex-end; block-size: 8.5rem; margin-block-end: var(--s-2); }
.hours i { flex: 1 1 0; min-inline-size: 0; border-radius: var(--r-1) var(--r-1) 1px 1px; background: var(--band); min-block-size: 3px; position: relative; }
.hours i.peak-hour { outline: 2px solid var(--text-primary); outline-offset: 1px; }
.hours i[tabindex] { cursor: pointer; }
.hours i[tabindex]:hover, .hours i[tabindex]:focus { outline: 2px solid var(--text-primary); outline-offset: 1px; }

.axis, .hourlabels {
  display: flex; justify-content: space-between;
  font-size: var(--step--2); color: var(--text-quiet);
  margin-block-start: var(--s-2);
  font-variant-numeric: tabular-nums;
}


/* ── chart readout ─────────────────────────────────────────────────────── */
.readout { margin-block-start: var(--s-4); padding: var(--s-4); border-radius: var(--r-2); background: var(--band-tint); border: 1px solid var(--band-edge); }
.readout[hidden] { display: none; }
.readout-head { display: flex; align-items: center; gap: var(--s-2); margin-block-end: var(--s-2); }
.readout-head .pip { inline-size: 10px; block-size: 10px; border-radius: 50%; background: var(--band); flex: none; }
.readout-head strong { font-size: var(--step-0); }
.readout-head span[data-ro-band] { color: var(--band-text); font-weight: var(--weight-semi); }
.readout p { margin: 0; font-size: var(--step--1); color: var(--text-secondary); max-inline-size: none; }
.readout-level { font-weight: var(--weight-semi); color: var(--band-text); margin-block: 0 var(--s-1); }
.readout-dest { color: var(--text-tertiary) !important; margin-block-start: var(--s-1) !important; }


/* ── legend ────────────────────────────────────────────────────────────── */
.legend { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-block-start: var(--s-4); font-size: var(--step--2); color: var(--text-tertiary); }
.legend span { display: inline-flex; align-items: center; gap: var(--s-2); }
.legend i { inline-size: 10px; block-size: 10px; border-radius: 3px; background: var(--band); }
.legend-hint { margin-inline-start: auto; color: var(--text-quiet); }


/* ── ranked lists ──────────────────────────────────────────────────────── */
.ranked { display: flex; flex-direction: column; }
.ranked[hidden] { display: none; }
.ranked > * {
  display: flex; align-items: center; gap: var(--s-3);
  padding-block: var(--s-3);
  border-block-end: 1px solid var(--border-hairline);
  text-decoration: none; color: var(--text-primary);
  font-size: var(--step-0);
}
.ranked > *:last-child { border-block-end: 0; }
.ranked a:hover { color: var(--text-action); }
.ranked .rank { flex: none; inline-size: 1.5rem; font-size: var(--step--2); color: var(--text-quiet); font-variant-numeric: tabular-nums; }
.ranked .meta { margin-inline-start: auto; color: var(--text-tertiary); font-size: var(--step--1); font-variant-numeric: tabular-nums; white-space: nowrap; }


/* ── KPI tiles ─────────────────────────────────────────────────────────────
   The one place a big number is the point. Tinted by band, so a bad number
   looks bad without needing a second component. */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s-3); margin-block-end: var(--s-5); }
.kpi { background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--r-2); padding: var(--s-4); }
.kpi .v {
  font-family: var(--font-display);
  font-size: var(--step-4); font-weight: var(--weight-bold);
  line-height: 1; letter-spacing: var(--tracking-tight);
  color: var(--band); font-variant-numeric: tabular-nums;
}
.kpi .k { font-size: var(--step--2); color: var(--text-tertiary); margin-block-start: var(--s-2); line-height: var(--leading-snug); }


/* ── two sections abreast ──────────────────────────────────────────────────
   For short blocks that each answered a related question in their own
   full-width row: a 20rem list in a 46rem column, twice, with the empty half
   of each row reading as a gap in the page. auto-fit rather than a fixed
   1fr 1fr so it folds to one column on a phone without a second breakpoint. */
.duo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--s-2) var(--s-6);
  margin-block-end: var(--s-5);
  align-items: start;
}
/* Grid items default to min-width:auto, so a long destination name would push
   the column wider than its share instead of wrapping. */
.duo > section { min-inline-size: 0; }
.duo h2 { margin-block-start: 0; }

/* One of these sections carries an intro sentence and the other does not, so
   their lists started at different heights and the pair read as misaligned
   rather than as a row. subgrid lets both sections share the OUTER grid's rows,
   and pinning the list to row 3 keeps it there whether or not row 2 is filled.

   Behind @supports on purpose: where subgrid is missing the rules are skipped
   and the layout falls back to two independently-flowing columns, which is
   exactly what it looked like before. Nothing to clean up later. */
@supports (grid-template-rows: subgrid) {
  .duo { grid-template-rows: auto auto 1fr; }
  .duo > section {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
  }
  .duo > section > .ranked { grid-row: 3; }
}

/* ── leaderboards ──────────────────────────────────────────────────────── */
.boards { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--s-4); margin-block-end: var(--s-5); }
.board { background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--r-2); padding: var(--s-4) var(--s-5) var(--s-2); }
.board h3 { font-size: var(--step-0); margin-block-end: var(--s-1); }
.board .sub { font-size: var(--step--2); color: var(--text-tertiary); margin-block-end: var(--s-3); line-height: var(--leading-snug); }
.board ol { list-style: none; margin: 0; padding: 0; }
.board li { display: flex; align-items: center; gap: var(--s-3); padding-block: var(--s-3); border-block-end: 1px solid var(--border-hairline); font-size: var(--step--1); }
.board li:last-child { border-block-end: 0; }
.board .n {
  flex: none; inline-size: 1.4rem; block-size: 1.4rem;
  display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--band-tint); color: var(--band-text);
  font-size: var(--step--2); font-weight: var(--weight-semi);
}
.board .val { margin-inline-start: auto; font-weight: var(--weight-semi); color: var(--band-text); font-variant-numeric: tabular-nums; }
.board.good { --band: var(--sig-quiet); }
.board.bad { --band: var(--sig-peak); }


/* ── the calculator ────────────────────────────────────────────────────── */
.calc {
  max-inline-size: var(--w-prose);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-3);
  padding: var(--s-5);
  margin-block-end: var(--s-5);
}
.field { margin-block-end: var(--s-5); }
.field:last-of-type { margin-block-end: var(--s-4); }
.field label { display: block; font-size: var(--step--1); font-weight: var(--weight-semi); color: var(--text-secondary); margin-block-end: var(--s-2); }
.field select {
  inline-size: 100%;
  font: inherit; font-size: var(--step-0);
  color: var(--text-primary);
  background-color: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  padding: var(--s-3) var(--s-4);
  padding-inline-end: var(--s-8);
  appearance: none;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right var(--s-4) center;
  background-size: 12px;
}
html[dir="rtl"] .field select { background-position: left var(--s-4) center; }
.field select:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring); }

/* direction: ltr, even on a Hebrew page. A flex row follows the writing
   direction, so in RTL the two selects swapped and the field read 30:08 --
   minutes first. A clock time is an LTR construct in Hebrew exactly as it is in
   English: HH then MM, left to right, with the colon between. The BOX still
   sits wherever the RTL layout puts it; only its contents are pinned. */
.timepair { display: flex; direction: ltr; align-items: center; gap: var(--s-2); }
.timepair select { inline-size: auto; flex: 1 1 0; text-align: center; }
.timepair span { color: var(--text-tertiary); font-weight: var(--weight-semi); }

.choices { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.choices button {
  flex: 1 1 8rem;
  font: inherit; font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  padding: var(--s-3);
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease);
}
.choices button:hover { border-color: var(--border-strong); }
.choices button[aria-pressed="true"] { border-color: var(--text-brand); background: var(--surface-brand); color: var(--text-brand); font-weight: var(--weight-semi); }

.cta {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  inline-size: 100%;
  font: inherit; font-size: var(--step-0); font-weight: var(--weight-semi);
  color: var(--text-invert);
  background: var(--surface-invert);
  border: 0; border-radius: var(--r-2);
  padding: var(--s-3) var(--s-5);
  cursor: pointer; text-decoration: none;
  transition: background-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease);
}
.cta:hover { background: var(--navy-1); color: var(--text-invert); transform: translateY(-1px); }
.cta:active { transform: none; }

/* The one thing on this page the reader came for, so it is the one thing that
   is not a white card. It is tinted by the band of the hour it recommends --
   the same channel every other component reads -- so the card is green when it
   is sending you at a quiet time and red when the best it can offer is a busy
   one. That is information, not decoration: the colour is the second half of
   the answer, and it was previously being thrown away. */
.result {
  max-inline-size: var(--w-prose);
  background: var(--band-tint);
  border: 1px solid color-mix(in srgb, var(--band) 32%, transparent);
  border-radius: var(--r-3);
  padding: var(--s-5);
  margin-block-end: var(--s-5);
  box-shadow: var(--shadow-2);
}
.result[hidden] { display: none; }
.result .k { font-size: var(--step--1); color: color-mix(in srgb, var(--ink-0) 62%, var(--band-tint)); }
.result .time {
  font-family: var(--font-display);
  font-size: var(--step-6); font-weight: var(--weight-bold);
  line-height: 1; letter-spacing: var(--tracking-tight);
  /* Not --band-text: that is mixed for a WHITE card, and on this card's own
     tint it landed at 3.99:1 for the three light bands -- legible as large
     text, under this project's 4.5:1 line. More ink, same hue. Measured on the
     rendered card across all five bands; worst is 5.0:1. */
  color: color-mix(in srgb, var(--band) 65%, var(--ink-0));
  margin-block: var(--s-2);
  font-variant-numeric: tabular-nums;
}
.result .band {
  display: inline-block;
  font-size: var(--step--2); font-weight: var(--weight-semi);
  color: var(--band-on-fill); background: var(--band-fill);
  padding: var(--s-1) var(--s-3); border-radius: var(--r-full);
}
.result dl {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--s-2) var(--s-4);
  margin: var(--s-4) 0 0;
  padding-block-start: var(--s-4);
  border-block-start: 1px solid var(--border-hairline);
  font-size: var(--step--1);
}
.result dt { color: color-mix(in srgb, var(--ink-0) 62%, var(--band-tint)); }
.result dd { margin: 0; text-align: end; font-weight: var(--weight-medium); }


/* The language row in the footer. Inline, comma separated, no flags. Each name
   is kept whole so a wrap never splits "Português" from its own comma. */
.footer-langs {
  margin: 0;
  font-size: var(--step--1);
  line-height: var(--leading-loose);
}
.footer-langs a { white-space: nowrap; }

/* ── contact / partnership form ────────────────────────────────────────── */
.cform { max-inline-size: var(--w-prose); margin-block-end: var(--s-6); }
.cform .field { margin-block-end: var(--s-4); }
.cform label {
  display: block; margin-block-end: var(--s-2);
  font-size: var(--step--1); font-weight: var(--weight-semi);
  color: var(--text-secondary);
}
.cform input, .cform textarea {
  inline-size: 100%;
  padding: var(--s-3);
  font: inherit; font-size: var(--step-0);
  color: var(--text-primary); background: var(--surface-card);
  border: 1px solid var(--border-subtle); border-radius: var(--r-2);
}
.cform textarea { resize: vertical; min-block-size: 7rem; }
.cform input:focus-visible, .cform textarea:focus-visible {
  outline: 2px solid var(--border-focus); outline-offset: 1px;
  border-color: transparent;
}
.cform button[disabled] { opacity: .6; cursor: progress; }
/* Off-screen rather than display:none -- a bot reading the DOM sees a normal
   field, which is the entire point of a honeypot. */
.cform-hp {
  position: absolute; inline-size: 1px; block-size: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.cform-note {
  margin-block-start: var(--s-3);
  font-size: var(--step--1);
  padding: var(--s-3) var(--s-4); border-radius: var(--r-2);
}
.cform-note.is-ok { background: var(--fill-quiet); color: var(--on-quiet); }
.cform-note.is-error { background: var(--fill-busy); color: var(--on-busy); }
.plain { list-style: none; padding: 0; margin: 0; }
.plain li {
  padding-block: var(--s-3);
  border-block-end: 1px solid var(--border-hairline);
  font-size: var(--step--1); line-height: var(--leading-normal);
}
.plain li:last-child { border-block-end: 0; }

/* ── notes, cautions, provenance ───────────────────────────────────────── */
.caution, .disclaimer {
  border-radius: var(--r-2);
  padding: var(--s-4);
  font-size: var(--step--1);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
  background: var(--surface-inset);
  border-inline-start: 3px solid var(--border-strong);
  margin-block: var(--s-4);
  max-inline-size: var(--w-prose);
}
.caution strong, .disclaimer strong { color: var(--text-primary); display: block; margin-block-end: var(--s-1); }
.disclaimer { background: var(--surface-brand); border-inline-start-color: var(--navy-0); }

.provenance { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; font-size: var(--step--2); color: var(--text-tertiary); margin-block-start: var(--s-3); }
.chip {
  display: inline-flex; align-items: center;
  font-size: var(--step--2); font-weight: var(--weight-semi);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--text-secondary); background: var(--surface-sunken);
  padding: 2px var(--s-2); border-radius: var(--r-1);
}
.chip.warn { color: var(--indigo-0); background: var(--indigo-tint); }
.chip[hidden] { display: none; }

.attribution { font-size: var(--step--2); color: var(--text-quiet); }


/* ── FAQ ───────────────────────────────────────────────────────────────── */
.faq { margin-block-start: var(--s-7); }
.faq-item { padding-block: var(--s-4); border-block-end: 1px solid var(--border-hairline); }
.faq-item:last-child { border-block-end: 0; }
.faq h3 { font-size: var(--step-0); margin-block-end: var(--s-2); }
.faq p { color: var(--text-secondary); font-size: var(--step--1); max-inline-size: var(--w-prose); }


/* ── sideways navigation ───────────────────────────────────────────────── */
.sideways { margin-block-start: var(--s-6); }
.sideways .chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.sideways .chips a, nav.pages a {
  text-decoration: none; font-size: var(--step--1);
  color: var(--text-secondary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-4);
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.sideways .chips a:hover, nav.pages a:hover { border-color: var(--border-focus); color: var(--text-brand); }
nav.pages { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-block-start: var(--s-6); }


/* ── editorial prose ───────────────────────────────────────────────────── */
.prose { max-inline-size: var(--w-prose); margin-block: var(--s-6) var(--s-5); }
.prose h2 { font-size: var(--step-2); }
.prose h3 { font-size: var(--step-1); margin-block-start: var(--s-5); }
.prose p { color: var(--text-secondary); line-height: var(--leading-loose); }
.prose ul, .prose ol { color: var(--text-secondary); padding-inline-start: var(--s-5); line-height: var(--leading-loose); }
.prose strong { color: var(--text-primary); font-weight: var(--weight-semi); }
.prose-updated { font-size: var(--step--2); color: var(--text-quiet); }


/* ── data tables ───────────────────────────────────────────────────────── */
table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  overflow: hidden;
}
th {
  text-align: start;
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-text);
  font-size: var(--step--2);
  font-weight: var(--weight-semi);
  color: var(--text-tertiary);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
thead th { border-block-end: 1px solid var(--border-subtle); }
td { padding: var(--s-3) var(--s-4); border-block-end: 1px solid var(--border-hairline); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
tbody th[scope="row"] {
  font-size: inherit; font-weight: var(--weight-medium); color: var(--text-primary);
  text-transform: none; letter-spacing: var(--tracking-normal);
  padding: var(--s-3) var(--s-4);
  border-block-end: 1px solid var(--border-hairline);
  font-variant-numeric: tabular-nums;
}
tr:last-child td, tbody tr:last-child th { border-block-end: none; }
.band-text { color: var(--band-text); font-weight: var(--weight-semi); }


/* ── eSIM ──────────────────────────────────────────────────────────────────
   The commercial block. It is allowed to use the action colour and nothing
   else on the page is, which is the whole reason it gets noticed without
   having to shout. */
.esim {
  margin-block-start: var(--s-7);
  padding: var(--s-5);
  border-radius: var(--r-3);
  background: var(--surface-accent);
  border: 1px solid color-mix(in srgb, var(--indigo-1) 24%, transparent);
}
.esim[hidden] { display: none; }
.esim h3 { font-size: var(--step-2); margin-block-end: var(--s-2); }
.esim p { color: var(--text-secondary); font-size: var(--step--1); margin-block-end: var(--s-4); max-inline-size: var(--w-prose); }
.esim .cta { inline-size: auto; background: var(--indigo-0); color: var(--text-invert); }
.esim .cta:hover { background: var(--indigo-hover); }


/* ── footer ────────────────────────────────────────────────────────────── */
.site-footer { margin-block-start: var(--s-8); background: var(--surface-invert); color: var(--on-invert); font-size: var(--step--1); }
.footer-inner {
  inline-size: min(var(--w-wide), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block: var(--s-7) var(--s-6);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s-6) var(--s-5);
}
.footer-brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: var(--weight-bold);
  font-size: var(--step-1); color: var(--text-invert);
  margin-block-end: var(--s-3);
}
.footer-col h3 {
  margin: 0 0 var(--s-3);
  font-family: var(--font-text);
  font-size: var(--step--2); font-weight: var(--weight-bold);
  color: var(--on-invert-muted);
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
}
html[dir="rtl"] .footer-col h3 { letter-spacing: var(--tracking-normal); }
.footer-col p { color: inherit; margin: 0; max-inline-size: 22rem; }
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-block-end: var(--s-2); }
.footer-col a { color: var(--on-invert-strong); text-decoration: none; }
.footer-col a:hover { color: var(--text-invert); text-decoration: underline; }
.footer-col[hidden] { display: none; }

.footer-legal {
  inline-size: min(var(--w-wide), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block: var(--s-4) var(--s-7);
  border-block-start: 1px solid var(--on-invert-line);
  color: var(--on-invert-muted);
  font-size: var(--step--2);
  line-height: var(--leading-normal);
}
.footer-legal p { margin: 0; color: inherit; max-inline-size: var(--w-content); }
.footer-legal a { color: var(--on-invert-strong); }
.footer-links { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); margin-block-start: var(--s-3) !important; }
.footer-esim { margin-block-start: var(--s-3) !important; }
.footer-esim a { color: var(--on-invert-action); font-weight: var(--weight-semi); }


/* ── utilities ─────────────────────────────────────────────────────────── */
/* Spacing off the scale, for the handful of places a block needs to sit
   further from what precedes it than its component says. Named steps, so the
   rhythm stays the rhythm. */
.mt-5 { margin-block-start: var(--s-5) !important; }
.mt-6 { margin-block-start: var(--s-6) !important; }
.mt-7 { margin-block-start: var(--s-7) !important; }

.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;
}

.reveal { animation: rise var(--dur-3) var(--ease-out) backwards; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ── forecast bar tooltip ──────────────────────────────────────────────────
   Positioned from the top-left with a transform rather than left/top: the
   script writes it on every pointer move, and transform is the only one of the
   three that does not force a layout pass on each one.

   `.strip i` is now focusable, so it needs a visible focus state — the tooltip
   alone is not one, because a keyboard user needs to see WHICH bar they are on. */
.bartip {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  z-index: 60; pointer-events: none;
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s-2) var(--s-3);
  background: var(--surface-invert); color: var(--on-invert-strong);
  border-radius: var(--r-1); box-shadow: var(--shadow-3);
  font-size: var(--step--2); line-height: var(--leading-snug);
  max-inline-size: 15rem;
  border-inline-start: 3px solid var(--band);
}
/* A pointer at the cell it is describing. The tooltip is clamped to the
   viewport, so on a phone it often sits well to one side of its anchor; without
   this, three cells in a row produce a tooltip in the same place and nothing
   says which one it belongs to. --arrow-x is set by the script to the anchor's
   centre, in the tooltip's own coordinates, so the pointer keeps tracking the
   cell after the box itself has been pushed sideways. */
.bartip::after {
  content: ""; position: absolute;
  inline-size: 0; block-size: 0;
  inset-inline-start: var(--arrow-x, 50%);
  margin-inline-start: -6px;
  border-inline-start: 6px solid transparent;
  border-inline-end: 6px solid transparent;
}
.bartip.is-above::after {
  inset-block-start: 100%;
  border-block-start: 6px solid var(--surface-invert);
}
.bartip.is-below::after {
  inset-block-end: 100%;
  border-block-end: 6px solid var(--surface-invert);
}
.bartip[hidden] { display: none; }
.bartip strong { color: var(--paper-0); font-weight: var(--weight-semi); }
.strip i { cursor: pointer; }
.strip i:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 1px; }

/* The cell for the hour the reader is actually in. It pulses because the grid
   is 168 cells and a static ring is lost in it — the movement is what makes
   "you are here" findable at a glance.

   color-mix reads --band, which the .b-* class declares on THIS element, so it
   resolves per band. Declared at :root it would resolve once against :root's
   own grey and every cell would pulse the same colour — the 168-grey-cells bug.

   The reduced-motion block at the end of this file already switches it off. */
.cell.is-now {
  position: relative; z-index: 2;
  animation: nowpulse 2.6s var(--ease) infinite;
}
@keyframes nowpulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--surface-card), 0 0 0 3px var(--band); }
  50%      { box-shadow: 0 0 0 2px var(--surface-card),
                         0 0 0 7px color-mix(in srgb, var(--band) 30%, transparent); }
}

/* ── Hebrew typography ──────────────────────────────────────────────────────
   Hebrew was being served Latin-tuned settings verbatim, and two of them are
   actively wrong for the script.

   TRACKING. Every heading, the wordmark and the big figures carry
   letter-spacing: -0.022em. Negative tracking suits Latin display type, whose
   letterforms have obvious ascenders and descenders to keep them apart. Hebrew
   letters are wide, square and sit in a single band with small counters —
   tightening them closes those counters and letters start to collide. Hebrew
   display type wants normal tracking or a touch positive, never negative.

   SIZE. Hebrew has no capitals and no ascenders: its glyphs occupy roughly the
   x-height band alone, so at an identical font-size Hebrew reads visually
   smaller than Latin. A small optical bump restores the balance rather than
   making it "bigger".

   LEADING. Lines of Hebrew have no descenders to separate them, so the same
   line-height that is comfortable in Latin runs together. A little more air.

   Scoped with :lang(he) rather than [dir=rtl] on purpose — the fix belongs to
   the script, not to the direction. */
:lang(he) h1, :lang(he) h2, :lang(he) h3, :lang(he) h4,
:lang(he) .wordmark, :lang(he) .answer .word, :lang(he) .figure {
  letter-spacing: var(--tracking-normal);
}
:lang(he) body, :lang(he) p, :lang(he) .lede, :lang(he) li {
  line-height: var(--leading-loose);
}
/* :root, NOT a bare :lang(he). `lang` is INHERITED, so :lang(he) matches every
   element on the page, and a relative font-size on all of them compounds once
   per nesting level. Measured in Chromium on the real cascade: root 16.96px,
   a paragraph six levels down 24.06px — a 42% overshoot, with two paragraphs of
   the same class rendering at different sizes purely by DOM depth. That is not
   a subtle tuning problem, it is the type scale being destroyed. Anchoring to
   :root applies the correction exactly once. */
:root:lang(he) {
  font-size: var(--script-he-scale);
}
:lang(he) h1 { line-height: var(--leading-he-h1); }
:lang(he) h2, :lang(he) h3 { line-height: var(--leading-he-h2); }
/* See --weight-he-display. Applies where the Latin sets 900. */
:lang(he) .status .word,
:lang(he) .answer .word { font-weight: var(--weight-he-display); }

