/*
 * Phase 1 styles for the find-a-grantee app.
 *
 * Covers the hero visual treatment (HAPRI brand signatures: full-bleed
 * teal field, white inner-frame, Hestia in the upper-left corner anchor,
 * staircased tagline upper-right, title lower-left, continuous-line tree
 * lower-right) plus the Layer 1 banner styling and the colophon.
 *
 * Phases 2-4 will layer additional CSS for filters bar, Layer 2 cluster
 * list, Layer 3 grantee cards, and Layer 4 advisory panel.
 */

/* ============================================================ */
/*  Be Vietnam — HAPRI's canonical typeface (NOT "Be Vietnam     */
/*  Pro"). Self-hosted from the brand kit per                    */
/*  HAPRI_branding/brand-spec/typography.md.                     */
/* ============================================================ */
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-Regular.woff2') format('woff2');
    font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-Italic.woff2') format('woff2');
    font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-Medium.woff2') format('woff2');
    font-weight: 500; font-display: swap;
}
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-SemiBold.woff2') format('woff2');
    font-weight: 600; font-display: swap;
}
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-Bold.woff2') format('woff2');
    font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Be Vietnam';
    src: url('assets/fonts/BeVietnam-ExtraBold.woff2') format('woff2');
    font-weight: 800; font-display: swap;
}
/* NOTE: the six @font-face blocks above are the ONLY ones; each declared
   weight/style is actually rendered somewhere (Light and BoldItalic were
   declared-but-never-fetched and have been removed). WOFF2 only — full
   glyph coverage incl. Vietnamese diacritics; the canonical TTFs live in
   the HAPRI_branding repo. CSS url() resolves relative to THIS stylesheet
   (always /find-a-grantee/styles.css), not to the HTML page that links it —
   so these blocks already serve every page, including the deeper by-name/
   and by-school/. An earlier `../assets/fonts/` duplicate only ever 404'd
   (it resolved to /assets/fonts/) and was removed. */

/* ============================================================ */
/*  Brand tokens (per HAPRI_branding/brand-spec/)               */
/* ============================================================ */
:root {
    /* Primary palette */
    --teal: #00B1AC;
    --teal-d: #00958F;            /* teal-700, large text + UI only */
    --teal-text: #007E7A;         /* teal-800, body-safe on white (4.5:1) */
    --teal-700d: #00716D;         /* teal-800 darker — body-safe AA on the
                                     teal-50/teal-100 tint backgrounds, where
                                     --teal-text only reaches 4.05–4.50:1 */
    --teal-900: #00514F;
    --teal-50: #E8F8F7;
    --teal-100: #CCF0EE;

    --blue: #20558A;
    --blue-d: #173F69;
    --blue-50: #EEF3F8;

    /* Semantic accents (F41) — the by-school quick-filter pills need a
       couple of category accents beyond the two-color brand. They are
       tokenized here (not hard-coded literals scattered in the rules)
       so the palette is auditable and the RETIRED gold #DAB978 cannot
       creep back in by association. "Be the first" deliberately uses
       the brand teal (it's an invitation, on-brand), NOT a gold. Only
       Ivy keeps a distinct semantic hue (the Ivy League's own
       identity); public/private reuse the neutral graphite. */
    --accent-ivy: #a51c30;        /* Ivy League pill — documented exception */
    --accent-ivy-50: #fbecef;     /* Ivy pill hover wash */

    /* Neutrals */
    --ink: #1B232C;
    --graphite: #364250;
    --slate: #5A6878;
    --mist: #97A3B1;
    --line: #D9DEE4;
    --soft: #F3F5F7;
    --paper: #FFFFFF;

    /* Page content-width tokens (F45). Two widths only, applied
       consistently so sibling pages stop shifting their left/right
       margins on tab switch. Dense pages opt into the wide one. */
    --page-max: 1180px;        /* Explore (non-rail) + By name */
    --page-max-wide: 1440px;   /* Explore rail mode + By school */

    /* Radius tokens — per layout.md */
    --r-xs:   2px;
    --r-sm:   4px;
    --r-md:   6px;   /* DEFAULT — cards, buttons, inputs */
    --r-lg:  10px;   /* callout cards echoing logomark frame */
    --r-xl:  16px;   /* large surfaces */
    --r-pill: 999px; /* badges, filter chips */

    /* Shadow ramp — cool-blue-tinted, 4 steps per layout.md.
       Anchored on --blue rgb(32,85,138). No inner shadows. */
    --shadow-1: 0 1px  2px rgba(32, 85, 138, 0.06),
                0 1px  1px rgba(32, 85, 138, 0.04);
    --shadow-2: 0 2px  6px rgba(32, 85, 138, 0.08),
                0 1px  2px rgba(32, 85, 138, 0.05);
    --shadow-3: 0 8px 20px rgba(32, 85, 138, 0.12),
                0 2px  6px rgba(32, 85, 138, 0.07);
    --shadow-4: 0 16px 40px rgba(32, 85, 138, 0.18),
                0 4px 10px rgba(32, 85, 138, 0.08);
}

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

html { scroll-behavior: smooth; }

body {
    margin: 0;
    color: var(--ink);
    background: var(--soft);
    font-family: 'Be Vietnam', -apple-system, BlinkMacSystemFont,
                 'Segoe UI', Roboto, sans-serif;
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; }
p { margin: 0; }

/* Focus ring: blue at 2px with offset, per a11y-spec.md (passes 3:1
   against teal and white surfaces). */
:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 3px;
}

/* ============================================================ */
/*  HERO - full-bleed teal field, 4-corner-anchor composition    */
/* ============================================================ */
/* Floating fullscreen toggle. Top-right of viewport so it never
   collides with the hero title or filter card. White-on-translucent
   in the page (over the teal hero); the icon swap (.fs-enter shown
   normally, .fs-exit swapped in while fullscreen) is driven from
   app.js. */
.fullscreen-btn {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 50;
    width: 36px;
    height: 36px;
    border: none;
    border-radius: var(--r-md);
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    transition: background 0.12s;
}
.fullscreen-btn:hover { background: rgba(255, 255, 255, 0.32); }
.fullscreen-btn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}
/* When user has scrolled past the teal hero, the button switches to
   a dark-ink theme so it stays visible against the gray page. */
.fullscreen-btn.is-on-light {
    background: rgba(27, 35, 44, 0.85);
    color: #fff;
}
.fullscreen-btn.is-on-light:hover { background: rgba(27, 35, 44, 1); }

.hero {
    position: relative;
    /* Solid brand teal — matches the baked-in teal of the tree JPG
       so there's no visible color-block mismatch around the tree.
       The earlier gradient drifted darker toward the bottom and left
       a visible rectangle around the tree art. */
    background: var(--teal);
    color: #fff;
    /* Two-row grid: title+tree on row 1, nav strip on row 2. Mark
       and tagline are overlaid inside the title block now (no
       dedicated upper strip) so the hero is shorter overall. */
    padding: 18px 56px 22px;
    display: grid;
    grid-template-columns: minmax(280px, 1fr) minmax(180px, 1fr);
    grid-template-rows: 1fr auto;
    column-gap: 40px;
    row-gap: 14px;
    overflow: hidden;
}
/* Mobile hero reflow is owned by the single consolidated
   @media (max-width: 720px) block further down (F48/F49). The old
   max-width:700px block was removed: it set .hero to display:block
   while the 720px block set it to a grid, and it left .hero-tagline
   absolutely positioned, so the tagline piled onto the title between
   700-720px and at the narrowest widths. One breakpoint now governs
   the whole mobile hero. */

/* The white inner-frame device per layout.md ("thin white rule set just
   inside the edge of a teal or blue field, subdividing the layout into
   corner anchors"). Picture-frame rectangle 18px inside the hero edge. */
.hero-frame {
    position: absolute;
    top: 18px;
    right: 18px;
    bottom: 18px;
    left: 18px;
    border: 1.5px solid rgba(255, 255, 255, 0.45);
    pointer-events: none;
}

/* Hestia logomark — small, sits in the hero's true top-left corner
   ABOVE the title block so it never shares pixels with the eyebrow
   text (F48). Sized by HEIGHT, not width: the master PNG is 2400×2596
   (taller than wide), so a fixed width would distort/oversize it. The
   teal master is filter-inverted to white for the dark field. */
.hero-mark {
    position: absolute;
    top: 20px;
    left: 56px;
    width: auto;
    height: 26px;        /* ~1.1em — height-driven per the 2400×2596 aspect */
    /* Convert the teal master to white. The Hestia is a single-
       color symbol; brightness(0) flattens to black, then invert
       flips to white. */
    filter: brightness(0) invert(1);
    opacity: 0.95;
    z-index: 1;
}
/* Staircased tagline — positioned over the tree column as a small
   brand mark instead of taking its own row. Sits in the upper-
   right corner of the hero. */
.hero-tagline {
    position: absolute;
    top: 22px;
    right: 56px;
    margin: 0;
    text-align: right;
    font-size: 0.82rem;
    font-weight: 500;
    line-height: 1.2;
    letter-spacing: 0.005em;
    opacity: 0.9;
    z-index: 1;
    /* Don't block clicks on the fullscreen button which lives in
       the same corner. */
    pointer-events: none;
}
.hero-tagline span {
    display: block;
}
/* Staircased / stepped setting per typography.md — each line nudges
   right of the one above it so the three lines climb diagonally. */
.hero-tagline span:nth-child(1) { padding-right: 0; }
.hero-tagline span:nth-child(2) { padding-right: 1.5em; }
.hero-tagline span:nth-child(3) { padding-right: 3em; font-weight: 700; }

/* Left column: page title set as a research-tool prompt. The Hestia
   mark sits absolutely in the hero's top-left corner (top:20px,
   height:26px → occupies ~y20-46). Push the title block below that
   band so the eyebrow never shares pixels with the mark (F48). */
.hero-title {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    padding-top: 34px;
    max-width: 56ch;
}
/* Eyebrow "A HAPRI RESEARCH TOOL" (F6): white-on-teal at opacity
   0.85 was only 2.29:1. Render it as solid white on a self-contained
   darker-teal band (#00807C → white = 4.80:1, AA pass) instead of
   dropping the opacity onto the lighter #00B1AC hero field (which
   would still fail at 2.66:1). Inline-block so the band hugs the text
   and the tree-JPG seam (F47) is left untouched. */
.hero-eyebrow {
    display: inline-block;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #fff;
    background: #00807C;
    padding: 3px 9px;
    border-radius: var(--r-sm);
    margin-bottom: 10px;
}

/* Bottom-anchored nav row: tabs on the left, snapshot date on the
   right. .hero-bottom is the row container in the hero grid. */
.hero-bottom {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-top: 12px;
    padding-top: 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.18);
    display: flex;
    align-items: center;
    gap: 16px;
}
.hero-tabs {
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 1.15rem;
    font-weight: 500;
    letter-spacing: 0.01em;
}
.hero-tabs a {
    color: rgba(255, 255, 255, 0.72);
    text-decoration: none;
    padding: 4px 2px 8px;
    border-bottom: 2px solid transparent;
    transition: color 0.14s, border-color 0.14s;
}
.hero-tabs a:hover {
    color: #fff;
    border-bottom-color: rgba(255, 255, 255, 0.4);
}
.hero-tabs a:focus-visible {
    color: #fff;
    border-bottom-color: rgba(255, 255, 255, 0.45);
    outline: 2px solid rgba(255, 255, 255, 0.7);
    outline-offset: 4px;
    border-radius: var(--r-xs);
}
.hero-tabs a[aria-current="page"] {
    color: #fff;
    border-bottom-color: #fff;
    font-weight: 600;
}
.hero-tabs-sep {
    color: rgba(255, 255, 255, 0.35);
    user-select: none;
    font-size: 0.85em;
}

.hero-title h1 {
    font-weight: 800;
    font-size: clamp(2rem, 4vw, 3rem);
    line-height: 1.1;
    margin-bottom: 14px;
}
/* Hero sub-paragraph (F6): white@0.92 on teal was ~2.47:1. Render it
   as solid white on a contained darker-teal panel (#00807C → white =
   4.80:1, AA pass) rather than dropping opacity onto the lighter hero
   field. Reads as an intro lozenge; leaves the tree-JPG seam (F47)
   untouched and visually ties to the eyebrow band above. */
.hero-sub {
    display: inline-block;
    font-size: 1rem;
    line-height: 1.55;
    color: #fff;
    background: #00807C;
    padding: 8px 12px;
    border-radius: var(--r-sm);
    max-width: 48ch;
}

/* Right column: the continuous-line tree. F47 — switched from the baked
   teal JPG (which needed a brittle seam-match to blend its opaque teal
   edge into the hero field, and carried JPG ringing on the white lines)
   to the canonical TRANSPARENT white-tree PNG drawn straight over the
   live --teal hero. The transparency means it always matches the hero
   colour with zero seam, and works on any future hero background.
   (The brand ships this art only as raster, so a true SVG would need a
   new vector master — this is the cleanest fix with existing assets.)
   Sized to match the title-block height; `contain` keeps the drawing
   intact at any height. */
.hero-tree {
    grid-column: 2;
    grid-row: 1;
    align-self: stretch;
    justify-self: end;
    width: 100%;
    min-height: 120px;
    background-image: url('assets/tree-white.png');
    background-size: contain;
    background-position: right center;
    background-repeat: no-repeat;
}

/* ============================================================ */
/*  MAIN - the Phase 1 mount point + future filter/results area  */
/* ============================================================ */
main {
    max-width: var(--page-max);   /* F45: shared narrow page width */
    margin: 0 auto;
    padding: 48px 24px 64px;
}

/* The Phase 2c app-shell wraps main + the field-detail aside. On
   viewports below the wide-grid breakpoint it's a transparent
   wrapper - the existing `main` rule above keeps its 960px max-width
   and centering. The grid kicks in at min-width: 1280px below. */
.app-shell { /* no-op on small viewports - main owns the layout */ }

/* ============================================================ */
/*  Layer 1 banner                                               */
/* ============================================================ */
.layer-1 {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 32px 36px;
}
.layer-1-head {
    color: var(--blue);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.25;
    margin-bottom: 12px;
}
.layer-1-body {
    color: var(--ink);
    font-size: 1rem;
    line-height: 1.6;
    margin-bottom: 18px;
}
.layer-1-body strong {
    color: var(--teal-text);
    font-weight: 600;
}
/* Type pill shown above each Layer 1 banner section and each
   breakdown card when both grantee types are visible. Distinguishes
   the FLTA section from the Foreign Student section at a glance. */
.layer-1-type-pill,
.breakdown-type-pill {
    display: inline-block;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--teal-text);
    background: var(--teal-50);
    border: 1px solid var(--teal-100);
    border-radius: var(--r-pill);
    padding: 3px 10px;
    margin-bottom: 8px;
}
.layer-1-type-pill {
    margin-top: 4px;
}
.layer-1-head + .layer-1-body + .layer-1-type-pill,
.layer-1-body + .layer-1-type-pill {
    margin-top: 18px;
}
/* M5: clearly separate stacked region briefs, with extra space above every
   type pill after the first (e.g. the "Foreign Student Grantee" block below FLTA). */
.layer-1-type-pill:not(:first-child) {
    margin-top: 34px;
}

.layer-1-meta {
    color: var(--slate);
    font-size: 0.86rem;
    border-top: 1px solid var(--line);
    padding-top: 14px;
    margin-bottom: 8px;
    /* Be Vietnam tabular figures, not SF Mono (F42) — keeps the date
       digits aligned without the dev-console voice. */
    font-variant-numeric: tabular-nums;
}
.layer-1-note {
    color: var(--slate);
    font-size: 0.88rem;
    font-style: italic;
}

.loading, .error {
    color: var(--slate);
    font-size: 0.95rem;
    text-align: center;
    padding: 24px 0;
}
.error {
    color: var(--blue-d);
}

/* ============================================================ */
/*  Filters panel (Phase 2a)                                     */
/* ============================================================ */
/* Unified input-surface treatment (F44): --r-lg corners + a soft
   --shadow-1 lift, matching .byname-search and .byschool-cmd so the
   three primary filter/search cards feel like one design system. */
.filters {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-1);
    padding: 24px 28px;
    margin-bottom: 18px;
}
.filter-row {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.filter-row:last-of-type { margin-bottom: 0; }
.filter-label {
    flex: 0 0 auto;
    min-width: 110px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--blue);
}

/* The "Popular majors" row sits visually closer to its sibling
   Field family row above (smaller top margin) since they are
   conceptually the same filter split across two lines. A teal-tinted
   label signals "this row is the high-traffic shortlist". */
.filter-row.popular-majors-row {
    margin-top: -8px;
}
.popular-majors-row .filter-label {
    color: var(--teal-text);
}

/* Native select, brand-styled */
.filter-row select {
    font: inherit;
    font-size: 0.95rem;
    color: var(--ink);
    background: var(--paper);
    border: 1.5px solid var(--line);
    border-radius: var(--r-md);
    padding: 7px 32px 7px 12px;
    cursor: pointer;
    min-width: 220px;
    appearance: none;
    -webkit-appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--slate) 50%),
                      linear-gradient(135deg, var(--slate) 50%, transparent 50%);
    background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}
/* Keep a visible brand focus ring (F31): the old outline:none relied
   on a border-tint alone, which is easy to miss and the resting-mist→
   teal-text delta is marginal. :focus-visible (not :focus) so mouse
   clicks don't flash a ring. */
.filter-row select:focus { border-color: var(--teal-text); }
.filter-row select:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 1px;
    border-color: var(--teal-text);
}

/* Radio pill group (geographic scope) */
.scope-group {
    display: inline-flex;
    background: var(--soft);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 3px;
}
.scope-group label {
    position: relative;
    cursor: pointer;
    font-size: 0.86rem;
    padding: 6px 14px;
    border-radius: var(--r-sm);
    color: var(--slate);
    font-weight: 500;
    transition: color 0.15s, background-color 0.15s;
}
.scope-group input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.scope-group label:has(input:checked) {
    background: var(--blue);
    color: #fff;
}

/* ------------------------------------------------------------
 * Mobile reflow for the Explore filter card (F13 — responsive
 * root cause). The card had NO narrow breakpoint: a min-width:220px
 * <select> plus a non-wrapping inline-flex segmented scope control
 * inside a 28px-padded card forced the page wider than a 390px
 * viewport, causing two-dimensional scrolling.
 *
 * ≤640px: shrink the card padding, let the select fill its row, and
 * make the scope control a full-width wrapping flex so the three
 * radios share the row instead of jutting past the card edge.
 * ------------------------------------------------------------ */
@media (max-width: 640px) {
    .filters { padding: 18px 16px; }
    .filter-row { gap: 10px 12px; }
    .filter-row select {
        min-width: 0;
        width: 100%;
    }
    .scope-group {
        display: flex;
        width: 100%;
    }
    .scope-group label {
        flex: 1 1 auto;
        text-align: center;
        padding: 8px 10px;   /* taller hit area too (helps F14/F30 targets) */
    }
    /* The year row (histogram + 240px track + two stepper pairs + value
       read-out + helper) is ~500px wide and cannot fit a phone. Let it
       WRAP: the histogram and the track each take their own full-width
       row, then the stepper pairs + value share the next row, and the
       helper drops below. DOM order is hist → track → start-steppers →
       value → end-steppers → helper, so flex-basis:100% on the first two
       wraps the rest automatically — no `order` needed. (Fixes the
       horizontal overflow the 2026 QA pass found on all three pages.) */
    .year-slider { width: 100%; flex-wrap: wrap; gap: 10px 8px; }
    .year-slider-hist { flex: 1 1 100%; }
    .year-slider-track-wrap {
        flex: 1 1 100%;
        width: auto;
        min-width: 0;
        max-width: 100%;
    }
    .year-slider-value { flex: 1 1 auto; min-width: 0; text-align: center; }
    .year-slider .filter-helper { flex: 1 1 100%; margin-left: 0; }
    /* Sticky bar on phones: drop the brand wordmark + snapshot so the
       centered segmented nav keeps room (the leaf mark stays at the left). */
    .hero-sticky-word { display: none; }
    .hero-sticky .hero-snapshot { display: none; }
    .hero-sticky { padding: 8px 14px; gap: 10px; }
}
@media (max-width: 480px) {
    /* Stack each filter row's label above its control so nothing is
       forced side-by-side on the narrowest phones. */
    .filter-row { align-items: stretch; }
    .filter-label { min-width: 0; }
    /* The field-dropdown panel is capped at min(360px,90vw) already,
       but pin it to the viewport so it can't add horizontal scroll. */
    .field-dropdown-panel { width: min(360px, calc(100vw - 32px)); }
}

/* ------------------------------------------------------------
 * Field-filter dropdown (Option C in the design review).
 *
 * Replaces the prior two stacked chip rows (umbrella family +
 * popular majors) with a single compact trigger that opens a
 * grouped checklist with search. Selected items appear as
 * removable chips inline. Shared by Explore, by-name, by-school.
 * ------------------------------------------------------------ */
.field-dropdown {
    position: relative;
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}
.field-dropdown-chips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 4px;
}
.field-dropdown-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--blue);
    color: #fff;
    border: 1.5px solid var(--blue);
    border-radius: var(--r-pill);
    padding: 3px 4px 3px 10px;
    font-size: 0.8rem;
    font-weight: 500;
    cursor: pointer;
    font-family: inherit;
    line-height: 1.3;
}
.field-dropdown-chip:hover { background: #18406c; border-color: #18406c; }
.field-dropdown-chip-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    background: rgba(255, 255, 255, 0.22);
    border-radius: 50%;
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1;
}
.field-dropdown-trigger {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--teal-text);
    background: var(--paper);
    border: 1.5px dashed var(--teal-text);
    border-radius: var(--r-pill);
    cursor: pointer;
    font-family: inherit;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.field-dropdown-trigger:hover,
.field-dropdown.is-open .field-dropdown-trigger {
    background: var(--teal-50);
    border-style: solid;
}
.field-dropdown-trigger:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.field-dropdown-panel {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 50;
    width: min(360px, 90vw);
    max-height: 360px;
    overflow-y: auto;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-3);
    padding: 12px;
}
.field-dropdown-panel[hidden] { display: none; }
.field-dropdown-search {
    width: 100%;
    font-family: inherit;
    font-size: 0.88rem;
    padding: 6px 10px;
    border: 1px solid var(--mist);
    border-radius: var(--r-md);
    margin-bottom: 10px;
}
.field-dropdown-search:focus { border-color: var(--teal-text); }
.field-dropdown-search:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 1px;
    border-color: var(--teal-text);
}
.field-dropdown-group-label {
    margin: 8px 0 4px;
    font-size: 0.66rem;
    font-weight: 700;
    color: var(--blue);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.field-dropdown-group-label:first-child { margin-top: 0; }
.field-dropdown-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-radius: var(--r-md);
    cursor: pointer;
    font-size: 0.86rem;
    color: var(--ink);
}
.field-dropdown-row:hover { background: var(--teal-50); }
.field-dropdown-row.is-child {
    padding-left: 28px;
    font-size: 0.82rem;
    color: var(--graphite);
}
.field-dropdown-row.is-child::before {
    content: '';
    /* Subtle vertical tick to visually link the cluster to its
       parent family above. */
    position: absolute;
    margin-left: -16px;
    width: 8px;
    border-left: 1px solid var(--teal-100);
    height: 100%;
}
.field-dropdown-row.is-child { position: relative; }
.field-dropdown-row input[type="checkbox"] {
    accent-color: var(--teal);
    width: 14px;
    height: 14px;
    margin: 0;
}
/* Field-panel V1: per-row grantee count + per-group "Select all".
   The label takes the slack so the count right-aligns; the count is a
   tabular, muted figure that brightens to teal on row hover. */
.field-dropdown-row-label { flex: 1 1 auto; min-width: 0; }
.field-dropdown-count {
    flex: 0 0 auto;
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
    color: var(--slate);
    margin-left: 8px;
}
.field-dropdown-row:hover .field-dropdown-count { color: var(--teal-text); }
.field-dropdown-group-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin: 8px 0 4px;
}
.field-dropdown-group-head:first-child { margin-top: 0; }
.field-dropdown-group-head .field-dropdown-group-label { margin: 0; }
.field-dropdown-selectall {
    flex: 0 0 auto;
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--teal-text);
    background: none;
    border: none;
    padding: 2px 4px;
    border-radius: var(--r-sm);
    cursor: pointer;
    text-transform: none;
}
.field-dropdown-selectall:hover { color: var(--teal-d); text-decoration: underline; }
.field-dropdown-selectall.is-all { color: var(--slate); }
.field-dropdown-selectall:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 1px;
}
.field-dropdown-empty {
    color: var(--slate);
    font-size: 0.84rem;
    font-style: italic;
    padding: 8px 0 4px;
    margin: 0;
}

/* Chip group (multi-select toggle chips: field family, grantee type) */
.chip-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 14px;
    align-items: center;
}
.chip-group {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}
/* Canonical chip primitive (F37/F40). One convention across all three
   pages: idle = teal outline on paper, hover = teal-50 wash, active =
   solid blue. Idle border unified to --teal-100 and radius to --r-pill
   so by-name/by-school chips (which extend this look) stop drifting.
   Outline-when-off + filled-when-on makes the toggle nature obvious. */
.chip {
    display: inline-flex;
    align-items: center;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--teal-text);
    background: var(--paper);
    border: 1.5px solid var(--teal-100);
    border-radius: var(--r-pill);
    padding: 4px 12px;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.chip input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.chip:hover {
    background: var(--teal-50);
    border-color: var(--teal);
}
.chip-active {
    background: var(--blue);
    color: #fff;
    border-color: var(--blue);
}
.chip-active:hover {
    background: var(--blue-d);
    border-color: var(--blue-d);
}
.chip:focus-within {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

/* Year range dual-handle slider.

   Two <input type="range"> overlap on the same track. Their backing
   tracks are made transparent (the visible track is a dedicated
   sibling span with a fill overlay), and each input gets
   pointer-events:none so the user's clicks pass straight through to
   whichever thumb is on top. Thumbs themselves re-enable pointer
   events. The fill span between the two thumbs is positioned in JS
   based on the current min/max values. */
.year-slider {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    font-size: 0.92rem;
    color: var(--graphite);
}
.year-slider-track-wrap {
    position: relative;
    width: 240px;
    height: 24px;
    flex: 0 0 auto;
}
.year-slider-track {
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    height: 4px;
    margin-top: -2px;
    background: var(--line);
    border-radius: var(--r-xs);
}
.year-slider-fill {
    position: absolute;
    top: 0;
    height: 100%;
    background: var(--teal-text);
    border-radius: var(--r-xs);
}
.year-slider-input {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    background: transparent;
    -webkit-appearance: none;
    appearance: none;
    pointer-events: none;  /* clicks pass through except on the thumb */
}
.year-slider-input::-webkit-slider-runnable-track {
    background: transparent;
    border: none;
    height: 4px;
}
.year-slider-input::-moz-range-track {
    background: transparent;
    border: none;
    height: 4px;
}
.year-slider-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    pointer-events: auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--blue);
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    cursor: grab;
    margin-top: -6px;     /* center the 16px thumb on the 4px track */
    transition: background-color 0.12s, transform 0.12s;
}
.year-slider-input::-moz-range-thumb {
    pointer-events: auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--blue);
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
    cursor: grab;
}
.year-slider-input:hover::-webkit-slider-thumb { background: var(--blue-d); }
.year-slider-input:hover::-moz-range-thumb     { background: var(--blue-d); }
.year-slider-input:active::-webkit-slider-thumb { cursor: grabbing; transform: scale(1.1); }
.year-slider-input:active::-moz-range-thumb     { cursor: grabbing; transform: scale(1.1); }
.year-slider-input:focus-visible::-webkit-slider-thumb {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.year-slider-input:focus-visible::-moz-range-thumb {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.year-slider-value {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.86rem;
    color: var(--blue);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 92px;
    white-space: nowrap;   /* keep "1992 – 2025" on one line between the stepper pairs */
    text-align: center;
}

.filter-helper {
    font-size: 0.82rem;
    color: var(--slate);
    font-style: italic;
    margin-left: 8px;
}

/* Reset-filters action row */
.filter-actions {
    justify-content: flex-end;
    border-top: 1px solid var(--line);
    padding-top: 14px;
    margin-top: 4px;
}
.reset-btn {
    font: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--blue);
    background: transparent;
    border: 1.5px solid var(--blue);
    border-radius: var(--r-pill);
    padding: 5px 16px;
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s;
}
.reset-btn:hover {
    background: var(--blue);
    color: #fff;
}
.reset-btn:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

/* Layer 2 - recent named grantees list shown below Layer 1.
   Per-grantee row is two lines: year + name on the first line
   (mono year, bold name), field/host/city on the second (slate). */
.recent-grantees {
    margin-top: 22px;
    /* Two grantee-type tables sit side-by-side (Foreign Student | FLTA) via
       --dual; a single type falls back to one full-width column on the left. */
    display: grid;
    grid-template-columns: 1fr;
    gap: 22px 24px;
    align-items: start;
}
.recent-grantees--dual { grid-template-columns: 1fr 1fr; }
.recent-grantees-section {
    margin: 0;
    min-width: 0;   /* let the grid cell shrink so rows wrap instead of overflowing */
}
.recent-grantees-section:last-child { margin-bottom: 0; }
.recent-grantees-head {
    color: var(--blue);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin-bottom: 6px;
    margin-top: 6px;
}

/* Heatmap section inside each chart card (right panel). Sits below
   the chart's legend and above the next card; sticky-positioned
   panel keeps it visible while the user scrolls the recent-grantees
   list on the left. */
.breakdown-heatmap {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px dashed var(--teal-100);
}
.breakdown-heatmap-head {
    color: var(--teal-text);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin: 0 0 8px;
}
.breakdown-heatmap .byschool-state-grid {
    margin: 0;
}

/* =====================================================================
 *  State map — SHARED look. The Explore destination heatmap and the
 *  by-school clickable filter now render the SAME markup
 *  (`.byschool-state-grid` / `.byschool-state-tile`, defined ONCE in the
 *  by-school section far below) and the SAME geometry (state-map.js).
 *  The duplicate `.state-heatmap` / `.state-tile*` appearance + grid
 *  rules that used to live here were removed in the unification refactor
 *  so the two maps can never visually drift. Only Explore's DISTINCT
 *  floating tooltip remains, under the `.state-heatmap-tooltip*` names
 *  below (the by-school map has no such tooltip — it opens an info
 *  popup instead).
 * ===================================================================== */

/* Tooltip floats over the page; positioned by JS using clientX/Y. */
.state-heatmap-tooltip {
    position: absolute;
    background: var(--ink);
    color: #fff;
    font-size: 0.75rem;
    padding: 8px 11px;
    border-radius: var(--r-sm);
    box-shadow: 0 3px 10px rgba(27, 35, 44, 0.25);
    z-index: 100;
    /* Clamp to the viewport so it never exceeds a phone screen (F52). */
    max-width: min(320px, calc(100vw - 24px));
    pointer-events: none;
    line-height: 1.4;
}
.state-heatmap-tooltip[hidden] { display: none; }
.state-heatmap-tooltip-head {
    font-weight: 700;
    font-size: 0.78rem;
    color: var(--teal-50);
    border-bottom: 1px solid rgba(255, 255, 255, 0.18);
    padding-bottom: 4px;
    margin-bottom: 5px;
}
.state-heatmap-tooltip-line {
    font-size: 0.72rem;
    margin-bottom: 2px;
    line-height: 1.4;
}
.state-heatmap-tooltip-year {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.55);
    font-weight: 600;
}
.state-heatmap-tooltip-names {
    color: rgba(255, 255, 255, 0.85);
}
.state-heatmap-tooltip-school {
    color: var(--school-color, rgba(255, 255, 255, 0.78));
    font-weight: 600;
    /* Brand colors are saturated and were tuned for white backgrounds;
       on dark we add a tiny brighten via mix-blend-mode so darker
       hues (Yale navy, etc.) don't disappear into the ink chip. */
    mix-blend-mode: screen;
}
.state-heatmap-tooltip-more {
    font-size: 0.7rem;
    font-style: italic;
    color: rgba(255, 255, 255, 0.6);
    margin-top: 3px;
}
/* Scrollable list wrapper - caps height so a 100+ grantee list
   doesn't push the page off-screen. Soft top/bottom shadows would
   indicate scrollability but we keep it minimal here. */
.recent-grantees-list-wrap {
    max-height: 420px;
    overflow-y: auto;
    overflow-x: hidden;            /* no horizontal scrollbar — long rows wrap instead */
    container-type: inline-size;   /* @container: rows stack when THIS column is narrow (2-up) */
    margin-top: 4px;
    padding-right: 4px;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
}
.recent-grantees-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.recent-grantees-item {
    padding: 10px 0;
    border-bottom: 1px solid var(--soft);
}
.recent-grantees-item:last-child { border-bottom: none; }
.recent-grantees-line1 {
    display: flex;
    gap: 10px;
    align-items: baseline;
    font-size: 0.98rem;
}
.recent-grantees-year {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.82rem;
    color: var(--teal-text);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}
.recent-grantees-name {
    font-weight: 600;
    color: var(--ink);
}
.recent-grantees-line2 {
    margin-top: 3px;
    margin-left: 46px;   /* aligns with name (year + gap = ~46px) */
    font-size: 0.88rem;
    color: var(--slate);
    line-height: 1.45;
}
/* F50: drop the 46px alignment indent on phones, where it eats
   ~13% of a 360-390px row and forces earlier wraps in a long list. */
@media (max-width: 560px) {
    .recent-grantees-line2 { margin-left: 0; }
}
/* Major: bold teal so the field-of-study scans first. */
.recent-grantees-major {
    font-weight: 600;
    font-style: italic;   /* #5 gloss, propagated to the recent-grantees list */
    color: var(--teal-text);
}
/* School: linked + colored with that school's brand color via
   --school-color set inline per row. Underline only on hover so
   the brand color reads as the primary signal. */
.recent-grantees-school {
    color: var(--school-color, var(--teal-text));
    font-weight: 600;
    text-decoration: none;
}
a.recent-grantees-school:hover,
a.recent-grantees-school:focus-visible {
    text-decoration: underline;
    text-decoration-thickness: 1.5px;
    text-underline-offset: 2px;
}
.recent-grantees-city {
    color: var(--slate);
    font-style: italic;
}
a.recent-grantees-city {
    text-decoration: none;
    border-bottom: 1px dotted var(--mist);
}
a.recent-grantees-city:hover,
a.recent-grantees-city:focus-visible {
    color: var(--graphite);
    border-bottom-color: var(--graphite);
    border-bottom-style: solid;
}

/* Trust line under filters / future text input */
.trust-line {
    margin: 18px 4px 0;
    font-size: 0.82rem;
    color: var(--slate);
    text-align: center;
    line-height: 1.5;
}

/* ============================================================ */
/*  Field-family detail panel (Phase 2c)                         */
/*                                                                */
/*  Sits in the right margin alongside main on wide viewports.   */
/*  Hidden below 1280px (see media query at end of file). On     */
/*  wide viewports, position:sticky keeps the panel visible as   */
/*  the user scrolls through long Layer 1 / Layer 2 content;     */
/*  internal overflow-y handles many-table stacks.               */
/* ============================================================ */
/* The right-side panels (field-detail and region-countries) render
   inline below main on narrow viewports, then move into the sticky
   side-rail at >=1280px (see Wide-viewport grid block below). The
   :empty rule collapses them when they have no content. */
.field-detail-panel,
.region-countries-panel {
    display: block;
}
.field-detail-panel:empty,
.region-countries-panel:empty { display: none; }

/* Narrow-viewport side-rail layout: a stacked container below main
   that matches main's max-width + side padding so the cards line up.
   The grid + sticky behavior at >=1280px overrides this. */
.side-rail {
    max-width: var(--page-max);   /* matches main (F45) */
    margin: 0 auto;
    padding: 0 24px 32px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.region-countries-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 20px 20px 18px;
    box-shadow: var(--shadow-2);
}
.region-countries-title {
    color: var(--blue);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-bottom: 4px;
}
.region-countries-subtitle {
    color: var(--slate);
    font-size: 0.74rem;
    margin-bottom: 12px;
    /* Be Vietnam, not SF Mono (F42) — this is a prose subtitle, not
       aligned tabular data. tabular-nums keeps any digits even. */
    font-variant-numeric: tabular-nums;
}
.region-countries-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    /* Two columns of countries. Auto rows so the list reads top-to-
       bottom in column 1 then column 2. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 12px;
    row-gap: 4px;
    grid-auto-flow: row;
    /* Cap height so the field-detail-panel above stays in view; the
       list scrolls internally for larger regions (Sub-Saharan = 44). */
    max-height: 360px;
    overflow-y: auto;
    padding-right: 4px;
}
.region-countries-item {
    min-width: 0;
}
.region-countries-link {
    display: flex;
    align-items: baseline;
    gap: 6px;
    color: var(--ink);
    text-decoration: none;
    font-size: 0.82rem;
    line-height: 1.4;
    padding: 2px 0;
    border-radius: var(--r-sm);
}
.region-countries-link:hover .region-countries-name,
.region-countries-link:focus-visible .region-countries-name {
    color: var(--blue);
    text-decoration: underline;
}
.region-countries-flag {
    flex: 0 0 auto;
    font-size: 0.95rem;
    /* Emoji fallback font keeps flags consistent on OSes that put
       flag glyphs in a separate font. */
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
.region-countries-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Breakdown card. The teal left accent + soft teal border give the
   card a brand-aligned look (teal #00B1AC + Be Vietnam) rather than
   the plain gray box it used to be. 10px radius matches the chip and
   filter card softness. */
.breakdown-table-wrap {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 20px 20px 18px;
    margin-bottom: 16px;
    box-shadow: var(--shadow-2);
}
.breakdown-table-wrap:last-child { margin-bottom: 0; }

.breakdown-title {
    color: var(--blue);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-bottom: 4px;
}
.breakdown-subtitle {
    color: var(--slate);
    font-size: 0.74rem;
    margin-bottom: 12px;
    /* Prose subtitle in Be Vietnam, not SF Mono (F42). */
    font-variant-numeric: tabular-nums;
}
.breakdown-empty {
    color: var(--slate);
    font-size: 0.84rem;
    font-style: italic;
}

/* Major-cluster table inside the breakdown card. Sits between the
   line chart legend and the state heatmap; one per active family. */
.cluster-table-wrap {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px dashed var(--teal-100);
}
.cluster-table-head {
    color: var(--teal-text);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin: 0 0 8px;
}
.cluster-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.82rem;
    line-height: 1.35;
}
.cluster-table thead th {
    text-align: left;
    font-weight: 600;
    color: var(--slate);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 4px 6px;
    border-bottom: 1px solid var(--teal-100);
}
.cluster-table thead th:not(:first-child) {
    text-align: right;
}
.cluster-table tbody td {
    padding: 4px 6px;
    border-bottom: 1px solid var(--soft);
    color: var(--ink);
}
.cluster-table tbody tr:last-child td { border-bottom: none; }
.cluster-table tbody tr:hover td { background: var(--paper-warm, #f9fbfa); }
.cluster-table-num {
    text-align: right;
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-variant-numeric: tabular-nums;
}
/* Sortable column headers: the th holds a reset button that inherits the
   header type styling; clicking sorts the rows. Active column tints teal and
   shows a direction arrow. */
.cluster-table thead th .cluster-sort-btn {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    background: none;
    border: 0;
    margin: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}
.cluster-table thead th.cluster-table-num .cluster-sort-btn { flex-direction: row-reverse; }
.cluster-table thead th .cluster-sort-btn:hover { color: var(--teal-text); }
.cluster-table thead th[aria-sort="ascending"] .cluster-sort-btn,
.cluster-table thead th[aria-sort="descending"] .cluster-sort-btn { color: var(--teal-text); }
.cluster-table thead th .cluster-sort-btn:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    border-radius: 2px;
}
.cluster-sort-arrow {
    font-size: 0.9em;
    line-height: 1;
    min-width: 0.6em;
}
/* Single descriptive caption for the unified majors-by-family table.
   Replaces the old per-family <h4> headings; styled to match the teal
   uppercase label they used (.cluster-table-head). */
.cluster-table-caption {
    caption-side: top;
    text-align: left;
    color: var(--teal-text);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin: 0 0 8px;
}
/* Full-width family group-header rows inside the unified table. Carry
   the same teal label treatment so each family still reads as its own
   section, with a tinted band to set it off from the major rows. */
.cluster-table-groupcell {
    text-align: left;
    color: var(--teal-text);
    background: var(--teal-50);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 6px 6px;
    border-top: 1px solid var(--teal-100);
    border-bottom: 1px solid var(--teal-100);
}
/* The group-header band is not a data row; suppress the hover tint that
   the --datatable modifier applies to tbody rows. */
.cluster-table--datatable tbody tr.cluster-table-grouprow:hover td,
.cluster-table.cluster-table--datatable tbody tr.cluster-table-grouprow:hover th {
    background: var(--teal-50);
}

/* Combined families line chart - one line per selected major. Each
   line tracks the major's share of the geographic-scope's grantees
   across 5-year bins from 1976 to 2025, so the user can compare
   growth/decline trajectories on a single axis. The chart-wrap
   is the positioning anchor for the floating hover tooltip. */
.families-line-chart-wrap {
    position: relative;
    margin: 4px 0 10px;
}
.families-line-chart {
    display: block;
    width: 100%;
    height: auto;
}
.families-line-grid {
    stroke: var(--line);
    stroke-width: 0.5;
}
.families-line-axis {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 8.5px;
    fill: var(--slate);
}

/* Per-line hover state. When a family is hovered (line, dot, or its
   matching legend item), every other line/dot fades to ~18% opacity
   so the focus reads cleanly. The hovered line gets a thicker stroke
   for an extra-visible cue. */
.families-line-path,
.families-line-dot {
    transition: opacity 0.12s, stroke-width 0.12s, r 0.12s;
}
.families-line-path.is-faded,
.families-line-dot.is-faded {
    opacity: 0.18;
}
.families-line-path.is-active {
    stroke-width: 2.6;
}
.families-line-dot.is-active {
    r: 3.5;
}

/* Floating tooltip anchored to the chart-wrap. Positioned absolutely
   relative to the wrap (set via inline style from the JS hover handler). */
.families-line-tooltip {
    position: absolute;
    background: var(--ink);
    color: #fff;
    font-size: 0.74rem;
    font-weight: 500;
    padding: 4px 9px;
    border-radius: var(--r-sm);
    pointer-events: none;
    white-space: nowrap;
    z-index: 10;
    box-shadow: 0 2px 6px rgba(27, 35, 44, 0.18);
}
.families-line-tooltip[hidden] { display: none; }
.families-line-tooltip-family {
    font-weight: 600;
}
.families-line-tooltip-stats {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.75);
}

/* Legend at the bottom. Hovering a line dims other items; hovering
   a legend item also pings the line via setActive() in JS. */
.families-line-legend {
    display: flex;
    flex-wrap: wrap;
    column-gap: 12px;
    row-gap: 5px;
    margin: 2px 0 0;
    font-size: 0.72rem;
    color: var(--ink);
}
.families-line-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    cursor: pointer;
    transition: opacity 0.12s;
}
.families-line-legend.has-active .families-line-legend-item {
    opacity: 0.25;
}
.families-line-legend.has-active .families-line-legend-item.is-active {
    opacity: 1;
}
.families-line-legend-swatch {
    display: inline-block;
    width: 16px;
    height: 3px;
    border-radius: 1px;
    flex-shrink: 0;
}
.families-line-legend-swatch.is-dashed {
    background-color: transparent !important;
    border-top: 2px dashed currentColor;
    height: 0;
}

/* ============================================================ */
/*  Colophon (print-style footer)                                */
/* ============================================================ */
.colophon {
    max-width: var(--page-max);   /* aligns with main/by-name (F45) */
    margin: 0 auto;
    padding: 0 24px 48px;
    color: var(--slate);
    font-size: 0.84rem;
    line-height: 1.55;
}
.colophon p {
    margin-bottom: 12px;
}
.colophon-link {
    color: var(--teal-text);
    font-weight: 500;
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    text-decoration: none;
    border-bottom: 1px dotted var(--teal-text);
}
.colophon-link:hover,
.colophon-link:focus-visible {
    color: var(--teal-900);
    border-bottom-style: solid;
}
.colophon .meta-line {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.78rem;
    color: var(--mist);
    border-top: 1px solid var(--line);
    padding-top: 14px;
}

/* ============================================================ */
/*  Responsive - collapse hero to single column under 720px     */
/*  Single consolidated mobile-hero breakpoint (F48/F49). Both    */
/*  the mark and the tagline are taken OUT of absolute            */
/*  positioning here (position:static) so they actually flow into */
/*  the grid rows below instead of piling onto the title.         */
/* ============================================================ */
@media (max-width: 720px) {
    /* Five explicit rows: mark, tagline, title, tree, then the nav row.
       Every hero child is placed by hand here. The earlier bug: only 4
       rows were declared and .hero-bottom (the nav tabs + snapshot date)
       had no grid-row, so CSS auto-placed it into row 1 — piling the
       tabs on top of the tagline ("Overv-iew-le."). Giving .hero-bottom
       its own row 5 removes the overlap. */
    .hero {
        display: grid;
        grid-template-columns: minmax(0, 1fr);   /* NOT 1fr (=minmax(auto,1fr)): the
            content-sized minimum let the segmented nav / long h1 word blow the
            column past the viewport on by-school + by-name. minmax(0,…) caps it. */
        grid-template-rows: auto auto auto auto auto;
        padding: 48px 32px 56px;
        min-height: auto;
        row-gap: 18px;
    }
    .hero-frame {
        top: 20px; right: 20px; bottom: 20px; left: 20px;
    }
    /* De-absolute the mark and reflow it as the first grid row in the
       hero's top-left. With it static here it can no longer share
       pixels with the eyebrow (which is in .hero-title, row 3). */
    .hero-mark {
        position: static;
        grid-column: 1;
        grid-row: 1;
        justify-self: start;
        height: 40px;
        margin-bottom: 0;
    }
    /* De-absolute the tagline and stack it as its own grid row, so it
       can never overlap the eyebrow/title/wordmark at 360/390/414px. */
    .hero-tagline {
        position: static;
        grid-column: 1;
        grid-row: 2;
        justify-self: start;
        text-align: left;
        max-width: none;
        font-size: 1.1rem;
    }
    /* Mobile hero is a flat teal band (no banner art), so the tagline's
       white text was 2.66:1. Ink on --teal is 5.96:1 and stays on-brand
       (teal + ink). Desktop keeps white over the artwork. */
    .hero-tagline span { display: inline; color: var(--ink); }
    .hero-tagline span:nth-child(1) { padding-right: 0; padding-left: 0; }
    .hero-tagline span:nth-child(2) { padding-right: 0; padding-left: 0; }
    .hero-tagline span:nth-child(3) { padding-right: 0; padding-left: 0; }
    .hero-title {
        grid-column: 1;
        grid-row: 3;
        max-width: none;
        align-self: auto;
        padding-top: 0;   /* mark is in its own row now; no clearance needed */
    }
    .hero-tree {
        grid-column: 1;
        grid-row: 4;
        min-height: 180px;
        justify-self: stretch;
        background-position: center bottom;
    }
    /* Explicitly pin the nav row last so it can never auto-place onto the
       tagline. Stack the tabs and the snapshot date instead of spreading
       them, so neither wraps into the other on a narrow screen. */
    .hero-bottom {
        grid-column: 1;
        grid-row: 5;
        margin-top: 4px;
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }
    /* The segmented nav is content-sized (inline-flex ~350px), which together
       with the capped column would otherwise clip the active pill on the right.
       Make the HERO nav fill the column with three equal, shrinkable tabs; the
       label text wraps inside each pill exactly as "By name" already does.
       Scoped to .hero-bottom so the sticky nav keeps its compact layout. */
    .hero-bottom .hero-tabs--segmented { display: flex; width: 100%; }
    .hero-bottom .hero-tabs--segmented a {
        flex: 1 1 0;
        min-width: 0;
        justify-content: center;
        text-align: center;
        padding: 8px 10px;
    }
    main { padding: 32px 20px 48px; }
    .layer-1 { padding: 24px 22px; }
}

/* ============================================================ */
/*  Wide-viewport grid: main + side-rail side-by-side             */
/*                                                                */
/*  Breakpoint: 1280px. Above this the page becomes a 2-column   */
/*  grid (60% main / 40% side-rail, 24px gap, 1440px max          */
/*  centered). The side-rail stacks the region-countries box      */
/*  above the field-family breakdown box; both hide themselves    */
/*  when empty. Below the breakpoint the rail is hidden entirely  */
/*  and main keeps its original 960px centered layout.            */
/* ============================================================ */
@media (min-width: 1280px) {
    .app-shell {
        max-width: var(--page-max-wide);   /* F45 */
        margin: 0 auto;
        padding: 48px 24px 64px;
        display: grid;
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
        column-gap: 24px;
        align-items: start;
    }
    .app-shell main {
        max-width: none;
        margin: 0;
        padding: 0;
    }
    .side-rail {
        max-width: none;
        margin: 0;
        padding: 0 4px 0 0;   /* small right pad for scrollbar */
        position: sticky;
        top: 24px;
        max-height: calc(100vh - 48px);
        overflow-y: auto;
    }
}

/* ============================================================ */
/*  By-name page                                                  */
/*  /find-a-grantee/by-name/                                      */
/* ============================================================ */

.byname-app {
    max-width: var(--page-max);   /* shared narrow width (F45) */
    margin: 0 auto;
    padding: 32px 24px 64px;
}

.byname-search {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 24px;
    margin-bottom: 24px;
    box-shadow: var(--shadow-1);   /* unified input-surface lift (F44) */
}
.byname-search-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 600px) {
    .byname-search-grid { grid-template-columns: 1fr; }
}
.byname-search-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.byname-search-label {
    /* Default field eyebrow standardized to blue (F43) so the same UI
       primitive isn't blue on Explore but teal here; teal stays
       reserved as a meaningful accent. */
    color: var(--blue);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.byname-search-field input {
    font: inherit;
    font-size: 1.05rem;
    padding: 10px 14px;
    border: 1.5px solid var(--mist);
    border-radius: var(--r-md);
    background: #fff;
    color: var(--ink);
    transition: border-color 0.12s;
}
.byname-search-field input:focus { border-color: var(--teal-text); }
.byname-search-field input:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 1px;
    border-color: var(--teal-text);
}
.byname-search-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 14px;
    font-size: 0.85rem;
    color: var(--graphite);
}
.byname-count strong { color: var(--blue); }
.byname-actions { display: flex; gap: 8px; }
.byname-link-btn {
    background: none;
    border: 1px solid var(--teal-100);
    color: var(--teal-text);
    font: inherit;
    font-size: 0.85rem;
    padding: 4px 12px;
    border-radius: var(--r-xl);
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.byname-link-btn:hover { background: var(--teal); color: #fff; border-color: var(--teal); }
.byname-helper {
    font-size: 0.78rem;
    color: var(--slate);
    margin-top: 10px;
    line-height: 1.5;
}
.byname-helper strong { color: var(--ink); }
.byname-helper em { color: var(--teal-text); font-style: normal; }

/* Default state: surname wall + common-surnames card + by-the-numbers */
.byname-default-loading {
    text-align: center;
    padding: 40px 0;
    color: var(--slate);
    font-style: italic;
}
.byname-default-grid {
    display: grid;
    /* Single row, three equal columns: wall · common surnames · by-the-
       numbers. Top-aligned so cards keep their natural heights. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: start;
    gap: 24px;
}
@media (max-width: 1100px) {
    /* Two columns: wall keeps its space on row 1, surnames + stats
       sit on row 2. */
    .byname-default-grid { grid-template-columns: 1fr 1fr; }
    .byname-default-wall { grid-column: 1 / -1; }
}
@media (max-width: 700px) {
    .byname-default-grid { grid-template-columns: 1fr; }
    .byname-default-wall { grid-column: auto; }
}
.byname-default-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 24px;
    min-width: 0;  /* let the grid track shrink past content width */
    box-shadow: var(--shadow-2);
}
.byname-default-title {
    color: var(--blue);
    font-size: 0.9rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin: 0 0 4px;
}
.byname-default-sub {
    color: var(--slate);
    font-size: 0.84rem;
    margin: 0 0 18px;
}
.byname-letter-wall {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    /* Tighter gaps fit 26 letters comfortably in the narrower
       1/3-width column without forcing overflow into 3+ rows. */
    gap: 6px 10px;
    line-height: 1.1;
    padding: 4px 0;
}
.byname-letter {
    color: var(--teal-text);
    text-decoration: none;
    font-weight: 800;
    letter-spacing: -0.02em;
    transition: color 0.12s, transform 0.12s;
}
.byname-letter:hover { color: var(--blue); transform: translateY(-2px); }
.byname-letter.is-empty { color: var(--mist); cursor: default; pointer-events: none; }

/* When two walls are stacked in the same card (lens-country wall on
   top, worldwide wall below) the lens wall paints in blue so the two
   are visually distinct at a glance — teal for the global default,
   blue for the country-scoped lens. */
.byname-letter-wall-lens .byname-letter { color: var(--blue); }
.byname-letter-wall-lens .byname-letter:hover { color: var(--teal-text); }
.byname-wall-divider {
    border: 0;
    border-top: 1px dashed var(--line);
    margin: 18px 0 16px;
}

.byname-surname-list {
    list-style: none;
    margin: 0;
    padding: 0;
    /* Two columns (5 rows of 2 for the top-10 list) so the surnames
       card height matches the wall and the by-the-numbers cards in
       the same row. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px 8px;
}
@media (max-width: 700px) {
    .byname-surname-list { grid-template-columns: 1fr; }
}
.byname-surname-link {
    position: relative;   /* anchor for the magnitude bar (F53) */
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    color: var(--ink);
    text-decoration: none;
    border-radius: var(--r-md);
    font-weight: 600;
    overflow: hidden;     /* clip the bar to the row's rounded corners */
    transition: background 0.12s, color 0.12s;
}
.byname-surname-link:hover {
    background: var(--teal-50);
    color: var(--teal-text);
}
/* F53: horizontal magnitude bar behind each surname row, scaled to
   top surname = 100% (width set inline in JS). Renders the dominant-
   surname story (Nguyen ≈ 5× Le) at a glance. Soft teal tint sits
   behind the text; name/count are lifted above it via z-index. */
.byname-surname-bar {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    background: var(--teal-50);
    border-radius: var(--r-md);
    z-index: 0;
    pointer-events: none;
}
.byname-surname-link:hover .byname-surname-bar {
    background: var(--teal-100);
}
/* F13: let the surname truncate with an ellipsis instead of widening
   the card on narrow viewports. */
.byname-surname-name {
    position: relative;
    z-index: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.byname-surname-count {
    position: relative;
    z-index: 1;
    flex-shrink: 0;       /* count pill never compresses (F13) */
    /* Tabular Be-Vietnam figures instead of SF Mono (F42) — keeps
       digit alignment without the developer-dashboard voice. */
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    color: var(--slate);
    background: var(--paper);
    padding: 2px 8px;
    border-radius: var(--r-lg);
}

.byname-stat-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 14px;
}
.byname-stat-list li { display: flex; flex-direction: column; }
.byname-stat-num {
    /* Be-Vietnam tabular figures instead of SF Mono (F42) — restores
       brand voice on these headline stats while keeping digit
       alignment. clamp() lets a 6-digit value shrink rather than
       overflow a single-column card at 360px (F51). */
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-size: clamp(1.2rem, 5vw, 1.6rem);
    color: var(--blue);
    font-weight: 800;
    line-height: 1.1;
    white-space: nowrap;
}
.byname-stat-label {
    font-size: 0.78rem;
    color: var(--slate);
    margin-top: 2px;
}

/* Results: card grid */
.byname-results-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 18px;
}
.byname-results-head h2 {
    color: var(--blue);
    font-size: 1.25rem;
    margin: 0;
}
.byname-results-head p {
    color: var(--slate);
    font-size: 0.85rem;
    margin: 0;
}
.byname-results-overflow {
    text-align: center;
    color: var(--slate);
    font-size: 0.85rem;
    font-style: italic;
    margin: 14px 0 0;
    padding: 10px;
    border-top: 1px dashed var(--teal-100);
}
.byname-card-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 14px;
}
.byname-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-md);   /* #5: brand-default 6px card radius */
    padding: 14px 18px;
    transition: border-color 0.12s, transform 0.12s, box-shadow 0.12s;
}
.byname-card:hover {
    border-color: var(--teal-100);
    transform: translateY(-1px);
    box-shadow: var(--shadow-2);
}
.byname-card-year {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.85rem;
    color: var(--teal-text);
    font-weight: 700;
    letter-spacing: 0.04em;
}
.byname-card-name {
    color: var(--ink);
    font-size: 1.1rem;
    font-weight: 700;
    margin: 2px 0 4px;
    line-height: 1.25;
}
.byname-card-country {
    font-size: 0.82rem;
    color: var(--slate);
    margin: 0 0 8px;
}
.byname-card-flag,
.byname-portrait-flag {
    /* Emoji-fallback stack keeps flags rendering as actual flags on
       systems where the default font has no flag glyphs (Win 7/8,
       some Linux distros). Matches the .region-countries-flag rule. */
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}

/* By-name card school logo — small mark next to the school link. */
.byname-card-logo {
    display: inline-block;
    width: 18px;
    height: 18px;
    object-fit: contain;
    vertical-align: -3px;
    margin-right: 6px;
    background: #fff;
    border-radius: var(--r-xs);
}

/* Brand icons (outline variant, brand blue) on the field + school-fallback
   lines, replacing the retired 📚 / 🏛 emoji. See assets/icons/README.md. */
.byname-card-ico {
    width: 16px;
    height: 16px;
    object-fit: contain;
    vertical-align: -3px;
    margin-right: 6px;
}

/* By-name three-column row: filter (50%) · majors (30%) · region (20%).
   Major + region panels each hide via :empty; :has() rules below
   reshape the grid so the filter always reclaims any freed width. */
.byname-filters-row {
    display: grid;
    grid-template-columns: 5fr 3fr 2fr;
    gap: 24px;
    align-items: start;
}
/* Both side panels empty → filter full width. */
.byname-filters-row:has(.byname-field-detail:empty):has(.region-countries-panel:empty) {
    grid-template-columns: 1fr;
}
/* Only majors empty (region still showing) → 80/20 split. */
.byname-filters-row:has(.byname-field-detail:empty):not(:has(.region-countries-panel:empty)) {
    grid-template-columns: 4fr 1fr;
}
/* Only region empty (majors still showing) → 70/30 split. */
.byname-filters-row:has(.region-countries-panel:empty):not(:has(.byname-field-detail:empty)) {
    grid-template-columns: 7fr 3fr;
}
@media (max-width: 900px) {
    .byname-filters-row,
    .byname-filters-row:has(.byname-field-detail:empty):has(.region-countries-panel:empty),
    .byname-filters-row:has(.byname-field-detail:empty):not(:has(.region-countries-panel:empty)),
    .byname-filters-row:has(.region-countries-panel:empty):not(:has(.byname-field-detail:empty)) {
        grid-template-columns: 1fr;
    }
}
/* Inside the narrow 20% column, force the country grid to a single
   column so names like "Mozambique" / "South Sudan" don't truncate. */
.byname-filters-row .region-countries-grid {
    grid-template-columns: 1fr;
}

/* By-name major breakdown section. One .breakdown-table-wrap card per
   active field family. The cards stack vertically inside the row's
   30% column. Hidden when no field family chips are toggled. */
.byname-field-detail {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;  /* let the grid track shrink past content width */
}
.byname-field-detail:empty { display: none; }
.byname-field-detail .breakdown-table-wrap { margin-bottom: 0; }
/* #5 gloss in the brand's own face: the field of study set in italic
   Be Vietnam, distinct from the body text without a second typeface.
   (Source Serif 4 was swapped out for the brand face per request.) */
.byname-card-major {
    color: var(--teal-text);
    font-style: italic;
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0 0 4px;
}
.byname-card-school { font-size: 0.85rem; margin: 0; }
.byname-card-school a {
    color: var(--school-color, var(--teal-text));
    text-decoration: none;
    font-weight: 600;
    border-bottom: 1px dotted currentColor;
}
.byname-card-school a:hover { border-bottom-style: solid; }
.byname-card-where { color: var(--slate); font-weight: 400; }

/* Portrait: single-match oversized treatment */
.byname-portrait {
    background: var(--paper);
    border: 1px solid var(--teal-100);
    border-left: 6px solid var(--portrait-color, var(--teal));
    border-radius: var(--r-xl);
    padding: 40px 48px;
    max-width: 720px;
    margin: 0 auto;
    box-shadow: var(--shadow-3);
}
@media (max-width: 600px) {
    .byname-portrait { padding: 28px 24px; }
}
.byname-portrait-eyebrow {
    color: var(--teal-text);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin: 0 0 8px;
}
.byname-portrait-name {
    color: var(--ink);
    font-size: clamp(2rem, 4vw, 2.8rem);
    font-weight: 800;
    line-height: 1.1;
    margin: 0 0 8px;
    letter-spacing: -0.01em;
}
.byname-portrait-from {
    color: var(--graphite);
    font-size: 1.1rem;
    margin: 0 0 28px;
}
.byname-portrait-from strong { color: var(--blue); }
.byname-portrait-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 16px 24px;
    padding: 18px 0;
    border-top: 1px dashed var(--teal-100);
    border-bottom: 1px dashed var(--teal-100);
    margin-bottom: 24px;
}
.byname-portrait-label {
    display: block;
    color: var(--slate);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 4px;
}
.byname-portrait-val {
    display: block;
    color: var(--ink);
    font-size: 1.05rem;
    font-weight: 600;
}
.byname-portrait-school-link {
    color: var(--portrait-color);
    font-size: 1.4rem;
    font-weight: 700;
    text-decoration: none;
    border-bottom: 2px solid currentColor;
}
.byname-portrait-where {
    color: var(--slate);
    font-size: 0.95rem;
    margin: 4px 0 0;
}
.byname-portrait-host-link a {
    color: var(--blue);
    font-size: 0.85rem;
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
}
.byname-portrait-host-link a:hover { border-bottom-style: solid; }

/* Empty state */
.byname-empty {
    text-align: center;
    padding: 60px 24px;
    background: var(--paper);
    border: 1px dashed var(--line);
    border-radius: var(--r-lg);
}
.byname-empty-title {
    color: var(--blue);
    font-size: 1.3rem;
    margin: 0 0 8px;
}
.byname-empty-sub {
    color: var(--slate);
    font-size: 0.95rem;
    margin: 0;
    line-height: 1.55;
}
.byname-empty-sub em { color: var(--ink); font-style: normal; font-weight: 600; }

.byname-error {
    color: #b00020;
    background: #fef1f4;
    padding: 14px 18px;
    border-radius: var(--r-md);
    font-size: 0.92rem;
}


/* ============================================================ */
/*  By-school page                                                */
/*  /find-a-grantee/by-school/                                    */
/* ============================================================ */

.byschool-app {
    max-width: var(--page-max-wide);   /* dense page → wide width (F45) */
    margin: 0 auto;
    padding: 32px 24px 64px;
}

/* Command bar */
.byschool-cmd {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-1);   /* unified input-surface lift (F44) */
    padding: 18px 22px;
    margin-bottom: 24px;
}
.byschool-cmd-row {
    display: flex;
    flex-wrap: wrap;
    gap: 14px 18px;
    align-items: end;
}
.byschool-cmd-row + .byschool-cmd-row { margin-top: 14px; }
.byschool-search-field, .byschool-filter-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* 100% basis so the two fields always stack on their own rows
       (search above, country lens below) rather than sharing a row
       in the narrow ~60% cmd column. */
    flex: 1 1 100%;
}
.byschool-search-label {
    /* Default field eyebrow → blue (F43), matching Explore + by-name. */
    color: var(--blue);
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.byschool-search-field input, .byschool-filter-field select {
    font: inherit;
    font-size: 0.95rem;
    padding: 8px 12px;
    border: 1.5px solid var(--mist);
    border-radius: var(--r-md);
    background: #fff;
    color: var(--ink);
}
.byschool-search-field input:focus, .byschool-filter-field select:focus {
    border-color: var(--teal-text);
}
.byschool-search-field input:focus-visible,
.byschool-filter-field select:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 1px;
    border-color: var(--teal-text);
}
.byschool-cmd-row-sort { gap: 8px; align-items: center; }
.byschool-sort-label {
    color: var(--slate);
    font-size: 0.82rem;
    font-weight: 600;
    margin-right: 4px;
}
.byschool-sort-btn {
    background: #fff;
    border: 1px solid var(--mist);
    color: var(--ink);
    font: inherit;
    font-size: 0.82rem;
    padding: 5px 12px;
    border-radius: var(--r-xl);
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.byschool-sort-btn:hover {
    border-color: var(--teal-text);
    color: var(--teal-text);
}
.byschool-sort-btn.is-active {
    background: var(--blue);
    color: #fff;
    border-color: var(--blue);
}
.byschool-cmd-meta {
    margin-top: 12px;
    font-size: 0.85rem;
    color: var(--graphite);
}
.byschool-cmd-meta strong { color: var(--blue); }

/* Wall */
.byschool-wall {}
.byschool-wall-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 12px;
    grid-auto-flow: row dense;
}
@media (max-width: 1180px) {
    .byschool-wall-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
    .byschool-wall-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 480px) {
    .byschool-wall-grid { grid-template-columns: 1fr; }
}

.byschool-tile {
    position: relative;
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--bg, #5A6878);
    color: var(--fg, #fff);
    transition: transform 0.12s, box-shadow 0.12s;
    box-shadow: var(--shadow-2);
    /* Hug the (compact) content: the decade bar is pinned to the tile bottom
       (margin-top:auto), so min-height above the content height is what shows up
       as a gap between the stats and the bar. Keep just enough for the tier
       hierarchy; tiles with 2-line names grow past this floor naturally. */
    min-height: 104px;
    display: flex;
    flex-direction: column;
}
.byschool-tile:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-3);
}
.byschool-tile.is-tier-xl { grid-column: span 3; min-height: 124px; }
.byschool-tile.is-tier-l  { grid-column: span 2; min-height: 112px; }
.byschool-tile.is-tier-m  { grid-column: span 1; min-height: 104px; }
.byschool-tile.is-tier-s  { grid-column: span 1; min-height: 92px; }
@media (max-width: 1180px) {
    .byschool-tile.is-tier-xl { grid-column: span 2; }
    .byschool-tile.is-tier-l  { grid-column: span 2; }
}
@media (max-width: 760px) {
    .byschool-tile.is-tier-xl,
    .byschool-tile.is-tier-l { grid-column: span 2; }
}
@media (max-width: 480px) {
    .byschool-tile.is-tier-xl,
    .byschool-tile.is-tier-l { grid-column: span 1; }
}
.byschool-tile.is-open {
    grid-column: 1 / -1 !important;
    min-height: 200px;
    background: var(--paper);
    color: var(--ink);
    border: 1px solid var(--teal-100);
    border-left: 4px solid var(--bg);
}

.byschool-tile-btn {
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    padding: 14px 16px 12px;
    cursor: pointer;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.byschool-tile-btn:focus-visible {
    /* Use the tile's resolved text color (--fg) — flips white-on-dark
       tile -> white outline, ink-on-light-tile -> ink outline. When
       open the tile bg is white and we override to blue below. */
    outline: 2px solid var(--fg);
    outline-offset: -3px;
}
.byschool-tile.is-open .byschool-tile-btn:focus-visible {
    outline-color: var(--blue);
}
.byschool-tile-headrow {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 2px;
}
.byschool-tile-logo {
    flex: 0 0 auto;
    /* +30% over the previous 28px (and per-tier sizes below). */
    width: 36px;
    height: 36px;
    object-fit: contain;
    background: #fff;
    border-radius: var(--r-sm);
    padding: 2px;
}
.is-tier-xl .byschool-tile-logo { width: 52px; height: 52px; }
.is-tier-l  .byschool-tile-logo { width: 44px; height: 44px; }
.is-tier-s  .byschool-tile-logo { width: 29px; height: 29px; padding: 1px; }
/* Name + motto stack to the right of the logo (the motto only renders in
   the open state — closed tiles stay compact). */
.byschool-tile-namecol { flex: 1 1 auto; min-width: 0; }
.byschool-tile-name {
    font-weight: 700;
    line-height: 1.18;
    font-size: 1.05rem;
    margin-bottom: 2px;
    min-width: 0;
}
.is-tier-xl .byschool-tile-name { font-size: 1.4rem; line-height: 1.15; }
.is-tier-l  .byschool-tile-name { font-size: 1.18rem; }
.is-tier-s  .byschool-tile-name { font-size: 0.92rem; }
/* Motto under the school name (open state), an italic serif pull-quote
   with a small teal quote mark — moved up from the old deep-dive header. */
.byschool-tile-motto {
    font-family: 'Source Serif 4', Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-size: 0.95rem;
    line-height: 1.4;
    color: var(--ink);
    margin: 3px 0 0;
    padding-left: 18px;
    position: relative;
}
.byschool-tile-motto::before {
    content: '\201C';
    position: absolute;
    left: 0;
    top: 0.02em;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 1.7rem;
    line-height: 0.9;
    color: var(--teal);
    opacity: 0.5;
    pointer-events: none;
}
/* School website link at the top of the open deep-dive panel (the link
   can't live inside the tile <button>). */
/* .byschool-deep-site retired: the open panel now pairs location + website on
   one line via .byschool-deep-loc / .byschool-deep-site-link (see below). */
/* Secondary tile lines: muted via the precomputed --fg-soft (solid, AA
   ≥4.5:1 against the tile bg) — NOT opacity, which alpha-blends the
   AA-passing --fg back toward the tile color (measured 3.3–4.4:1 across
   ~820 axe nodes). tileColors() in by-school/app.js owns the blend. */
/* Address now sits directly under the school name (inside the name column),
   not as a separate full-width row under the logo. */
.byschool-tile-where {
    font-size: 0.78rem;
    color: var(--fg-soft, inherit);
    margin: 1px 0 0;
}
/* One row: "N grantees · M from <country> · Top: <field> P%" — items
   flow inline with middot separators and wrap only if the tile is too
   narrow to hold them. */
.byschool-tile-stats {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 7px;
    /* Sit directly under the name/address block. (Was `margin-top: auto`, which
       pushed the stats to the card's min-height bottom and left a big empty band
       between the address and the stats.) The flexible spacer now lives on the
       sparkline so the decade bar stays pinned to the card footer. */
    margin-top: 6px;
    font-size: 0.82rem;
}
.byschool-tile-stats > * + *::before {
    content: "·";
    margin-right: 7px;
    color: var(--fg-soft, inherit);
    opacity: 0.7;
}
.byschool-tile-total { font-weight: 600; }
.byschool-tile-cc {
    font-size: 0.8rem;
    color: var(--fg-soft, inherit);
}
.byschool-tile-specialty {
    font-size: 0.78rem;
    color: var(--fg-soft, inherit);
}
.byschool-tile-share {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    color: var(--fg-soft, inherit);
    margin-left: 2px;
}
/* Open tile flips to paper bg + ink text (see .byschool-tile.is-open) —
   the brand-tinted --fg-soft would be unreadable there; use slate. */
.byschool-tile.is-open .byschool-tile-where,
.byschool-tile.is-open .byschool-tile-cc,
.byschool-tile.is-open .byschool-tile-specialty,
.byschool-tile.is-open .byschool-tile-share {
    color: var(--slate);
}
.byschool-tile-badge {
    /* Inline at the top of the tile content (was absolute top-right,
       which overlapped wrapped school names on smaller tiles). */
    display: inline-flex;
    align-items: center;
    gap: 3px;
    align-self: flex-start;
    margin: 0 0 6px;
    /* Invert the tile's own resolved (bg, fg) pair so the badge stays
       legible whether the tile color is dark (white text) or light
       (ink text). var(--fg) is the chosen text color = the badge bg. */
    background: var(--fg);
    color: var(--bg);
    font-size: 0.6rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: var(--r-md);
}
.byschool-tile.is-open .byschool-tile-badge {
    background: var(--bg);
    color: #fff;
}

.byschool-spark {
    display: flex;
    gap: 3px;
    /* Pin the decade bar to the card footer; absorbs the tile's spare height
       (the spacer that used to sit above the stats). */
    margin-top: auto;
    height: 6px;
    align-items: center;
}
.byschool-spark-cell {
    flex: 1;
    height: 6px;
    background: currentColor;
    border-radius: 1px;
}
.byschool-spark-cell.is-empty {
    background: currentColor;
    opacity: 0.15;
}
/* On the open/white deep-dive tile the tile sets color:var(--ink),
   so the spark cells (background:currentColor) render near-black —
   the single most off-brand mark on that view (F39). Recolor to
   teal on the open surface; empties to a faint teal tint. Closed
   colored tiles keep their white --fg cells unchanged. */
.byschool-tile.is-open .byschool-spark-cell {
    background: var(--teal);
}
.byschool-tile.is-open .byschool-spark-cell.is-empty {
    background: var(--teal-100);
    opacity: 1;
}

/* Deep dive (in-place accordion) */
.byschool-deep {
    padding: 0 24px 24px;
    color: var(--ink);
}
.byschool-deep-head {
    /* Only the sr-only panel heading lives here now (no close button), so
       this collapses to nothing. */
    padding: 0;
    min-height: 0;
}
.byschool-deep-name {
    font-size: 1.5rem;
    color: var(--blue);
    margin: 0 0 4px;
}
/* .byschool-deep-close removed: the school deep-dive no longer has a close
   button (the tile toggles itself closed, and Escape also closes it). */

/* M4: location + website paired on one line at the top of the deep panel. */
.byschool-deep-loc {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    margin: 0 0 6px;
    font-size: 0.85rem;
    color: var(--slate);
}
.byschool-deep-place { color: var(--slate); }
.byschool-deep-sep { color: var(--mist); }
.byschool-deep-site-link {
    color: var(--teal-text);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
}
.byschool-deep-site-link:hover { color: var(--teal-900); border-bottom-style: solid; }

.byschool-deep-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 14px;
    padding: 18px 0;
    margin: 14px 0;
    border-top: 1px dashed var(--teal-100);
    border-bottom: 1px dashed var(--teal-100);
}
.byschool-deep-stats > div { display: flex; flex-direction: column; }
.byschool-stat-num {
    /* Headline stat in Be Vietnam tabular figures, not SF Mono (F42). */
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    color: var(--blue);
    font-size: 1.4rem;
    font-weight: 800;
    line-height: 1.1;
}
.byschool-stat-label {
    color: var(--slate);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-top: 2px;
}

.byschool-deep-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    margin-bottom: 18px;
}
@media (max-width: 720px) {
    .byschool-deep-cols { grid-template-columns: 1fr; }
}
.byschool-deep-subhead {
    color: var(--teal-text);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin: 0 0 10px;
}
.byschool-deep-subhead-meta { color: var(--slate); font-weight: 500; }

.byschool-bar-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}
.byschool-bar {
    display: grid;
    grid-template-columns: minmax(110px, 30%) 1fr 44px;
    gap: 10px;
    align-items: center;
    font-size: 0.84rem;
}
.byschool-bar-label {
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.byschool-bar.is-lens .byschool-bar-label {
    color: var(--teal-text);
    font-weight: 700;
}
.byschool-bar-track {
    background: var(--soft);
    height: 12px;
    border-radius: var(--r-md);
    overflow: hidden;
}
.byschool-bar-fill {
    /* Brand teal (F11). Previously inherited the school's brand color
       via --bg (e.g. Syracuse orange) — an off-brand third accent on
       the open/white deep-dive tile. The two-color brand is teal +
       blue; the lens row stays blue (override below), so the table
       reads as teal bars with one blue lens bar — on-brand and still
       distinguishable. */
    background: var(--teal);
    height: 100%;
    border-radius: var(--r-md);
    display: block;
}
.byschool-bar.is-lens .byschool-bar-fill {
    background: var(--blue);
}
.byschool-bar-num {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.82rem;
    color: var(--graphite);
    text-align: right;
}

/* Combined origin table: one row per top-8 origin country, with a
   horizontal bar for the grantee count, an inline list of top majors
   that country sent to this school, and the most recent year. */
.byschool-deep-origin {
    margin-bottom: 18px;
}
.byschool-origin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.86rem;
}
.byschool-origin-table thead th {
    text-align: left;
    font-weight: 600;
    color: var(--slate);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 6px 10px;
    border-bottom: 1px solid var(--teal-100);
}
.byschool-origin-bar-h { width: 130px; }
.byschool-origin-year-h { width: 56px; text-align: right; }
/* Clickable column-sort headers (grantees / country / latest year). */
.byschool-origin-sort {
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}
.byschool-origin-sort:hover { color: var(--teal-text); }
.byschool-origin-sort:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    border-radius: 2px;
}
.byschool-origin-table th[aria-sort="ascending"] .byschool-origin-sort,
.byschool-origin-table th[aria-sort="descending"] .byschool-origin-sort { color: var(--teal-text); }
.byschool-sort-ind { font-size: 0.9em; line-height: 1; }
.byschool-origin-table tbody td {
    /* Tightened from 8px 10px → 4px 10px so each origin row eats
       less vertical space (8 rows fit in the same column height). */
    padding: 4px 10px;
    border-bottom: 1px solid var(--soft);
    vertical-align: middle;
}
.byschool-origin-table tbody tr:last-child td { border-bottom: none; }
.byschool-origin-country {
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
}
.byschool-origin-flag {
    /* Emoji-fallback stack so flags render even on systems whose
       default font has no flag glyphs. */
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
    margin-left: 4px;
    vertical-align: -1px;
}
.byschool-origin-row.is-lens {
    /* Lens-country row gets a soft blue background tint + left-edge
       accent so users immediately read it as "this is your country
       lens — the highlighted row is dynamic." */
    background: rgba(32, 85, 138, 0.07);
    box-shadow: inset 3px 0 0 var(--blue);
}
.byschool-origin-row.is-lens .byschool-origin-country {
    color: var(--blue);
    font-weight: 700;
}
.byschool-origin-row.is-lens .byschool-origin-year {
    color: var(--blue);
    font-weight: 700;
}
.byschool-origin-bar {
    /* Tight: just the 5-dot magnitude strip + the count. Was 32%, which left a
       huge gap before the Top-majors column. The majors cell (auto width) now
       reclaims that space. (Mobile stacks this onto its own grid row, where
       ~130px reads the same as the old 32%.) */
    width: 130px;
}
.byschool-origin-bar .byschool-bar-track {
    display: inline-block;
    width: calc(100% - 40px);
    vertical-align: middle;
    margin-right: 8px;
}
.byschool-origin-bar .byschool-bar-num {
    display: inline-block;
    vertical-align: middle;
    min-width: 30px;
}
.byschool-origin-row.is-lens .byschool-bar-fill { background: var(--blue); }
.byschool-origin-fields {
    color: var(--ink);
    line-height: 1.4;
}
.byschool-origin-fcount {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.78rem;
    color: var(--slate);
}
.byschool-origin-empty {
    color: var(--slate);
    font-size: 0.78rem;
    font-style: italic;
}
.byschool-origin-more {
    background: none;
    border: none;
    border-bottom: 1px dotted var(--teal);
    padding: 0;
    margin: 0;
    color: var(--teal-text);
    font: inherit;
    font-size: 0.78rem;
    font-style: italic;
    cursor: pointer;
}
.byschool-origin-more:hover,
.byschool-origin-more:focus-visible {
    color: var(--blue);
    border-bottom-style: solid;
    outline: none;
}

/* Floating popup card listing the remaining majors for a country
   when the user clicks "+N more". Absolutely positioned next to the
   button; one open at a time, closed by outside-click / Esc / scroll. */
.byschool-origin-popup {
    z-index: 1000;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 12px 14px;
    box-shadow: var(--shadow-3);
    /* Clamp to viewport on narrow screens (F52) — the +N more majors
       popup could otherwise approach full width at 360px. */
    max-width: min(320px, calc(100vw - 24px));
    max-height: 320px;
    overflow-y: auto;
}
.byschool-origin-popup-title {
    color: var(--blue);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin: 0 0 6px;
}
.byschool-origin-popup-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 0.84rem;
    color: var(--ink);
}
.byschool-origin-year {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.82rem;
    color: var(--graphite);
    text-align: right;
    white-space: nowrap;
}
@media (max-width: 700px) {
    /* On narrow viewports, drop the inline-majors cell beneath the
       country/bar row so each origin gets two stacked rows. */
    .byschool-origin-table,
    .byschool-origin-table thead,
    .byschool-origin-table tbody,
    .byschool-origin-table tr {
        display: block;
        width: 100%;
    }
    .byschool-origin-table thead { display: none; }
    .byschool-origin-table tbody tr {
        display: grid;
        grid-template-columns: 1fr auto;
        gap: 4px 12px;
        padding: 10px 0;
        border-bottom: 1px solid var(--soft);
    }
    .byschool-origin-table tbody td {
        padding: 0;
        border-bottom: none;
    }
    .byschool-origin-country { grid-column: 1; }
    .byschool-origin-year   { grid-column: 2; }
    .byschool-origin-bar    { grid-column: 1 / -1; }
    .byschool-origin-fields { grid-column: 1 / -1; font-size: 0.82rem; }
}

.byschool-deep-alumni {
    border-top: 1px dashed var(--teal-100);
    padding-top: 14px;
}
.byschool-alum-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 280px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-right: 6px;
}
.byschool-alum-list li {
    padding: 4px 8px;
    border-radius: var(--r-sm);
    font-size: 0.85rem;
    color: var(--ink);
}
.byschool-alum-list li:hover { background: var(--soft); }
.byschool-alum-year {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    color: var(--teal-text);
    font-weight: 700;
    margin-right: 8px;
}
.byschool-alum-name { font-weight: 600; }
.byschool-alum-field { color: var(--slate); font-style: italic; font-size: 0.8rem; }
.byschool-alum-more {
    color: var(--slate);
    font-size: 0.78rem;
    font-style: italic;
    margin: 8px 0 0;
}

.byschool-deep-empty {
    color: var(--slate);
    font-style: italic;
    text-align: center;
    padding: 20px;
    border-top: 1px dashed var(--teal-100);
    margin: 14px 0 0;
}

.byschool-empty, .byschool-error {
    text-align: center;
    padding: 60px 24px;
    color: var(--slate);
    font-style: italic;
}
.byschool-error { color: #b00020; }

/* Two-column filter row: cmd (search/sort) + family chips + major
   breakdown stacked in the left column; state heatmap fills the
   right column so it sizes down from the page-wide treatment that
   used to dominate. The major breakdown hides via :empty when no
   umbrella family is selected. */
.byschool-filters-row {
    display: grid;
    grid-template-columns: 3fr 2fr;
    grid-template-rows: auto auto auto;
    gap: 16px 24px;
    align-items: start;
    margin-bottom: 18px;
}
.byschool-filters-row .byschool-cmd          { grid-column: 1; grid-row: 1; min-width: 0; }
.byschool-filters-row .byschool-family-chips { grid-column: 1; grid-row: 2; min-width: 0; }
.byschool-filters-row .byschool-field-detail { grid-column: 1; grid-row: 3; min-width: 0; }
.byschool-filters-row .byschool-state-filter {
    grid-column: 2;
    grid-row: 1 / span 3;
    margin-bottom: 0;
    min-width: 0;
}
@media (max-width: 900px) {
    .byschool-filters-row {
        grid-template-columns: 1fr;
    }
    .byschool-filters-row .byschool-cmd,
    .byschool-filters-row .byschool-family-chips,
    .byschool-filters-row .byschool-field-detail,
    .byschool-filters-row .byschool-state-filter {
        grid-column: 1;
        grid-row: auto;
    }
}

/* By-school: per-family major breakdown. Cards stack vertically;
   the section hides itself via :empty. Reuses .breakdown-table-wrap
   and .cluster-table styles. */
.byschool-field-detail {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}
.byschool-field-detail:empty { display: none; }
.byschool-field-detail .breakdown-table-wrap { margin-bottom: 0; }

/* By-school: country-relevance pills above the wall. Five mutually
   exclusive buckets (most / moderate / twice / once / first) the
   user can toggle as additional filters. Multi-select. Hidden when
   no country lens is active. */
.byschool-relevance {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
    padding: 10px 14px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
}
.byschool-relevance:empty { display: none; }
.byschool-relevance-label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--blue);
}
.byschool-relevance-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    /* Force each strip onto its own row inside .byschool-relevance.
       The first strip sits next to "Quick filters:" label; the second
       wraps below since flex-basis 100% breaks the row. */
    flex: 1 1 100%;
}
.byschool-relevance-label + .byschool-relevance-strip {
    /* Reset the first strip so it can sit on the same row as the
       label rather than dropping below it. */
    flex: 1 1 auto;
}
.byschool-relevance-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--paper);
    border: 1.5px solid var(--teal-100);
    border-radius: var(--r-pill);
    color: var(--ink);
    font-size: 0.84rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s, transform 0.08s;
}
.byschool-relevance-pill:hover {
    border-color: var(--teal);
    background: var(--teal-50);
}
.byschool-relevance-pill.is-active {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
}
.byschool-relevance-pill.is-active .byschool-relevance-count {
    background: rgba(255, 255, 255, 0.25);
    color: #fff;
}
.byschool-relevance-pill:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.byschool-relevance-count {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.75rem;
    color: var(--slate);
    background: var(--soft);
    padding: 1px 8px;
    border-radius: var(--r-lg);
    line-height: 1.3;
}
/* "Be the first!" reads like an invitation. Moved OFF the retired-
   gold family (#e8b54a/#8a5a00/#fff4d6 sat right next to the dead
   #DAB978 palette — F41) and onto the brand teal: a soft teal-50
   wash + body-safe teal text, distinct from the blue active state. */
.byschool-relevance-pill.is-first:not(.is-active) {
    border-color: var(--teal);
    color: var(--teal-text);
}
.byschool-relevance-pill.is-first:not(.is-active):hover {
    background: var(--teal-50);
}
/* "Ivy League" — crimson accent so it reads as a distinct school-set
   filter, not a country-relevance bucket. Now via tokenized
   --accent-ivy (F41) rather than hard-coded literals. */
.byschool-relevance-pill.is-ivy:not(.is-active) {
    border-color: var(--accent-ivy);
    color: var(--accent-ivy);
}
.byschool-relevance-pill.is-ivy:not(.is-active):hover {
    background: var(--accent-ivy-50);
}
.byschool-relevance-pill.is-ivy.is-active {
    background: var(--accent-ivy);
    border-color: var(--accent-ivy);
}
/* Public / Private sector pills share the Ivy row but use slate
   accents so they read as a paired group, distinct from Ivy red. */
.byschool-relevance-pill.is-public:not(.is-active),
.byschool-relevance-pill.is-private:not(.is-active) {
    border-color: var(--graphite);
    color: var(--graphite);
}
.byschool-relevance-pill.is-public:not(.is-active):hover,
.byschool-relevance-pill.is-private:not(.is-active):hover {
    background: var(--soft);
}
.byschool-relevance-pill.is-public.is-active,
.byschool-relevance-pill.is-private.is-active {
    background: var(--graphite);
    border-color: var(--graphite);
}

/* State-map filter — 12x8 tile grid (same geometry as Explore's
   state heatmap, but clickable + uses the page-paper background so
   inactive tiles blend with the page when there's nothing to show). */
.byschool-state-filter {
    margin-bottom: 18px;
}
.byschool-state-row {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 16px 22px;
}
.byschool-state-header {
    margin: 0 0 12px;
}
.byschool-state-title {
    margin: 0 0 2px;
    color: var(--blue);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}
.byschool-state-subtitle {
    margin: 0;
    color: var(--slate);
    font-size: 0.78rem;
    line-height: 1.4;
}
.byschool-state-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 4px;
    width: 100%;
    max-width: 760px;
    margin: 0 auto 12px;
}
.byschool-state-tile {
    aspect-ratio: 1;
    min-width: 0;
    border: none;
    border-radius: var(--r-sm);
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: clamp(8px, 0.85vw, 11px);
    font-weight: 700;
    /* Continuous heatmap ramp drives the fill via these custom properties
       (set inline per tile from state-map.js rampColor). Using vars — not a
       direct background — lets the .is-active / .is-empty class rules below
       still win. Fallbacks keep un-ramped tiles neutral. */
    color: var(--tile-fg, var(--ink));
    background: var(--tile-bg, var(--soft));
    cursor: pointer;
    user-select: none;
    transition: transform 0.08s, outline-color 0.08s, background 0.08s;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Empty-tile label mist→slate for AA on soft (F38); is-high ground
   teal→teal-900 so the white abbreviation clears AA (F6). Mirrors the
   Explore heatmap buckets above. */
.byschool-state-tile.is-empty {
    color: var(--slate);
    background: var(--soft);
    cursor: default;
}
.byschool-state-tile.is-low  { background: var(--teal-50);  color: var(--graphite); }
.byschool-state-tile.is-med  { background: var(--teal-100); color: var(--teal-900); }
.byschool-state-tile.is-high { background: var(--teal-900); color: #fff; }
.byschool-state-tile:not(.is-empty):hover {
    transform: scale(1.15);
    outline: 1.5px solid var(--blue);
    z-index: 5;
    position: relative;
}
/* Explore-only cross-highlight: hovering a grantee row in the recent-
   grantees list highlights the matching tile in the heatmap. Folded into
   this shared tile rule set so it tracks the unified
   `.byschool-state-tile` class (was a separate `.state-tile.is-list-hover`
   rule before the maps were unified). Same treatment as :hover above so a
   hovered tile and a row-highlighted tile read identically. The
   by-school map never adds this class, so it's inert there. */
.byschool-state-tile.is-list-hover {
    transform: scale(1.15);
    outline: 1.5px solid var(--blue);
    z-index: 5;
    position: relative;
}
.byschool-state-tile.is-active {
    background: var(--blue);
    color: #fff;
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    z-index: 4;
    position: relative;
}
.byschool-state-tile:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.byschool-state-meta {
    text-align: center;
    font-size: 0.82rem;
    color: var(--slate);
}
.byschool-state-hint { font-style: italic; }
.byschool-state-clear {
    background: var(--blue);
    color: #fff;
    border: none;
    border-radius: var(--r-xl);
    font: inherit;
    font-size: 0.8rem;
    padding: 5px 14px;
    cursor: pointer;
}
.byschool-state-clear:hover { background: var(--blue-dark, #173f69); }

/* Touch-target sizing (F30). On coarse-pointer (touch) devices bump
   the chip / sort-button / relevance-pill hit areas toward the 44px
   comfortable target (and ≥24px AA-2.2 floor). State tiles get a
   min-height only — NOT min-width — because they live in a fixed
   12-col grid (max-width:760px) where a min-width would overflow the
   row and add horizontal scroll at the narrowest widths. */
@media (pointer: coarse) {
    .byschool-sort-btn { padding-top: 9px; padding-bottom: 9px; }
    .byschool-chip,
    .byschool-relevance-pill { padding-top: 9px; padding-bottom: 9px; }
    .chip { padding-top: 8px; padding-bottom: 8px; }
    .byschool-state-tile { min-height: 30px; }
}

/* Field-family + popular-major chip rows. */
.byschool-family-chips {
    margin-bottom: 18px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 14px 22px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.byschool-chip-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}
.byschool-chip-label {
    color: var(--blue);   /* default field eyebrow → blue (F43) */
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    flex: 0 0 auto;
    min-width: 100px;
}
.byschool-chip-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
/* Unified to the .chip convention (F40): --r-pill radius + teal-100
   idle border, matching the Explore/by-name chips and the relevance
   pills so the same control reads identically across all three pages. */
.byschool-chip {
    background: #fff;
    border: 1.5px solid var(--teal-100);
    color: var(--teal-text);
    font: inherit;
    font-size: 0.82rem;
    padding: 5px 12px;
    border-radius: var(--r-pill);
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.byschool-chip:hover {
    border-color: var(--teal-text);
    background: var(--teal-50);
}
.byschool-chip.is-active {
    background: var(--blue);
    color: #fff;
    border-color: var(--blue);
}

/* By-school year-range slider row inside the cmd column. Same
   widget shape as the Explore filter card; we just need to give the
   row label the same eyebrow treatment as the search-field labels. */
.byschool-cmd-row-year {
    align-items: center;
    gap: 14px;
}
.byschool-year-label {
    flex: 0 0 auto;
    color: var(--blue);   /* default field eyebrow → blue (F43) */
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.byschool-year-slider {
    flex: 1 1 auto;
    display: block;
}

/* ============================================================ */
/*  State info popover — opens beside the clicked state tile.   */
/*  Non-modal: no backdrop, page stays scrollable, click out    */
/*  or Esc closes. Anchored via JS to the trigger tile.         */
/* ============================================================ */
.byschool-state-popup {
    /* JS sets position/top/left after measuring the trigger. */
    position: absolute;
    z-index: 2000;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow-3);
    width: min(520px, calc(100vw - 24px));
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    padding: 18px 22px 16px;
    animation: byschool-state-rise 0.14s ease-out;
}
@keyframes byschool-state-rise {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes byschool-state-rise {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
.byschool-state-popup-close {
    position: absolute;
    top: 12px;
    right: 14px;
    background: transparent;
    border: none;
    font-size: 1.6rem;
    line-height: 1;
    color: var(--slate);
    cursor: pointer;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.byschool-state-popup-close:hover {
    background: var(--soft);
    color: var(--ink);
}
/* Visible brand focus ring on the dialog close button (a11y) — a
   background wash alone was a weak keyboard-focus signal. */
.byschool-state-popup-close:focus-visible {
    background: var(--soft);
    color: var(--ink);
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.byschool-state-popup-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
    padding-right: 28px;  /* room for the close button */
}
.byschool-state-popup-flag {
    /* Real SVG state flag served from Wikimedia Commons via
       Special:FilePath. ~40px wide, fixed height keeps the aspect
       ratio close to a 3:2 flag without distorting the actual
       proportions of each state's flag art. */
    flex: 0 0 auto;
    width: 40px;
    height: 28px;
    object-fit: contain;
    border-radius: var(--r-xs);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06);
    background: var(--paper);
}
.byschool-state-popup-title {
    margin: 0;
    font-size: 1.18rem;
    font-weight: 800;
    color: var(--blue);
    line-height: 1.2;
    flex: 1 1 auto;
}
.byschool-state-popup-title a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted var(--blue);
}
.byschool-state-popup-title a:hover,
.byschool-state-popup-title a:focus-visible {
    border-bottom-style: solid;
    outline: none;
}
.byschool-state-popup-wiki-ico {
    font-size: 0.85rem;
    color: var(--teal-text);
    margin-left: 2px;
}
.byschool-state-popup-abbr {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--teal-text);
    background: var(--paper);
    border: 1px solid var(--teal-100);
    padding: 2px 8px;
    border-radius: var(--r-pill);
    flex: 0 0 auto;
}
.byschool-state-popup-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    gap: 8px 12px;
    padding: 10px 12px;
    background: var(--teal-50);
    border-radius: var(--r-md);
    margin-bottom: 14px;
}
.byschool-state-popup-stat {
    display: flex;
    flex-direction: column;
}
.byschool-state-popup-num {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 1.15rem;
    color: var(--blue);
    font-weight: 700;
    line-height: 1.1;
}
.byschool-state-popup-label {
    font-size: 0.74rem;
    color: var(--slate);
    line-height: 1.3;
    margin-top: 2px;
}
.byschool-state-popup-section + .byschool-state-popup-fields,
.byschool-state-popup-fields {
    margin-top: 16px;
}
.byschool-state-popup-h3 {
    color: var(--blue);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin: 0 0 8px;
}
.byschool-state-popup-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.byschool-state-popup-list li {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 8px 10px;
    padding: 6px 10px;
    background: var(--paper);
    border: 1px solid var(--teal-100);
    border-radius: var(--r-md);
    font-size: 0.85rem;
}
.byschool-state-popup-school-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
}
.byschool-state-popup-school-name {
    color: var(--ink);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.byschool-state-popup-school-count {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.82rem;
    color: var(--graphite);
}
.byschool-state-popup-cc {
    font-size: 0.72rem;
    color: var(--teal-text);
    background: var(--teal-50);
    padding: 2px 8px;
    border-radius: var(--r-lg);
    white-space: nowrap;
}
.byschool-state-popup-chips {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.byschool-state-popup-chips li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: var(--paper);
    border: 1px solid var(--teal-100);
    border-radius: var(--r-pill);
    font-size: 0.78rem;
    color: var(--ink);
}
.byschool-state-popup-chip-num {
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 0.72rem;
    color: var(--slate);
}
.byschool-state-popup-empty {
    color: var(--slate);
    font-size: 0.84rem;
    font-style: italic;
    margin: 0;
}
.byschool-state-popup-actions {
    margin-top: 16px;
    display: flex;
    justify-content: stretch;
}
.byschool-state-popup-action {
    width: 100%;
    text-align: center;
}
.byschool-state-popup-action {
    background: var(--blue);
    color: #fff;
    border: none;
    border-radius: var(--r-pill);
    font: inherit;
    font-weight: 600;
    font-size: 0.88rem;
    padding: 10px 20px;
    cursor: pointer;
    transition: background 0.12s, transform 0.08s;
}
.byschool-state-popup-action:hover { background: var(--blue-d, #154069); }
.byschool-state-popup-action:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.byschool-state-popup-action.is-clear {
    background: var(--paper);
    color: var(--blue);
    border: 1.5px solid var(--blue);
}
.byschool-state-popup-action.is-clear:hover {
    background: var(--teal-50);
}

/* "Be the first" empty-state stat (when lens country has 0 grantees
   in this state). Replaces the number with a ✦ glyph + warmer copy.
   Recolored off the retired-gold #8a5a00 onto brand teal (F41). */
.byschool-state-popup-stat-empty .byschool-state-popup-num {
    color: var(--teal-text);
    font-family: inherit;
}
.byschool-state-popup-stat-empty .byschool-state-popup-label strong {
    color: var(--teal-text);
}

/* Mobile: tighten padding, single-column stats grid, reflow each
   school-list row into name+count on top + ccTag on its own row. */
@media (max-width: 480px) {
    .byschool-state-popup {
        padding: 20px 18px 18px;
        border-radius: var(--r-lg);
    }
    .byschool-state-popup-head {
        flex-wrap: wrap;
        padding-right: 32px;
    }
    .byschool-state-popup-title {
        font-size: 1.18rem;
    }
    .byschool-state-popup-flag { font-size: 1.6rem; }
    .byschool-state-popup-stats {
        grid-template-columns: 1fr;
        padding: 12px 14px;
        gap: 10px;
    }
    .byschool-state-popup-list li {
        grid-template-columns: auto 1fr auto;
        row-gap: 4px;
    }
    .byschool-state-popup-cc {
        grid-column: 2 / -1;
        justify-self: start;
    }
    .byschool-state-popup-action {
        width: 100%;
        text-align: center;
    }
    .byschool-state-popup-actions {
        margin-top: 18px;
    }
}

/* ============================================================ */
/*  Snapshot date + sticky page nav                              */
/* ============================================================ */
/* Snapshot freshness signal (right side of .hero-bottom). Filled
   by JS once meta.json loads. Renders as small, low-emphasis text
   pushed to the right edge of the row. */
.hero-snapshot {
    margin-left: auto;
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.78);
    /* Slight monospace lean for the date so digits align visually
       across page loads — uses the same SF Mono stack we use for
       counts and ratios elsewhere. */
    font-variant-numeric: tabular-nums;
}
.hero-snapshot:empty { display: none; }
.hero-snapshot strong {
    color: #fff;
    font-weight: 600;
}

/* Sticky page-switcher: hidden until the hero scrolls off-screen,
   then slides in from the top. A second nav surface (same links as
   .hero-tabs) so users can change lenses without scrolling back up. */
.hero-sticky {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1500;
    background: var(--teal);
    color: #fff;
    padding: 10px 24px;
    /* 3-column grid keeps the nav optically centered regardless of the
       brand wordmark (left) and snapshot (right) widths. */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 16px;
    box-shadow: var(--shadow-2);
    transform: translateY(-100%);
    transition: transform 0.22s cubic-bezier(0.2, 0, 0, 1);
    visibility: hidden;
}
.hero-sticky-brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    justify-self: start;
    min-width: 0;
}
.hero-sticky-word {
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #fff;   /* solid-teal fallback; the frosted variant overrides to ink */
}
.hero-sticky-nav { justify-self: center; }
.hero-sticky .hero-snapshot { justify-self: end; }
.hero-sticky.is-visible {
    transform: translateY(0);
    visibility: visible;
}
.hero-sticky-nav {
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 1rem;
    font-weight: 500;
}
.hero-sticky-nav a {
    color: rgba(255, 255, 255, 0.78);
    text-decoration: none;
    padding: 2px 0;
    border-bottom: 2px solid transparent;
    transition: color 0.12s, border-color 0.12s;
}
.hero-sticky-nav a:hover { color: #fff; border-bottom-color: rgba(255,255,255,0.4); }
.hero-sticky-nav a[aria-current="page"] {
    color: #fff;
    border-bottom-color: #fff;
    font-weight: 600;
}
.hero-sticky-nav a:focus-visible {
    outline: 2px solid rgba(255,255,255,0.7);
    outline-offset: 4px;
    border-radius: var(--r-xs);
}
.hero-sticky .hero-snapshot {
    color: rgba(255, 255, 255, 0.7);
}

/* Reduced motion: kill any (future) hero transitions / sparkline anim. */
@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
    html { scroll-behavior: auto; }
}

/* ------------------------------------------------------------------ *
 * Review-fix hooks for the shared filter module (filter-ui.js).
 * New elements added for F14 (year steppers), F16 (grantee-type
 * definition), F37 (field-trigger caret/label). Styled here to match
 * the existing two-color system. Appended after the parallel review.
 * ------------------------------------------------------------------ */

/* F14 — precision +/- year steppers. Two pairs flank the value label
   inline: [−][+] 1992 – 2025 [−][+]. Each pair is a nowrap inline-flex
   so its − and + stay side by side and vertically centered with the
   slider; the start pair hugs the left of the year read-out, the end
   pair the right, so each visibly controls its own end of the range. */
.year-slider-steppers {
    display: inline-flex;
    flex-wrap: nowrap;
    gap: 4px;
    align-items: center;
}
.year-slider-steppers-start { margin-right: 4px; }
.year-slider-steppers-end { margin-left: 4px; }
.year-slider-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    height: 30px;
    padding: 0 8px;
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1;
    color: var(--teal-text);
    background: #fff;
    border: 1px solid var(--teal-100);
    border-radius: var(--r-pill, 999px);
    cursor: pointer;
    transition: background .12s ease, border-color .12s ease;
}
.year-slider-step:hover { background: var(--teal-50); border-color: var(--teal); }
.year-slider-step:active { background: var(--teal-100); }
.year-slider-step:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.year-slider-steppers .stepper-label {
    font-size: 0.78rem;
    color: var(--slate);
    margin-right: 2px;
}

/* F16 — define the two grantee-type routes under the chips */
.grantee-type-col { display: flex; flex-direction: column; gap: 6px; }
.grantee-type-def {
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--slate);
    margin: 2px 0 0;
}
.grantee-type-def b, .grantee-type-def strong { color: var(--ink); font-weight: 600; }

/* F37 — make the field-filter trigger read clearly as a menu opener */
.field-dropdown-trigger-label { display: inline; }
.field-dropdown-trigger-caret {
    display: inline-block;
    margin-left: 6px;
    font-size: 0.8em;
    color: var(--teal-text);
    transition: transform .12s ease;
}
.field-dropdown.is-open .field-dropdown-trigger-caret { transform: rotate(180deg); }

/* F14 — larger slider thumb hit area on touch / coarse pointers (≥24px
   visual; the input itself provides the surrounding tap area). */
@media (pointer: coarse) {
    .year-slider-input::-webkit-slider-thumb { width: 24px; height: 24px; }
    .year-slider-input::-moz-range-thumb     { width: 24px; height: 24px; }
    .year-slider-step { min-width: 40px; height: 40px; }
}

/* (F24's .state-tile overrides were removed so the Explore heatmap
   matches the by-school state map exactly — the standard look. The
   font-size now uses the same clamp() and empty tiles use the same
   plain soft fill as .byschool-state-tile, no dashed outline.) */

/* ============================================================================
   ===== 2026 REDESIGN (picks) — appended; revert by deleting to EOF =====
   ----------------------------------------------------------------------------
   Additive overrides for the 26 chosen redesign variants (IMPL_SPEC.md §A–§E).
   Keyed to existing live classes + new §0 hook classes that JS owners emit, so
   the redesign previews/reverts cleanly (delete from the banner above to EOF).
   ALL gallery vars renamed to live tokens: gallery --sh-1/2/3 + --shadow-sm/md/lg
   → --shadow-1..4; gallery --crimson → --accent-ivy; gallery --mono → live SF-Mono
   stack / font-variant-numeric:tabular-nums; gallery #03302e → --teal-900; gallery
   breakdown swatch literals → --blue/--teal. No #0F192D, no #DAB978, no new hex.
   Dataset figure is 59,070 (text lives in HTML/JS, not here).
   Reduced-motion: the global kill-switch at styles.css:3636 covers every
   animation/transition added below — no per-rule work needed.
   ============================================================================ */

/* ===========================================================================
   G1.1 — Nav tabs V1 (segmented) + per-tab counts  [H3 hero-tabs--segmented,
          H4 hero-tab-count]. Applied to BOTH .hero-tabs and .hero-sticky-nav.
          Hero field is teal, so the gallery's light .tabsA track is adapted to
          translucent-white here (NOT var(--soft) on the teal field).
   =========================================================================== */
.hero-tabs--segmented {
    display: inline-flex;
    gap: 4px;
    padding: 5px;
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--r-pill);
}
/* De-underline the segmented tabs (override the base .hero-tabs a underline
   border + padding) and make each a pill. */
.hero-tabs--segmented a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 16px;
    border: none;
    border-bottom: none;
    border-radius: var(--r-pill);
    color: rgba(255, 255, 255, 0.82);
    font-weight: 600;
    font-size: 0.95rem;
}
.hero-tabs--segmented a:hover {
    color: #fff;
    border-bottom-color: transparent;
    background: rgba(255, 255, 255, 0.12);
}
.hero-tabs--segmented a[aria-current="page"] {
    background: #fff;
    color: var(--blue);
    box-shadow: var(--shadow-1);
    border-bottom: none;
}
.hero-tab-count {
    display: inline-flex;
    align-items: center;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    padding: 1px 7px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.22);
    color: #fff;
    font-variant-numeric: tabular-nums;
}
.hero-tabs--segmented a[aria-current="page"] .hero-tab-count {
    background: var(--teal-50);
    color: var(--teal-text);
}

/* ===========================================================================
   G1.1b — Frosted sticky page-switcher  [H1 hero-sticky--frosted,
           H2 hero-sticky-mark]. Overrides the solid-teal .hero-sticky
           (styles.css:3585) with a frosted-white bar + ink text.
   =========================================================================== */
.hero-sticky--frosted {
    /* 0.94 (was 0.85): the bar composites over whatever scrolls behind
       it, so a more-opaque white keeps the --slate nav/snapshot text
       reliably ≥4.5:1 regardless of the content (teal hero, brand tiles)
       passing under it. The blur still reads as frosted glass. */
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: saturate(160%) blur(8px);
    -webkit-backdrop-filter: saturate(160%) blur(8px);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-2);
    color: var(--ink);
}
.hero-sticky--frosted .hero-sticky-nav a {
    color: var(--slate);
}
.hero-sticky--frosted .hero-sticky-nav a:hover {
    color: var(--teal-text);
    border-bottom-color: var(--teal-100);
}
.hero-sticky--frosted .hero-sticky-nav a[aria-current="page"] {
    color: var(--teal-text);
    border-bottom-color: var(--teal-text);
}
.hero-sticky--frosted .hero-snapshot {
    color: var(--slate);
}
.hero-sticky--frosted .hero-snapshot strong {
    color: var(--ink);
}
/* Brand wordmark reads as ink on the light frosted bar. */
.hero-sticky--frosted .hero-sticky-word { color: var(--ink); }
/* Counts on the frosted bar: recolor off the translucent-white treatment. */
.hero-sticky--frosted .hero-tab-count {
    background: var(--soft);
    color: var(--slate);
}
.hero-sticky--frosted .hero-tabs--segmented {
    background: var(--soft);
    border-color: var(--line);
}
.hero-sticky--frosted .hero-tabs--segmented a {
    color: var(--slate);
}
.hero-sticky--frosted .hero-tabs--segmented a[aria-current="page"] {
    background: #fff;
    color: var(--blue);
}
/* Mini leaf mark prepended inside the frosted bar. The inline SVG uses the
   gallery .tree-line / .leaf classes (teal stroke + blue accent leaf). */
.hero-sticky-mark {
    width: 18px;
    height: 18px;
    flex: none;
    display: inline-flex;
}
.hero-sticky-mark .tree-line {
    fill: none;
    stroke: var(--teal);
    stroke-linecap: round;
    stroke-linejoin: round;
}
.hero-sticky-mark .tree-line.b { stroke: var(--blue); opacity: 0.55; }
.hero-sticky-mark .leaf { fill: var(--teal); opacity: 0.9; }
.hero-sticky-mark .leaf.b { fill: var(--blue); opacity: 0.5; }

/* ===========================================================================
   G1.2 — Footer V3 (branded centered colophon)  [H5 colophon--branded,
          H6 colophon-lockup / colophon-stamp / colophon-row / colophon-fine].
          Ported from g1 .footC. Be Vietnam italic stamp (no serif payload).
   =========================================================================== */
.colophon--branded {
    text-align: center;
    padding: 30px 22px 48px;
    border-top: 2px solid var(--line);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}
.colophon--branded p { margin-bottom: 0; }
.colophon-lockup {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}
.colophon-lockup svg {
    width: 34px;
    height: 34px;
}
.colophon-lockup .tree-line {
    fill: none;
    stroke: var(--teal);
    stroke-linecap: round;
    stroke-linejoin: round;
}
.colophon-lockup .tree-line.b { stroke: var(--blue); opacity: 0.55; }
.colophon-lockup .leaf { fill: var(--teal); opacity: 0.9; }
.colophon-lockup .leaf.b { fill: var(--blue); opacity: 0.5; }
.colophon-stamp {
    /* Be Vietnam italic (brand typeface) — serif intentionally NOT loaded. */
    font-style: italic;
    font-size: 13px;
    color: var(--slate);
}
.colophon-row {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
}
.colophon-row a {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--graphite);
    text-decoration: none;
    padding: 6px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
    transition: border-color 0.12s, color 0.12s;
}
.colophon-row a:hover,
.colophon-row a:focus-visible {
    border-color: var(--teal);
    color: var(--teal-text);
}
.colophon-fine {
    font-size: 11.5px;
    color: var(--slate);   /* was --mist #97A3B1 = 2.35:1 on --soft (AA fail) */
    font-variant-numeric: tabular-nums;
}
/* The by-school footer's snapshot span carries .hero-snapshot (white, for
   the teal hero) but lives inside the light colophon — white-on-#F3F5F7
   was 1.09:1. Pin it (and any bold child) to slate in the footer. */
.colophon-fine .hero-snapshot,
.colophon-fine .hero-snapshot strong {
    color: var(--slate);
}

/* ===========================================================================
   G2.1 — Country dropdown V1 searchable combobox  [H7 cd-combo / cd-combo-box /
          cd-combo-menu / cd-combo-row / cd-combo-search / cd-combo-flag /
          cd-combo-count / cd-combo-caret]. Ported from g2 .cd-combo.
          (filter-ui.js emits the markup + role=combobox/listbox a11y.)
   =========================================================================== */
.cd-combo {
    position: relative;
    /* Grow to fill the filter row (after the label) up to the cap, instead of
       hugging the "Vietnam 697" content at min-width — a longer, easier target. */
    flex: 1 1 auto;
    max-width: 420px;
    min-width: 260px;
}
.cd-combo-box {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--paper);
    border: 1.5px solid var(--teal);
    border-radius: var(--r-lg);
    padding: 9px 12px;
    box-shadow: 0 0 0 4px var(--teal-50);
    cursor: pointer;
    font: inherit;
    width: 100%;
    text-align: left;
}
.cd-combo-box:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.cd-combo-flag {
    font-size: 1.2rem;
    line-height: 1;
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
.cd-combo-name {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--ink);
}
.cd-combo-count {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.74rem;
    font-weight: 700;
    color: var(--teal-text);
    background: var(--teal-50);
    border-radius: var(--r-pill);
    padding: 2px 9px;
}
.cd-combo-caret {
    width: 8px;
    height: 8px;
    border-right: 2px solid var(--mist);
    border-bottom: 2px solid var(--mist);
    transform: rotate(45deg);
    margin-left: 4px;
    flex: none;
}
.cd-combo-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 60;
    margin-top: 0;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-3);
    overflow: hidden;
    max-height: 320px;
    overflow-y: auto;
}
.cd-combo-menu[hidden] { display: none; }
.cd-combo-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    border-bottom: 1px solid var(--soft);
    color: var(--mist);
    font-size: 0.85rem;
    position: sticky;
    top: 0;
    background: var(--paper);
}
.cd-combo-search input {
    border: 0;
    outline: 0;
    font-family: inherit;
    font-size: 0.88rem;
    width: 100%;
    color: var(--ink);
    background: transparent;
}
.cd-combo-search svg { flex-shrink: 0; }
.cd-combo-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    font-size: 0.9rem;
    cursor: pointer;
    color: var(--ink);
}
.cd-combo-row:hover { background: var(--teal-50); }
/* Keyboard active option (the aria-activedescendant target) — must read
   distinctly from plain hover, hence the inset teal ring. */
.cd-combo-row.is-active {
    background: var(--teal-50);
    box-shadow: inset 0 0 0 2px var(--teal);
    border-radius: var(--r-sm);
}
.cd-combo-row.is-sel { background: var(--teal-50); }
.cd-combo-row.is-sel .cd-combo-name { color: var(--teal-900); font-weight: 600; }
.cd-combo-row .cd-combo-count { margin-left: auto; }
/* Non-interactive region grouping header (role=presentation, skipped by the
   roving keyboard index). Muted uppercase label, no hover/select affordance. */
.cd-combo-region {
    padding: 9px 12px 4px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mist);
    pointer-events: none;
    user-select: none;
}

/* ===========================================================================
   G2.2 — Geographic scope V1 sliding pill + icons  [H8 scope-group--slide,
          scope-thumb]. Layers a sliding thumb onto the existing .scope-group
          radios (the :has(input:checked) logic stays for the active label).
   =========================================================================== */
.scope-group--slide {
    position: relative;
    background: var(--soft);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 4px;
    overflow: hidden;
}
.scope-thumb {
    position: absolute;
    top: 4px;
    left: 4px;
    height: calc(100% - 8px);
    /* 3 equal segments; JS sets transform:translateX(n * 100%) to move it. */
    width: calc((100% - 8px) / 3);
    background: var(--blue);
    border-radius: var(--r-pill);
    box-shadow: var(--shadow-2);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
    z-index: 0;
}
.scope-group--slide label {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex: 1 1 0;
    text-align: center;
    border-radius: var(--r-pill);
    font-weight: 600;
    /* The blue active fill is the sliding thumb now, not a per-label bg. */
    background: transparent;
}
.scope-group--slide label:has(input:checked) {
    background: transparent;
    color: #fff;
}
.scope-group--slide label svg {
    width: 14px;
    height: 14px;
    flex: none;
}

/* ===========================================================================
   G2.3 — Field-filter trigger V1 solid tinted  [H9 field-dropdown-trigger--solid].
          De-dashes the live dashed-teal opener (styles.css:725) into a solid
          on-brand teal-tint button. Keeps the caret + label spans + is-open.
   =========================================================================== */
.field-dropdown-trigger--solid {
    border-style: solid;
    border-color: var(--teal-100);
    background: var(--teal-50);
    /* --teal-700d clears AA on BOTH the base --teal-50 (5.36:1) and the
       hover/open --teal-100 (4.82:1); --teal-text was 4.05:1 on open. */
    color: var(--teal-700d);
}
.field-dropdown-trigger--solid:hover,
.field-dropdown.is-open .field-dropdown-trigger--solid {
    background: var(--teal-100);
    border-color: var(--teal);
    border-style: solid;
}

/* ===========================================================================
   G2.4 — Field-filter OPEN panel V2 pill-toggle list  [H10 field-dropdown-pills,
          field-dropdown-row--pill]. renderList emits tap-to-toggle pills (with
          aria-pressed) per group instead of checkbox rows. Ported from g2 .fp-pills.
   =========================================================================== */
.field-dropdown-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    padding: 0 0 10px;
}
.field-dropdown-row--pill {
    font: inherit;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--teal-text);
    background: var(--paper);
    border: 1.5px solid var(--teal-100);
    border-radius: var(--r-pill);
    padding: 5px 12px;
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.field-dropdown-row--pill:hover {
    background: var(--teal-50);
    border-color: var(--teal);
}
.field-dropdown-row--pill[aria-pressed="true"] {
    background: var(--teal);
    color: #fff;
    border-color: var(--teal);
}
.field-dropdown-row--pill[aria-pressed="true"]::before {
    content: "\2713 ";
    font-size: 0.74rem;
}
.field-dropdown-row--pill:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
/* Slightly lighter pill for cluster (child) items. */
.field-dropdown-row--pill.is-child {
    color: var(--graphite);
    border-color: var(--line);
}

/* ===========================================================================
   G2.5 — Grantee-type chips V2 toggle-switch rows  [H11 chip--switch,
          chip-switch-knob, chip-count]. Ported from g2 .chip-sw.
          Keeps state.grantee_types Set + the .grantee-type-def helper.
   =========================================================================== */
/* Stack the grantee-type toggle rows as a column with breathing room — the
   container was an unstyled block, so the rows touched (0px gap). */
.chip-sw {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.chip--switch {
    display: flex;
    align-items: center;
    gap: 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 11px 14px;
    cursor: pointer;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--ink);
    background: var(--paper);
    transition: background 0.15s, border-color 0.15s;
}
.chip--switch input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.chip-switch-knob {
    flex-shrink: 0;
    width: 36px;
    height: 20px;
    border-radius: var(--r-pill);
    background: var(--line);
    position: relative;
    transition: background 0.2s;
}
.chip-switch-knob::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: var(--shadow-1);
    transition: transform 0.2s;
}
.chip-count {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.78rem;
    color: var(--slate);
}
/* on-state (class .is-on or :has(input:checked) — emit either). */
.chip--switch.is-on,
.chip--switch:has(input:checked) {
    border-color: var(--teal-100);
    background: var(--teal-50);
}
.chip--switch.is-on .chip-switch-knob,
.chip--switch:has(input:checked) .chip-switch-knob {
    background: var(--teal);
}
.chip--switch.is-on .chip-switch-knob::after,
.chip--switch:has(input:checked) .chip-switch-knob::after {
    transform: translateX(16px);
}
.chip--switch.is-on .chip-count,
.chip--switch:has(input:checked) .chip-count {
    color: var(--teal-text);
}
.chip--switch:focus-within {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

/* ===========================================================================
   G2.6 — Year slider V1 histogram + tooltips  [year-slider-hist, ys-bar, ys-tip].
          ADDS a grantees-per-year histogram behind the track + live thumb
          tooltips; KEEPS the existing dual-range track, fill, value + steppers.
          Ported from g2 .ys-hist.
   =========================================================================== */
.year-slider-hist {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 46px;
    margin: 0 0 4px;
}
.ys-bar {
    flex: 1;
    min-width: 1px;
    background: var(--teal-100);
    border-radius: 2px 2px 0 0;
}
.ys-bar.is-inrange { background: var(--teal); }
/* When the slider carries the histogram, the fill reads as a teal→blue ramp
   (the modifier scopes the override so the plain slider keeps its teal fill). */
.year-slider--hist .year-slider-fill {
    background: linear-gradient(90deg, var(--teal), var(--blue));
}
/* Live value tooltips over each thumb (JS sets left% + text). */
.ys-tip {
    position: absolute;
    top: -34px;
    transform: translateX(-50%);
    background: var(--blue);
    color: #fff;
    font-variant-numeric: tabular-nums;
    font-size: 0.72rem;
    padding: 3px 8px;
    border-radius: var(--r-sm);
    white-space: nowrap;
    pointer-events: none;
    z-index: 6;
}
.ys-tip::after {
    content: "";
    position: absolute;
    bottom: -4px;
    left: 50%;
    transform: translateX(-50%);
    border: 4px solid transparent;
    border-top-color: var(--blue);
    border-bottom: 0;
}

/* ===========================================================================
   G2.7 — Reset button V3 split (count + clear-all)  [H12 filter-actions--split,
          filter-active-count, reset-btn--split]. Ported from g2 .rs-split.
          Overrides the default blue-outline .reset-btn to a soft-teal clear-all.
   =========================================================================== */
.filter-actions--split {
    justify-content: space-between;
    align-items: center;
    gap: 14px;
}
.filter-active-count {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
    color: var(--graphite);
}
.filter-active-count .b {
    font-variant-numeric: tabular-nums;
    font-size: 0.74rem;
    font-weight: 700;
    color: #fff;
    background: var(--teal);
    border-radius: var(--r-pill);
    padding: 2px 9px;
}
.reset-btn--split {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--teal-700d);   /* was --teal-d #00958F = 3.37:1 on --teal-50 */
    background: var(--teal-50);
    border: 1.5px solid var(--teal-100);
}
.reset-btn--split:hover {
    background: var(--teal-100);
    color: var(--teal-700d);   /* 4.82:1 on the hover --teal-100 bg */
}
.reset-btn--split svg {
    width: 14px;
    height: 14px;
}

/* ===========================================================================
   G3.1 — Country write-up V1 editorial brief  [H13 layer-1--brief, layer-1-flagline,
          layer-1-flag, layer-1-eyebrow, layer-1-rule, layer-1-chips, layer-1-chip].
          Reskin of the head/body region of #layer-1; KEEPS .layer-1-meta + type
          pill + per-type split. Be Vietnam (serif NOT loaded). Ported from g3 .wu1.
   =========================================================================== */
.layer-1--brief {
    box-shadow: var(--shadow-2);
}
.layer-1-flagline {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 0 0 4px;
}
.layer-1-flag {
    font-size: 26px;
    line-height: 1;
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
.layer-1-eyebrow {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--teal-text);
}
.layer-1-rule {
    height: 3px;
    width: 46px;
    background: var(--teal);
    border-radius: var(--r-pill);
    margin: 13px 0 12px;
}
.layer-1--brief .layer-1-body .lead,
.layer-1--brief .layer-1-body strong.lead {
    font-weight: 600;
    color: var(--ink);
}
.layer-1-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}
.layer-1-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    background: var(--soft);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 6px 12px;
    font-size: 12px;
    color: var(--slate);
    font-variant-numeric: tabular-nums;
}
.layer-1-chip b {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--blue);
}

/* ===========================================================================
   G3.2 — Recent-grantees list V3 leader-dot ledger  [H14 recent-grantees-item--ledger,
          recent-grantees-dots]. Single optical line: year · name · dotted leader ·
          major · school. KEEPS data-state hover wiring + --school-color link + name
          link. Ported from g3 .rg3. Overrides the block .recent-grantees-item layout.
   =========================================================================== */
.recent-grantees-item--ledger {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 8px 0;
}
.recent-grantees-item--ledger .recent-grantees-year {
    /* Be Vietnam tabular (serif NOT loaded); keeps the teal-text + weight. */
    flex: 0 0 auto;
}
.recent-grantees-item--ledger .recent-grantees-name {
    flex: 0 0 auto;
}
.recent-grantees-dots {
    flex: 1 1 auto;
    border-bottom: 1.5px dotted var(--line);
    transform: translateY(-3px);
    min-width: 14px;
}
.recent-grantees-item--ledger .recent-grantees-major,
.recent-grantees-item--ledger .recent-grantees-school {
    flex: 0 0 auto;
    font-size: 0.88rem;
}
/* The 46px line-2 indent + the block line1/line2 only apply to the NON-ledger
   layout now; scope the old margin away when the item is a ledger row. */
.recent-grantees-item--ledger .recent-grantees-line2 {
    margin-left: 0;
    margin-top: 0;
}
/* Country flag before the grantee name. */
.recent-grantees-flag {
    flex: 0 0 auto;
    font-size: 1rem;
    line-height: 1;
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
/* When the list COLUMN is narrow (2-up layout, or phones) the single optical
   line can't fit name + major + school, so stack: the dotted leader becomes an
   invisible full-width break, pushing major + school onto a second line where
   they wrap. Container query keys off the column width, so it fires for the
   2-column layout even on a wide viewport (and on phones). */
@container (max-width: 520px) {
    .recent-grantees-item--ledger { flex-wrap: wrap; row-gap: 1px; }
    .recent-grantees-item--ledger .recent-grantees-name { flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; }
    .recent-grantees-item--ledger .recent-grantees-dots {
        flex: 1 0 100%;        /* full-width zero-height spacer = forces the line break */
        height: 0;
        min-width: 0;
        border-bottom: none;
        transform: none;
    }
    .recent-grantees-item--ledger .recent-grantees-major,
    .recent-grantees-item--ledger .recent-grantees-school {
        flex: 0 1 auto;
        min-width: 0;
        overflow-wrap: anywhere;
    }
}
/* Below ~760px there isn't room for two columns — collapse the side-by-side
   layout back to a single stacked column (Foreign Student first). */
@media (max-width: 760px) {
    .recent-grantees--dual { grid-template-columns: 1fr; }
}

/* ===========================================================================
   G3.3 — Region-countries panel V3 ranked count bars  [H15 region-countries-card--ranked,
          rc-rank-row, rc-rank-bar, rc-rank-num, rc-rank-flag, rc-rank-name].
          Shared by Explore + by-name (filter-ui.js renderRegionCountriesList).
          Ported from g3 .rc3.
   =========================================================================== */
.region-countries-card--ranked .region-countries-grid {
    /* The ranked list is single-column rows, not the 2-col link grid. */
    display: block;
    grid-template-columns: none;
    max-height: 360px;
    overflow-y: auto;
}
.rc-rank-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 7px 0;
    text-decoration: none;
    cursor: pointer;
}
.rc-rank-row + .rc-rank-row {
    border-top: 1px solid var(--soft);
}
.rc-rank-flag {
    font-size: 18px;
    width: 22px;
    text-align: center;
    flex: 0 0 auto;
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}
.rc-rank-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    width: 96px;
    flex: 0 0 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rc-rank-row:hover .rc-rank-name,
.rc-rank-row:focus-visible .rc-rank-name {
    color: var(--teal-900);
}
.rc-rank-bar {
    flex: 1 1 auto;
    height: 7px;
    background: var(--soft);
    border-radius: var(--r-pill);
    overflow: hidden;
}
.rc-rank-bar i {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, var(--teal), var(--teal-d));
    border-radius: var(--r-pill);
}
.rc-rank-num {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--blue);
    width: 34px;
    text-align: right;
    flex: 0 0 auto;
    font-size: 11.5px;
}
.rc-rank-row .rc-rank-wk {
    font-size: 10px;
    color: var(--mist);
    flex: 0 0 auto;
}
/* In by-name's narrow 20% column the ranked list still works; let the name
   shrink rather than overflow. */
.byname-filters-row .region-countries-card--ranked .rc-rank-name { width: auto; min-width: 0; }

/* ===========================================================================
   G3.4 — Empty / loading states V3+V2  [H16 breakdown-empty--guided, es-ladder,
          es-step (es-step--rec), es-step-ico, es-step-tx, es-step-go; loading
          es-skeleton, sk (+ width utils), sk-foot, es-pulse]. Ported from g3
          .es3 (guided ladder) + .es2 (skeleton shimmer). The crimson "0" mark
          uses --accent-ivy (gallery #a51c30 → token).
   =========================================================================== */
/* --- Loading skeleton (V2) --- */
.es-skeleton {
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 11px;
}
.es-skeleton .sk-head {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-bottom: 6px;
}
.es-skeleton .sk-c {
    width: 38px;
    height: 38px;
    border-radius: 50%;
}
.es-skeleton .sk-lines {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.es-skeleton .sk-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 0;
    border-top: 1px solid var(--soft);
}
.es-skeleton .sk-sq {
    width: 36px;
    height: 36px;
    border-radius: var(--r-md);
    flex: 0 0 auto;
}
.es-skeleton .sk {
    /* shimmer mid swapped off gallery #E9EDF1 to a teal-tinted token. */
    background: linear-gradient(100deg, var(--soft) 30%, var(--teal-50) 50%, var(--soft) 70%);
    background-size: 200% 100%;
    animation: redesign-shimmer 1.3s ease-in-out infinite;
    border-radius: var(--r-sm);
    height: 11px;
}
.es-skeleton .sk.w30 { width: 30%; }
.es-skeleton .sk.w45 { width: 45%; }
.es-skeleton .sk.w55 { width: 55%; }
.es-skeleton .sk.w70 { width: 70%; }
.es-skeleton .sk.w90 { width: 90%; }
.es-skeleton .sk-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: center;
    margin-top: 6px;
    font-size: 11.5px;
    color: var(--teal-text);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.es-pulse {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--teal);
    animation: redesign-pulse 1.1s ease-in-out infinite;
}
@keyframes redesign-shimmer { to { background-position: -200% 0; } }
@keyframes redesign-pulse {
    0%, 100% { opacity: 0.35; transform: scale(0.8); }
    50%      { opacity: 1;    transform: scale(1.15); }
}
/* --- Guided "broaden scope" empty ladder (V3) --- */
.breakdown-empty--guided {
    padding: 22px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.breakdown-empty--guided .es-top {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-bottom: 14px;
}
.breakdown-empty--guided .es-mark {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--accent-ivy-50);
    border: 1px solid var(--accent-ivy);
    color: var(--accent-ivy);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
}
.breakdown-empty--guided .es-mark svg { width: 19px; height: 19px; }
.breakdown-empty--guided .es-top h4 {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ink);
    margin: 0;
}
.breakdown-empty--guided .es-top p {
    font-size: 12px;
    color: var(--slate);
    margin: 2px 0 0;
}
.es-ladder {
    display: flex;
    flex-direction: column;
    gap: 9px;
}
.es-step {
    display: flex;
    align-items: center;
    gap: 11px;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 10px 12px;
    background: var(--paper);
    cursor: pointer;
    text-decoration: none;
    font: inherit;
    text-align: left;
    width: 100%;
    transition: background 0.15s, border-color 0.15s;
}
.es-step:hover {
    border-color: var(--teal);
    background: var(--teal-50);
}
.es-step:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.es-step-ico {
    width: 26px;
    height: 26px;
    border-radius: var(--r-sm);
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    background: var(--soft);
}
.es-step-tx { flex: 1; }
.es-step-tx b {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    display: block;
    line-height: 1.25;
}
.es-step-tx span {
    font-size: 11.5px;
    color: var(--slate);
    font-variant-numeric: tabular-nums;
}
.es-step-go {
    font-size: 13px;
    color: var(--mist);
    font-weight: 700;
    flex: 0 0 auto;
}
.es-step:hover .es-step-go { color: var(--teal); }
.es-step--rec {
    border-color: var(--teal-100);
    background: var(--teal-50);
}
.es-step--rec .es-step-ico { background: #fff; }

/* ===========================================================================
   G4.1 — US state heatmap V1 polish (KEEP intensity-only blue ramp; just add
          rounded tiles + soft glow on the hovered/active tile). Layered onto the
          shared .byschool-state-tile so it applies on both maps. Ported from g4 .hm-v1.
          (Heatmap V1 = keep current ramp per user; this is polish only.)
   =========================================================================== */
.byschool-state-tile {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
}
.byschool-state-tile.is-empty {
    box-shadow: none;
}
.byschool-state-tile:not(.is-empty):hover,
.byschool-state-tile.is-list-hover,
.byschool-state-tile.is-active {
    /* Soft teal glow on the lifted tile (the existing :hover already scales +
       outlines; this just adds the brand-tinted depth). */
    box-shadow: 0 6px 16px rgba(0, 149, 143, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.3);
}

/* ===========================================================================
   G4.2 — Popular-majors line chart V3 (100%-share ribbon) — CSS support only.
          The chart is SVG-attribute driven in app.js (palette + ribbon paths +
          <defs> gradients live there). This block only documents the gradient
          IDs the JS builder must define + styles the share-ribbon hover read-out.
          Gradient ramp (teal→blue, all live tokens — NO new hex):
            #ribEdu  : stop0 var(--blue)   #20558A → stop1 var(--blue-d) #173F69
            #ribPub  : stop0 var(--teal)   #00B1AC → stop1 var(--teal-d) #00958F
            top tints: var(--teal-100) #CCF0EE
          Documented JS PALETTE (app.js) — auditable in one place per spec §C-2:
            [#20558A, #00B1AC, #173F69, #00958F, #00514F, #5A6878]
            == [--blue, --teal, --blue-d, --teal-d, --teal-900, --slate]
   =========================================================================== */
.families-line-chart--ribbon .families-line-axis {
    /* No y-axis on the 100%-normalized ribbon; keep x labels readable. */
    fill: var(--slate);
}
.families-line-band {
    transition: opacity 0.12s;
}
.families-line-band.is-faded { opacity: 0.35; }
/* Inline band share labels drawn over the ribbon. */
.families-line-band-label {
    font-size: 9px;
    font-weight: 700;
    fill: #fff;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

/* ===========================================================================
   G4.3 — Field/major breakdown V2 data-table 2.0  [H17 cluster-table--datatable,
          cluster-spark, cluster-spark-i, cluster-trend (--up/--dn/--fl)].
          Adds an in-cell sparkbar column + hover rows (+ optional trend pills)
          to .cluster-table. Ported from g4 .fb-v2. Gallery swatch literals →
          --blue/--teal; gallery --crimson → --accent-ivy.
   =========================================================================== */
.cluster-table--datatable tbody tr:hover td,
.cluster-table.cluster-table--datatable tbody tr:hover td {
    background: var(--teal-50);
}
.cluster-spark {
    height: 9px;
    background: var(--soft);
    border-radius: var(--r-pill);
    overflow: hidden;
    min-width: 40px;
}
.cluster-spark-i {
    display: block;
    height: 100%;
    border-radius: var(--r-pill);
    background: var(--blue);
}
.cluster-trend {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: var(--r-pill);
}
.cluster-trend--up { color: var(--teal-900); background: var(--teal-50); }
.cluster-trend--dn { color: var(--accent-ivy); background: var(--accent-ivy-50); }
.cluster-trend--fl { color: var(--slate); background: var(--soft); }

/* ===========================================================================
   G5.1 — By-school origin table V3 ranked + dot gauge  [H18 byschool-origin--ranked,
          byschool-origin-rank, byschool-origin-dots, byschool-origin-dot (is-off)].
          Swaps the magnitude bar for a rank numeral + 5-dot gauge. KEEPS flag,
          country, is-lens highlight, latest year, +N more popup. Ported from g5 .octRank.
   =========================================================================== */
.byschool-origin-rank {
    font-size: 13px;
    font-weight: 600;
    color: var(--mist);
    width: 18px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.byschool-origin--ranked .byschool-origin-row.is-lens .byschool-origin-rank {
    color: var(--blue);
}
.byschool-origin-dots {
    display: inline-flex;
    gap: 3px;
    align-items: center;
}
.byschool-origin-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--teal);
    flex: 0 0 auto;
}
.byschool-origin-dot.is-off {
    background: var(--teal-100);
}
/* Lens row: dots go blue (mirrors the existing .is-lens .byschool-bar-fill). */
.byschool-origin--ranked .byschool-origin-row.is-lens .byschool-origin-dot {
    background: var(--blue);
}
.byschool-origin--ranked .byschool-origin-row.is-lens .byschool-origin-dot.is-off {
    background: var(--blue-50);
}

/* ===========================================================================
   G5.2 — State-map info popup V3 mini split-bar  [H19 byschool-state-popup--split,
          popup-split-seg, popup-split-seg-b, popup-split-key, popup-split-row,
          popup-split-sw]. Adds a stacked split-bar (state's grantees by host
          school) atop the existing popup. REUSES per-school brand colors (set
          inline). Ported from g5 .popV3.
   =========================================================================== */
.byschool-state-popup--split .popup-split-seg {
    height: 8px;
    border-radius: var(--r-pill);
    overflow: hidden;
    display: flex;
    margin-bottom: 8px;
}
.popup-split-seg-b {
    display: block;
    height: 100%;
}
/* Two-color guard: schools with no brand color fall back to alternating
   blue/teal segments (no new hex). JS may add .is-alt-a / .is-alt-b when a
   school color is missing. */
.popup-split-seg-b.is-alt-a { background: var(--blue); }
.popup-split-seg-b.is-alt-b { background: var(--teal); }
.popup-split-key {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 11.5px;
}
.popup-split-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--graphite);
    gap: 8px;
}
.popup-split-row .popup-split-row-lab {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.popup-split-row b {
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.popup-split-sw {
    width: 9px;
    height: 9px;
    border-radius: 3px;
    flex: 0 0 auto;
}

/* ===========================================================================
   G5.3 — Surname stats V2 top-3 podium  [H20 byname-surname--podium, sn-pod,
          sn-pod-col (p1/p2/p3), sn-pod-bar, sn-pod-name, sn-pod-rk]. Ported from
          g5 .snPod. Heights scale to actual counts in JS (the px values below are
          the gallery max heights / sensible fallbacks). KEEPS click → ?last= link.
   =========================================================================== */
.byname-surname--podium {
    margin-bottom: 14px;
}
.sn-pod {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    justify-content: center;
}
.sn-pod-col {
    flex: 1;
    text-align: center;
    text-decoration: none;
}
.sn-pod-bar {
    border-radius: var(--r-md) var(--r-md) 0 0;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    /* 19px (≥14pt) bold = WCAG large text → 3:1 AA. The rank numerals on
       the teal-d (3.69:1) and teal (3.44:1) bars miss the 4.5 normal-text
       floor but clear large-text; bumping 18→19px qualifies them. */
    font-size: 19px;
    padding-top: 8px;
    font-variant-numeric: tabular-nums;
}
.sn-pod-col.p1 .sn-pod-bar { background: var(--blue); height: 78px; }
.sn-pod-col.p2 .sn-pod-bar { background: var(--teal-d); height: 58px; }
/* gallery #03302e → token --teal-900 for AA contrast on the lighter teal bar. */
.sn-pod-col.p3 .sn-pod-bar { background: var(--teal); height: 42px; color: var(--teal-900); }
.sn-pod-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--ink);
    margin-top: 6px;
}
.sn-pod-rk {
    font-size: 10px;
    color: var(--slate);   /* was --mist #97A3B1 = 2.56:1 on white (AA fail) */
    font-weight: 700;
}

/* ===========================================================================
   G5.4 — By-the-numbers V2 progress rings  [H21 byname-stats--rings, btn-ring,
          btn-ring-dial, btn-ring-n, btn-ring-l]. Conic dials use ONLY
          --blue/--blue-50/--teal/--teal-50/--teal-d (token-pure; the conic %P
          is set inline per stat in JS). Ported from g5 .btnRing.
   =========================================================================== */
.byname-stats--rings {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    justify-content: space-around;
}
.btn-ring {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}
.btn-ring-dial {
    width: 74px;
    height: 74px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    position: relative;
    /* JS sets background:conic-gradient(var(--blue) 0 P%, var(--blue-50) P% 100%)
       (or the teal variants) inline per dial. Fallback ring shown until then. */
    background: conic-gradient(var(--blue) 0 65%, var(--blue-50) 65% 100%);
}
.btn-ring-dial::after {
    content: "";
    position: absolute;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: #fff;
}
.btn-ring-n {
    position: relative;
    z-index: 1;
    font-variant-numeric: tabular-nums;
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
}
.btn-ring-l {
    font-size: 11px;
    color: var(--slate);
    font-weight: 600;
    text-align: center;
}

/* ===========================================================================
   G5.5 — By-school alumni V1 avatar cards (light touch-up)  [byschool-alum--card].
          Optional upgrade of .byschool-alum-list rows to initials-avatar cards
          with a field line. Ported from g5 .almCard. (Nice-to-have; styled here
          so by-school/app.js can opt in by adding the modifier.)
   =========================================================================== */
/* Two columns of linked alumni cards (each links to that grantee on the
   by-name page). The <li> is the grid cell; the <a>.byschool-alum-card is
   the box, so it fills the cell height for an even grid. */
.byschool-alum--card {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 12px;
}
.byschool-alum--card li { display: block; margin: 0; padding: 0; }
.byschool-alum-card {
    display: flex;
    align-items: center;
    gap: 11px;
    height: 100%;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 9px 11px;
    background: #fff;
    color: inherit;
    text-decoration: none;
    transition: border-color 0.15s;
}
a.byschool-alum-card:hover { border-color: var(--teal); }
a.byschool-alum-card:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--teal); }
@media (max-width: 560px) {
    .byschool-alum--card { grid-template-columns: 1fr; }
}
.byschool-alum-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--blue-50);
    color: var(--blue);
    font-weight: 700;
    font-size: 12px;
    display: grid;
    place-items: center;
    flex: 0 0 auto;
}
.byschool-alum--card .byschool-alum-meta {
    flex: 1;
    min-width: 0;
}
.byschool-alum--card .byschool-alum-year {
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    background: var(--teal-50);
    padding: 3px 9px;
    border-radius: var(--r-pill);
    margin-right: 0;
    flex: 0 0 auto;
}

/* ===========================================================================
   G5.6 retired (2026-06): the teal edge-stripe + year-pill + 📚/🏛 meta-emoji
   were dropped when the by-name card adopted direction #5 (italic Be Vietnam
   gloss): a white hairline card with no left-stripe (banned by brand), the
   field set in italic Be Vietnam, and the vendored brand icons (.byname-card-ico)
   on the field + school-fallback lines. by-name/app.js no longer opts into
   .byname-card--stripe.
   =========================================================================== */

/* ============================================================================
   ===== P1 fix batch (Phase C review, 2026-06-10) — responsive + print =====
   Appended AFTER the 2026-redesign section on purpose: several rules below
   override same-specificity redesign rules (e.g. segmented-tab padding) and
   must win the source-order tiebreak.
   ============================================================================ */

/* C-2 — the sticky page-switcher was content-sized (~372px): the
   "By school" tab + badge sat clipped offscreen on 320–412px viewports,
   unreachable without knowing it was there. Let the nav fill the bar
   with three equal shrinkable tabs (mirrors the in-flow hero nav fix
   scoped to .hero-bottom). */
@media (max-width: 640px) {
    .hero-sticky-nav.hero-tabs--segmented {
        display: flex;
        width: 100%;
        min-width: 0;
    }
    .hero-sticky-nav.hero-tabs--segmented a {
        flex: 1 1 0;
        min-width: 0;
        justify-content: center;
        text-align: center;
        padding: 8px 6px;
    }
}

/* C-3 — under 480px the count badges overpaint their tab labels (the
   59,070 badge bleeds into both neighbor tabs at 320). The counts are
   hero flourish, not load-bearing data — drop them on the narrowest
   phones, in BOTH the in-flow hero nav and the sticky copy. */
@media (max-width: 480px) {
    .hero-tab-count { display: none; }
}

/* C-4 — the year row's wrap rules were scoped to <=640px, but its
   unwrapped min-content (hist + 240px track + two stepper pairs +
   read-out + helper) is ~750px: the 641–840px band overflowed ~33px.
   Same wrap recipe as the <=640 block, wider window. */
@media (max-width: 840px) {
    .year-slider { width: 100%; flex-wrap: wrap; gap: 10px 8px; }
    .year-slider-hist { flex: 1 1 100%; }
    .year-slider-track-wrap { flex: 1 1 100%; width: auto; min-width: 0; max-width: 100%; }
    .year-slider-value { flex: 1 1 auto; min-width: 0; text-align: center; }
    .year-slider .filter-helper { flex: 1 1 100%; margin-left: 0; }
}

/* C-5 — grid items default to min-width:auto, so the by-name filter
   card couldn't shrink below the grantee-type switch row's min-content
   and overflowed 32px at 320 (Explore's identical card in plain flow
   wraps fine). C-6 — a <select>'s intrinsic width follows its longest
   option (country names), overflowing 23px at 320 on by-school. */
.byname-filters-row > * { min-width: 0; }
.byschool-filter-field select,
.byschool-search-field input {
    width: 100%;
    min-width: 0;
    max-width: 100%;
}

/* C-7 — print stylesheet. Browsers default to background graphics OFF,
   which turned the teal hero and brand-color tiles into white-on-white;
   interactive chrome (steppers, switches, fullscreen) printed as junk;
   scroll-capped panels clipped mid-row. */
@media print {
    /* Hide interactive chrome — buttons, steppers, switches, skeletons. */
    #fullscreen-btn, .hero-sticky, .year-slider-steppers, .year-slider-step,
    .filter-actions, .byname-actions, .field-dropdown-panel, .es-skeleton,
    .hero-tree, .scope-thumb { display: none !important; }
    /* Sliders/toggles: the adjacent text read-outs carry the values. */
    .year-slider-hist, .year-slider-track-wrap, input[type='range'],
    .chip-switch-knob { display: none !important; }
    /* Flatten the teal hero to ink-on-white. */
    .hero, header { background: #fff !important; color: var(--ink) !important;
        border-bottom: 2px solid var(--teal); }
    .hero h1, .hero p, .hero-sub, .hero-eyebrow, .hero-tagline span,
    .hero-tabs--segmented a { color: var(--ink) !important; background: none !important; }
    /* Un-cap scroll panels so lists paginate instead of clipping mid-row. */
    .recent-grantees-list, .region-countries-panel {
        max-height: none !important; overflow: visible !important; }
    /* by-school tiles: brand-color cards print near-invisible without
       backgrounds — force ink-on-white and keep each tile on one page. */
    .byschool-tile, .byschool-tile-btn, .byschool-tile-btn * {
        color: var(--ink) !important; background: #fff !important; }
    .byschool-tile { border: 1px solid #ccc; }
    .byschool-tile-btn, .layer-1, .filters { break-inside: avoid; }
    a { text-decoration: none; color: var(--blue) !important; }
    body { background: #fff !important; }
}

/* C-1 follow-ups, exposed once the giant-table mask was removed: at 320
   the scope segments couldn't shrink (flex-basis auto keeps min-content
   — "Worldwide" hung 6px past the card) and the field panel, anchored
   left:0 to a wrap sitting ~37px in, overhung the viewport by 5px.
   Equal shrinkable thirds keep the slide-thumb geometry intact (it
   assumes 3 equal segments — do NOT let this row wrap); the panel pins
   to the viewport on the narrowest phones. */
@media (max-width: 480px) {
    .scope-group label { flex: 1 1 0; min-width: 0; padding: 8px 6px; }
    .field-dropdown-panel {
        position: fixed;
        left: 16px;
        right: 16px;
        /* Pin near the top of the viewport. Without this, the base rule's
           top: calc(100% + 6px) is inherited, and for a FIXED element 100%
           means the viewport height — so the panel opened ~850px down, off the
           bottom of the screen, and tapping "Choose field" appeared to do
           nothing. Top-anchored also keeps the search box above the on-screen
           keyboard. */
        top: 64px;
        bottom: auto;
        width: auto;
        max-height: calc(100vh - 96px);
    }
}

/* The per-major breakdown table's min-content (rank + major + 3 stat
   columns) exceeds the column under ~340px and, like all tables, treats
   CSS width as a floor — it pushed the page wider at 320. Scroll the
   WRAP instead of the page (standard responsive-table recipe). */
.cluster-table-wrap { overflow-x: auto; }

/* ============================================================================
   ===== P2 a11y: skip link + screen-reader-only headings =====
   WCAG 2.4.1 (Bypass Blocks) + 1.3.1/2.4.6 heading structure. The skip link
   is the first focusable element on each page; .sr-only carries headings that
   give SR heading-jump navigation without altering the visual layout.
   ============================================================================ */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
/* Off-screen until focused, then slides into the top-left on the blue
   brand chip. Highest z-index so it clears the sticky hero bar. */
.skip-link {
    position: fixed;
    left: 8px;
    top: -64px;
    z-index: 2000;
    background: var(--blue);
    color: #fff;
    padding: 10px 16px;
    border-radius: var(--r-sm);
    font-weight: 600;
    font-size: 0.95rem;
    text-decoration: none;
    transition: top 0.15s ease;
}
.skip-link:focus {
    top: 8px;
    outline: 2px solid #fff;
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .skip-link { transition: none; }
}
/* The main content target takes focus from the skip link but must not
   show a focus ring (it's a programmatic landing, not a control). */
main:focus { outline: none; }

/* ============================================================================
   ===== P2 fault UX: friendly dataset-load error + Retry (sub-pages) =====
   Replaces the technical "Loading failed: fetch …404" copy that stranded
   live-looking dead controls. The .es-skeleton loading state reuses the
   Explore component (above). ============================================== */
.fg-load-error {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    max-width: 32rem;
    margin: 24px auto;
    padding: 22px 24px;
    background: var(--soft);
    border: 1px solid var(--line);
    border-left: 4px solid var(--teal);
    border-radius: var(--r-md);
}
.fg-load-error-msg {
    margin: 0;
    color: var(--ink);
    font-size: 1rem;
    line-height: 1.5;
}
.fg-retry-btn {
    font: inherit;
    font-weight: 600;
    color: #fff;
    background: var(--blue);
    border: none;
    border-radius: var(--r-pill);
    padding: 9px 22px;
    cursor: pointer;
    transition: background 0.12s ease;
}
.fg-retry-btn:hover { background: var(--teal-text); }
.fg-retry-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
