/*
Theme Name: DHTC
Theme URI: https://duhocthanhcong.vn
Author: Brett Wertz
Description: Custom theme for Du Hoc Thanh Cong — Vietnamese study abroad consulting.
Version: 0.1.0
Requires at least: 6.0
Requires PHP: 8.2
Text Domain: dhtc

═══════════════════════════════════════════════════════════════════════════════
  STYLE SYSTEM — read /style-guide/ before adding any CSS to this file.
═══════════════════════════════════════════════════════════════════════════════
  The design system is fully tokenized. Use the canonical building blocks;
  don't invent new ones. Quick rules:

  - Use spacing tokens (--section-*, --gap-*, --card-pad-*). Don't write raw px.
  - Use canonical components (.overline, .pill, .surface, .heading-*, .list-*,
    .link-*, .btn--*). Don't invent component classes when modifiers cover it.
  - Tokenize any new color before using it. No hardcoded hex in component CSS.
  - No global a:hover color rule. Components define their own hover behavior.

  Full rulebook + rendered examples + anti-patterns: dhtc.local/style-guide/
═══════════════════════════════════════════════════════════════════════════════
*/

/* ─── Design Tokens ─────────────────────────────────────────────── */
:root {
    /* ── Brand colors ────────────────────────────────────────── */
    --navy:        #0D2840;
    --navy-light:  #1A3D5C;
    --navy-deep:   #14365A;   /* gradient endpoint for navy backgrounds */
    --mint:        #4FD9A4;
    --mint-dark:   #1A9270;
    --mint-light:  #E6FAF4;
    --mint-border: #b2edd6;   /* mint-tinted border for chips/cards */
    --amber:       #FFC200;
    --amber-dark:  #D9A500;
    --amber-soft:  #FFF8E0;   /* pale amber tint for sponsor backgrounds (.section--amber, .pill--amber) */

    /* ── Alert / danger — for form validation errors and destructive actions.
       Cooler / pinker than typical "Bootstrap red" so it sits in the same
       temperature family as navy and mint. Same saturation level as mint
       (~50%) so it reads as part of the system, not a foreign warning lib. */
    --danger:        #C24A4A;
    --danger-dark:   #9C2929;
    --danger-light:  #FBEAEA;   /* very pale tint for inline error backgrounds */
    --danger-border: #EFC4C4;   /* matches the mint-border pattern */

    /* ── Surfaces & text ──────────────────────────────────────── */
    --bg:          #FFFFFF;
    --surface:     #F0F5FA;
    --surface-soft: #F8F9FB;  /* softer listing-page background */
    --border:      #DDE8F0;

    --text:        #1A2E3B;
    --text-muted:  #5A7080;
    --text-light:  #8FA3B0;
    --text-stat:   #3D5165;   /* stat numerics on cards */

    /* ── Typography ───────────────────────────────────────────── */
    --font:        'Be Vietnam Pro', sans-serif;
    --font-display: 'Be Vietnam Pro', sans-serif;

    /* (--danger duplicate removed — the canonical block above at lines 46–49
       owns the danger palette: #C24A4A primary + #FBEAEA light + #EFC4C4 border.) */

    /* ── Article level indicators (only blue/orange/purple on site) ── */
    --level-uni-bg: #E8F0FF;
    --level-uni-fg: #2255CC;
    --level-hs-bg:  #FFF0E8;
    --level-hs-fg:  #C04800;
    --level-cc-bg:  #F0E8FF;
    --level-cc-fg:  #6B21A8;

    /* ── Layout primitives ────────────────────────────────────── */
    --nav-height:  80px;
    --radius:      0px;
    --radius-lg:   0px;

    /* ── Shadows ──────────────────────────────────────────────── */
    --shadow:      0 2px 12px rgba(13,40,64,.08);
    --shadow-md:   0 6px 24px rgba(13,40,64,.12);
    --shadow-card: 0 6px 20px rgba(13,40,64,.08);  /* canonical card-hover */

    /* ── Brand-color overlays (for hero scrims, on-dark badge bgs,
       hairline dividers, hero glows). Tokenized from repeated rgba
       call sites so the same scrim value is reused everywhere. */
    --overlay-navy-light:  rgba(13,40,64,.55);   /* hero photo scrim (top of gradient) */
    --overlay-navy-faint:  rgba(13,40,64,.12);   /* hairline dividers, soft tints, light shadows */
    --overlay-mint-faint:  rgba(79,217,164,.12); /* on-dark mint badge bg, hero glow tint */
    --overlay-mint-strong: rgba(79,217,164,.9);  /* mint text-on-navy with slight transparency */
    --overlay-amber-faint: rgba(255,194,0,.15);  /* on-dark amber badge bg */

    /* ── Interaction tiers ────────────────────────────────────── */
    /* Lift effects retired 2026-05-16. Token kept (not deleted) so the
       11 existing usages of `transform: var(--lift-sm)` no-op cleanly.
       Replaced sitewide with subtle image-zoom on hover for cards that
       have images — see the .img-zoom-on-hover rules near the bottom of
       this file. */
    --lift-sm:     none;

    /* ── Focus rings (keyboard accessibility) ─────────────────── */
    --focus-outline: 3px solid rgba(79,217,164,.7);  /* buttons, pills, tabs */
    --focus-offset:  2px;

    /* ── Transition timings ───────────────────────────────────── */
    --ease-fast:   .15s;   /* color / bg / border */
    --ease-base:   .18s;   /* shadows, multi-property */
    --ease-slow:   .25s;   /* transforms, drawers */

    /* ── Spacing — section vertical padding ───────────────────── */
    --section-xs:  32px;   /* tight bands (footer chrome, trust strips) */
    --section-sm:  48px;   /* modest sections (page headers, secondary content) */
    --section-md:  64px;   /* standard section (default — most content) */
    --section-lg:  96px;   /* major / hero sections */

    /* ── Spacing — flex / grid gaps ───────────────────────────── */
    --gap-2xs:     8px;    /* tag rows, badge groups */
    --gap-xs:      12px;   /* button rows, dense lists */
    --gap-sm:      16px;   /* small-card grids, mobile */
    --gap-md:      24px;   /* default — most card grids */
    --gap-lg:      32px;   /* section-internal layout */
    --gap-xl:      48px;   /* page-level columns (sidebar gaps) */

    /* ── Spacing — card internal padding ──────────────────────── */
    --card-pad-sm: 16px;   /* compact cards (image grid card body) */
    --card-pad-md: 24px;   /* default — most cards */
    --card-pad-lg: 32px;   /* generous (CTA cards, essay block, form steps) */
    --card-pad-row: 14px 22px;  /* compact list rows (sc-row, list-rows) */

    /* ── Container max-widths (pixel — for layout) ────────────── */
    --container-max: 1200px; /* page container */
    --container-md:  1024px; /* medium grids */
    --container-sm:  720px;  /* reading content + forms */
    --container-xs:  560px;  /* intro / lead paragraphs */

    /* ── Character-based widths (typography line-length) ───────── */
    --measure-lg:    56ch;   /* hero subtitles, descriptions */
    --measure-sm:    18ch;   /* hero titles (forces line break) */
}

/* ─── Reset ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { font-size: 16px; -webkit-font-smoothing: subpixel-antialiased; overflow-x: clip; }

body {
    font-family: var(--font);
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    /* Pair with the html-level overflow-x: clip so the off-canvas
       .nav-drawer doesn't push the page's scrollable width out and
       leak its drop-shadow into the right margin. */
    overflow-x: clip;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

/* ─── Typography ─────────────────────────────────────────────────── */
h1, h2, h3, h4, h5 {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.4;
    color: var(--navy);
}

h1 { font-size: clamp(2rem, 5vw, 3.25rem); font-weight: 800; letter-spacing: -.02em; }
h2 { font-size: clamp(1.5rem, 3.5vw, 2.25rem); font-weight: 800; letter-spacing: -.01em; }
h3 { font-size: 1.25rem; font-weight: 700; }
h4 { font-size: 1rem; font-weight: 700; }

p { font-size: 1rem; line-height: 1.75; color: var(--text-muted); }

.lead { font-size: 1.25rem; color: var(--text); font-weight: 400; line-height: 1.65; }
.overline {
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--navy);
}
.overline--light { color: var(--mint); }

/* ─── Layout ─────────────────────────────────────────────────────── */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 24px;
}

.section { padding: var(--section-lg) 0; }
/* Background variants */
.section--surface { background: var(--surface); }
.section--navy    { background: var(--navy); }
.section--amber   {                                  /* sponsor / partner emphasis */
    background: var(--amber-soft);
    border-top: 3px solid var(--amber);
    border-bottom: 3px solid var(--amber);
}
/* Vertical-padding variants — for content-dense pages where the default
   --section-lg (96px) is too airy. Compose alongside background variants. */
.section--md { padding: var(--section-md) 0; }
.section--sm { padding: var(--section-sm) 0; }
.section--xs { padding: var(--section-xs) 0; }

/* ─── Accent-color rule: mint on white, navy on surface ─────────────────
   Components that use a colored accent (top stripe, donut fill, etc.) flip
   from mint → navy when nested inside a surface-bg section. Keeps the
   contrast pair consistent: the highlight color always sits ~1 step away
   from the section background.

   Currently applies to:
     - .surface--accent-top (top stripe on cards / context cards / stat
       cards / donut wrapper)
     - .donut-chart__fill (the filled portion of the donut ring)
*/
.section--surface .surface--accent-top { border-top-color: var(--navy); }
.section--surface .donut-chart__fill   { stroke: var(--navy); }

/* ─── Detail-page layout · canonical pattern ────────────────────────────
   Page-body wrapper for CPT detail pages (school profile, event campaign,
   student profile). Main content on the left, sticky context card on the
   right. The aside follows the user's scroll within its own column so the
   primary CTA stays visible.

   Composes:
     .detail-layout         — outer container (uses canonical .container conventions)
     .detail-layout__main   — main scrolling content (where .section bands live)
     .detail-layout__aside  — sticky right-rail (typically holds .context-card)

   Aside is fixed 320px wide on desktop. Mobile collapses to 1 column and
   aside is display: none (mobile uses .fixed-cta-bar instead).

   Section colored backgrounds (.section--surface, --amber) inside the main
   column are confined to that column — intentional. Detail pages with
   sticky asides shouldn't use full-viewport color bands.
*/
/* ─── Detail page layout · canonical 2-column primitive ─────────────────
   Main content (1fr) + 300px sidebar with sticky aside (default).
   Used by school profile, article single, article category (with the
   --no-sticky-aside modifier), per-list rankings, and any future
   detail-style page with a right-rail. */
.detail-layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: var(--gap-xl);
    align-items: start;
}
.detail-layout__main { min-width: 0; }   /* prevent grid blowout from wide children */
.detail-layout__aside {
    position: sticky;
    top: calc(var(--nav-height) + var(--gap-md));
    align-self: start;
}
.detail-layout--no-sticky-aside .detail-layout__aside {
    position: static;
    top: auto;
}
@media (max-width: 960px) {
    .detail-layout { grid-template-columns: 1fr; gap: var(--gap-lg); }
    /* Aside still renders on mobile — falls below main content (source-order
       second + 1-col grid). */
    .detail-layout__aside { position: static; top: auto; }
}

/* Colored section bands inside the layout get more inner padding so they
   read as contained cards (not just full-width strips). The default
   .container 24px feels tight when the colored band is constrained to
   a column width — bump to --card-pad-lg (32px). */
.detail-layout__main .section--surface > .container,
.detail-layout__main .section--amber > .container {
    padding-left: var(--card-pad-lg);
    padding-right: var(--card-pad-lg);
}

/* ─── School profile page wrapper · used only by single-school.php ──────
   Provides the page-level max-width + padding for the school-profile
   detail page. The bottom --section-md adds the gap below the layout
   before the CTA band. The aside needs an extra top push to align with
   the first section's content (which sits below its own padding-top). */
.sp-prof-page {
    max-width: var(--container-max);
    margin: 0 auto;
    padding: 0 24px var(--section-md);
}
.sp-prof-page .detail-layout__aside { margin-top: var(--section-md); }
@media (max-width: 720px) {
    .sp-prof-page { padding: 0 16px var(--section-md); }
}
@media (max-width: 960px) {
    /* Mobile: hide the sticky context-card (the lead-admissibility drawer
       handles conversion); other sidebar widgets remain visible. */
    .sp-prof-page .detail-layout__aside .context-card { display: none; }
}

/* ─── Context card · canonical right-rail snapshot + CTA ────────────────
   Sticky right-rail card on detail pages. Snapshot of the most important
   stats at top, primary action at bottom. Visible from the moment a user
   lands on the page; scrolls with them.

   Composes:
     .context-card                 — outer surface
     .context-card__stats          — vertical stack of label-value rows
     .context-card__stat-row       — single label-value row
     .context-card__stat-label     — left side (muted)
     .context-card__stat-value     — right side (bold navy)
     .context-card__divider        — horizontal rule between blocks
     .context-card__actions        — vertical button + link stack
*/
/* Context card — composes with .surface (no top accent — kept clean
   per design call). Stats are a borderless vertical stack of label/value
   rows; CTA buttons stack below. */
.context-card {
    padding: var(--card-pad-md);
}
/* Spacing below the context-card when other sidebar widgets follow it
   (school profile aside has sticky CTA + popular-articles + recently-viewed
   stacked). .cat-side-section has margin-bottom but no margin-top, so the
   gap has to come from the context-card. */
.detail-layout__aside .context-card { margin-bottom: var(--gap-lg); }
/* Compound selector to win over .heading-card { margin: 0 } defined later
   in the file (both single-class selectors have the same specificity, so
   later wins on tie). --gap-md is the canonical default for content gaps. */
.context-card .context-card__title {
    margin: 0 0 var(--gap-md);
}
.context-card__stats {
    list-style: none;
    margin: 0 0 var(--gap-md);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
}
.context-card__stats > li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--gap-sm);
    font-size: .9375rem;
}
.context-card__stat-label {
    color: var(--text-muted);
}
.context-card__stat-value {
    color: var(--navy);
    font-weight: 700;
}
.context-card__actions {
    display: flex;
    flex-direction: column;
    gap: var(--gap-2xs);
}
.context-card__stat-value--mint { color: var(--mint-dark); }

/* Navy variant — composes onto .context-card. The white version (default,
   above) stays intact; navy modifier inverts surfaces + text for use on
   detail pages where the right-rail card needs more visual weight. */
.context-card--navy {
    background: var(--navy);
    color: #fff;
    padding: var(--card-pad-md);
}
.context-card--navy .context-card__title       { color: #fff; }
.context-card--navy .context-card__stat-label  { color: rgba(255,255,255,.6); }
.context-card--navy .context-card__stat-value  { color: #fff; }
.context-card--navy .context-card__stat-value--mint { color: var(--mint); }

/* ─── Fixed-bottom CTA bar · mobile-only conversion anchor ──────────────
   Replaces the sticky right-rail on mobile (where there's no room for an
   aside). Anchored to the bottom of the viewport, padded to clear the
   safe area on iOS. Holds one .btn--primary. Hidden on desktop (the
   .context-card already provides the CTA there).
*/
.fixed-cta-bar {
    display: none;
}
@media (max-width: 960px) {
    .fixed-cta-bar {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 50;
        padding: var(--gap-xs) 16px calc(var(--gap-xs) + env(safe-area-inset-bottom));
        background: rgba(255,255,255,.96);
        backdrop-filter: blur(8px);
        border-top: 1px solid var(--border);
        box-shadow: 0 -4px 16px rgba(13,40,64,.08);
    }
    .fixed-cta-bar .btn { width: 100%; justify-content: center; }
}

/* ─── Two-column layout · canonical pattern ─────────────────────────────
   For content-split layouts: hero halves, form + sidebar, About photo +
   copy, etc. Stacks to single column on mobile (≤ 720px). For sidebar-
   fixed-width layouts (article single, school listing) see their bespoke
   patterns — different shape (fixed-px sidebar, not fr-based ratio).
*/
.layout-2col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-lg);
    align-items: start;
}
.layout-2col--hero,
.layout-2col--wide-left  { grid-template-columns: 3fr 2fr; }
.layout-2col--wide-right { grid-template-columns: 2fr 3fr; }
@media (max-width: 720px) {
    .layout-2col,
    .layout-2col--hero,
    .layout-2col--wide-left,
    .layout-2col--wide-right { grid-template-columns: 1fr; }
}
/* Reverse stack order on mobile (right column appears above left).
   Useful when the right column carries trust signals or important
   context that should precede the form ask on mobile. */
@media (max-width: 720px) {
    .layout-2col--mobile-reverse > :first-child { order: 2; }
    .layout-2col--mobile-reverse > :last-child  { order: 1; }
}

/* ─── Buttons ────────────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 14px 28px;
    border-radius: var(--radius);
    font-family: var(--font);
    font-size: .9375rem;
    font-weight: 700;
    cursor: pointer;
    border: 2px solid transparent;
    transition: all .18s ease;
}

.btn--primary {
    background: var(--amber);
    color: var(--navy);
}
.btn--primary:hover {
    background: var(--amber-dark);
    color: var(--navy);
}

/* .btn--secondary IS the mint button. (`.btn--mint` is just an alias for
   readability — same rules apply.) Use either name interchangeably. */
.btn--secondary,
.btn--mint {
    background: var(--mint);
    color: var(--navy);
}
.btn--secondary:hover,
.btn--mint:hover {
    background: #3cc490;
    color: var(--navy);
}

.btn--outline {
    background: transparent;
    border-color: var(--navy);
    color: var(--navy);
}
.btn--outline:hover {
    background: var(--navy);
    color: #fff;
}

.btn--ghost-white {
    background: rgba(255,255,255,.12);
    border-color: rgba(255,255,255,.4);
    color: #fff;
}
.btn--ghost-white:hover {
    background: rgba(255,255,255,.22);
}

/* Full-width button modifier — pairs with any color modifier */
.btn--block {
    width: 100%;
    justify-content: center;
}

/* Small button modifier */
.btn--sm {
    padding: 10px 16px;
    font-size: .875rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   CANONICAL COMPONENTS — the rulebook
   ═══════════════════════════════════════════════════════════════════════════
   Shared components that replace per-page bespoke variants. New code should
   use these classes; older callsites are being migrated to them. See the
   style guide page for usage examples.
*/

/* ─── Default link — applies to any <a> not given a specific class ───── */
/* Uses :where() so specificity is zero — any class-based color wins.
   We deliberately do NOT add a global :hover rule, since that would
   override component hover behavior (buttons, badges, pills). Components
   that need hover feedback define it themselves. .prose a has its own. */
:where(a) {
    color: var(--navy);
    transition: color var(--ease-fast);
}

/* ─── Global focus-visible — a11y default for non-input interactives ───── */
button:focus-visible,
a:focus-visible,
[tabindex]:focus-visible,
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible,
label.form-card:focus-visible,
.form-pill:focus-visible {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}

/* ─── Overlines — small uppercase labels ───────────────────────────────── */
.overline {
    display: block;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--navy);
    line-height: 1.4;
}
.overline--sm { font-size: .625rem; }
.overline--lg { font-size: .75rem; }
.overline--muted    { color: var(--text-muted); }
.overline--mint     { color: var(--mint-dark); }
.overline--on-dark  { color: rgba(255,255,255,.65); }
.overline--on-dark.overline--mint { color: var(--mint); }

/* ─── Badge · canonical informational label (2026-05-11) ────────────────────
   New canon. Replaces .pill for category/identity labels (school level,
   sponsored marker, sticker on a card). Non-interactive — never a link's
   primary affordance. Pairs with .tag (interactive inline taxonomy) and
   .chip (removable filter token). Existing .pill usage stays valid; new
   code should prefer the .badge / .tag / .chip trio. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.5;
    background: #fff;
    color: var(--navy);
    border: 1px solid var(--border);
    text-decoration: none;
    transition: background-color .15s, color .15s, border-color .15s;
}
.badge--mint    { background: var(--mint-light); color: var(--mint-dark); border-color: var(--mint-border); }
.badge--amber   { background: var(--amber); color: var(--navy); border-color: transparent; }
.badge--solid   { background: var(--navy); color: #fff; border-color: var(--navy); }
.badge--outline { background: transparent; color: var(--text-muted); border-color: var(--border); font-weight: 600; }

/* Size modifiers — most badges sit at default; sm/xs for dense rows
   (inline meta lines, compact listing cards). */
.badge--sm { font-size: .6875rem; padding: 3px 8px; }
.badge--xs { font-size: .625rem;  padding: 2px 6px; min-width: 18px; text-align: center; font-weight: 800; }

/* Level-color modifiers on .badge — for decorative level labels inside
   contexts that are NOT themselves the clickable affordance for the level
   (e.g., a tier preview card whose whole body is a link to /dich-vu/, with
   a level label inside that's decorative, not a per-level navigation handle).
   Use .tag--level-* when the level surface IS the clickable affordance
   (school card, listing pages, school profile header). */
.badge--level-uni { background: var(--level-uni-bg); color: var(--level-uni-fg); border-color: transparent; text-transform: uppercase; }
.badge--level-hs  { background: var(--level-hs-bg);  color: var(--level-hs-fg);  border-color: transparent; text-transform: uppercase; }
.badge--level-cc  { background: var(--level-cc-bg);  color: var(--level-cc-fg);  border-color: transparent; text-transform: uppercase; }
a.badge--level-uni:hover { background: var(--level-uni-fg); color: #fff; }
a.badge--level-hs:hover  { background: var(--level-hs-fg);  color: #fff; }
a.badge--level-cc:hover  { background: var(--level-cc-fg);  color: #fff; }

/* On-dark variants — for hero badges over navy backgrounds */
.badge--on-dark {
    background: rgba(255,255,255,.07);
    color: rgba(255,255,255,.65);
    border: 1.5px solid rgba(255,255,255,.25);
    text-transform: uppercase;
}
.badge--on-dark--uni   { background: rgba(122,163,245,.15); color:#93BBFA; border:1.5px solid #7AA3F5; text-transform: uppercase; }
.badge--on-dark--hs    { background: rgba(255,140,80,.15);  color:#FFA875; border:1.5px solid #FF9F66; text-transform: uppercase; }
.badge--on-dark--cc    { background: rgba(180,140,255,.15); color:#C9A8FF; border:1.5px solid #B48CFF; text-transform: uppercase; }
/* Anchor variants — solid fill on hover, navy text (the border color
   becomes the background so the level taxonomy stays intact). */
a.badge--on-dark--uni:hover { background:#7AA3F5; color: var(--navy); border-color:#7AA3F5; }
a.badge--on-dark--hs:hover  { background:#FF9F66; color: var(--navy); border-color:#FF9F66; }
a.badge--on-dark--cc:hover  { background:#B48CFF; color: var(--navy); border-color:#B48CFF; }
.badge--on-dark--mint  { background: var(--overlay-mint-faint); color: var(--mint); border:1.5px solid var(--mint); text-transform: uppercase; }
.badge--on-dark--amber { background: var(--overlay-amber-faint); color: var(--amber); border:1.5px solid var(--amber); text-transform: uppercase; }
/* Inline SVG star inside a badge — used for sponsored "Nổi bật" markers.
   Replaces the Unicode ★ which doesn't render reliably across all systems
   (Be Vietnam Pro lacks the glyph and the fallback chain isn't always caught). */
.badge__star { vertical-align: -1px; margin-right: 1px; flex-shrink: 0; }

/* ─── Chip · interactive removable filter token ───────────────────────────
   For active-filter UI: "Đại học ×", "California ×". Click to remove.
   Chip is the ONLY intentionally pill-shaped component in the system —
   the 14px radius is part of its affordance vocabulary (the "removable
   token" feel). All other components stay square per canon. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 6px 5px 12px;
    font-size: .8125rem;
    line-height: 1.4;
    background: var(--navy);
    color: #fff;
    font-weight: 600;
    border: none;
    border-radius: 14px;
    cursor: default;
    font-family: inherit;
    transition: filter var(--ease-fast);
}
.chip__close { border-radius: 999px; }
.chip__label { font-weight: 600; }
/* When the entire chip is itself a <button> (e.g. a "Clear all" action with
   no inside __close button), it should signal interactivity. */
button.chip { cursor: pointer; }
button.chip:hover { filter: brightness(1.08); }
.chip__close {
    border: 0;
    background: transparent;
    color: rgba(255,255,255,.7);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
}
.chip__close:hover { background: rgba(255,255,255,.15); color: #fff; }
.chip--mint { background: var(--mint); color: var(--navy); }
.chip--mint .chip__close { color: rgba(13,40,64,.6); }
.chip--mint .chip__close:hover { background: var(--overlay-navy-faint); color: var(--navy); }
.chip--outline { background: #fff; color: var(--navy); border: 1px solid var(--border); }
.chip--outline .chip__close { color: var(--text-muted); }
.chip--outline .chip__close:hover { background: var(--surface); color: var(--navy); }

/* ─── Tag · inline taxonomy, clickable ─────────────────────────────────── */
.tag {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 4px 10px;
    font-size: .8125rem;
    line-height: 1.4;
    background: var(--surface);
    color: var(--navy);
    border: 1px solid transparent;
    text-decoration: none;
    font-weight: 500;
    transition: background var(--ease-fast), border-color var(--ease-fast);
}
.tag:hover {
    background: #fff;
    border-color: var(--mint);
    cursor: pointer;
}
.tag--mint { background: var(--mint-light); color: var(--mint-dark); }
.tag--mint:hover { background: var(--mint); color: var(--navy); border-color: var(--mint); }
.tag--outline {
    background: #fff;
    color: var(--text-muted);
    border-color: var(--border);
}
.tag--outline:hover { color: var(--navy); border-color: var(--mint); }

/* Level-color tag modifiers (DH/THPT/CĐ — junior_boarding renders as THPT).
   Level surfaces are ALWAYS clickable (navigation to filtered listings),
   so the level palette only ever wears the tag primitive — never badge.

   These overrides bring the .tag box metrics in line with the .badge
   look (centered alignment, 1.5 line-height, 1.5px border) so a level
   tag sitting next to a badge in a single header row reads as same-size. */
.tag--level-uni,
.tag--level-hs,
.tag--level-cc,
.tag--on-dark--uni,
.tag--on-dark--hs,
.tag--on-dark--cc {
    align-items: center;
    line-height: 1.5;
    border-width: 1.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    font-size: .75rem;
}
.tag--level-uni { background: var(--level-uni-bg); color: var(--level-uni-fg); }
.tag--level-hs  { background: var(--level-hs-bg);  color: var(--level-hs-fg);  }
.tag--level-cc  { background: var(--level-cc-bg);  color: var(--level-cc-fg);  }
.tag--level-uni:hover { background: var(--level-uni-fg); color: #fff; border-color: var(--level-uni-fg); }
.tag--level-hs:hover  { background: var(--level-hs-fg);  color: #fff; border-color: var(--level-hs-fg); }
.tag--level-cc:hover  { background: var(--level-cc-fg);  color: #fff; border-color: var(--level-cc-fg); }

/* On-dark variants — used in navy hero contexts (school profile header). */
.tag--on-dark--uni { background: rgba(122,163,245,.15); color:#93BBFA; border-color:#7AA3F5; }
.tag--on-dark--hs  { background: rgba(255,140,80,.15);  color:#FFA875; border-color:#FF9F66; }
.tag--on-dark--cc  { background: rgba(180,140,255,.15); color:#C9A8FF; border-color:#B48CFF; }
.tag--on-dark--uni:hover { background:#7AA3F5; color: var(--navy); border-color:#7AA3F5; }
.tag--on-dark--hs:hover  { background:#FF9F66; color: var(--navy); border-color:#FF9F66; }
.tag--on-dark--cc:hover  { background:#B48CFF; color: var(--navy); border-color:#B48CFF; }

.tag .tag__en {
    color: var(--text-muted);
    font-size: .75em;
    font-style: italic;
    font-weight: 400;
    margin-left: 4px;
}

/* ─── Surface — card background pattern ────────────────────────────────── */
.surface,
.school-card,
.sc-img,
.article-card,
.hub-featured-card,
.sidebar-widget,
.event-archive-card,
.tier-card,
.tier-preview-card,
.event-form__autocomplete-results {
    background: #fff;
    border: 1px solid var(--border);
}
.surface--subtle,
.sp-review-card {
    background: var(--surface);
    border: 1px solid var(--border);
}
.surface--form,
.event-form__guest-card,
.role-card__inner {
    border-width: 2px;
}
.surface--accent-top {
    border-top: 3px solid var(--mint);
}
.surface--accent-left,
.person-card {
    border-left: 4px solid var(--mint);
}

/* ─── Feature card · canonical (heading + description) ─────────────────
   Compact 2-line content card used in highlight grids ("what to expect"
   feature cards on landing pages, homepage trust blocks, service-tier
   feature lists). Surface bg + 3px mint top stripe. Composes inside any
   grid container — own grid layout is the consumer's choice.
*/
.feature-card {
    background: var(--surface);
    border-top: 3px solid var(--mint);
    padding: var(--card-pad-md);
}
.feature-card__heading {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--navy);
    margin: 0 0 var(--gap-2xs);
    line-height: 1.3;
}
.feature-card__description {
    font-size: .9375rem;
    color: var(--text-muted);
    line-height: 1.5;
    margin: 0;
}
/* On-dark variant — for use inside .section--navy or other dark surfaces */
.feature-card--on-dark {
    background: rgba(255,255,255,.06);
    border-top-color: var(--mint);
}
.feature-card--on-dark .feature-card__heading { color: #fff; }
.feature-card--on-dark .feature-card__description { color: rgba(255,255,255,.78); }

/* ─── Process steps · canonical sequential cards with connecting line ──
   Numbered step cards in a row, linked by a horizontal mint line that
   runs through the badge centerlines (above the cards). Says "this is a
   sequence." Used on the volunteer landing page (apply → interview →
   training → event), service-tier "how it works" sections, and any
   process explainer. Mobile: stacks vertically, line rotates to the
   left side and runs only between the first/last badges (no overshoot).

   Markup:
     <div class="process-steps">
       <article class="process-step">
         <span class="process-step__badge">1</span>
         <span class="overline overline--mint">5 phút</span>
         <h3 class="process-step__title">Đăng ký</h3>
         <p class="process-step__body">…</p>
       </article>
       … 2, 3, 4 …
     </div>
*/
.process-steps {
    position: relative;
    padding-top: 56px;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--gap-md);
}
.process-steps::before {
    content: '';
    position: absolute;
    top: 22px; left: 12.5%; right: 12.5%; height: 2px;
    background: var(--mint);
    border-radius: 0;
}
.process-step {
    position: relative;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: var(--card-pad-md);
    text-align: center;
    overflow: visible;
}
.process-step__badge {
    position: absolute;
    top: -56px; left: 50%; transform: translateX(-50%);
    width: 44px; height: 44px;
    border-radius: 999px;
    background: var(--mint);
    color: var(--navy);
    border: 4px solid var(--surface);
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 1.0625rem;
    z-index: 2;
}
.process-step__title {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.3;
    margin: 0 0 var(--gap-2xs);
}
.process-step__body {
    font-size: .9375rem;
    line-height: 1.5;
    color: var(--text-muted);
    margin: 0;
}
/* 3-step variant — same component, different column count */
.process-steps--3 { grid-template-columns: repeat(3, 1fr); }
.process-steps--5 { grid-template-columns: repeat(5, 1fr); }

/* Mobile: stack vertically. Wrap-level line is hidden; each card draws
   its own segment (per-card ::before) so the line ends cleanly at the
   last badge instead of overshooting to the bottom of the last card. */
@media (max-width: 720px) {
    .process-steps,
    .process-steps--3,
    .process-steps--5 {
        grid-template-columns: 1fr;
        padding-top: 0;
        padding-left: 56px;
    }
    .process-steps::before { display: none; }
    .process-step { text-align: left; padding-top: 24px; }
    .process-step::before {
        content: '';
        position: absolute;
        top: 0; bottom: -24px;
        left: -34px;
        width: 2px;
        background: var(--mint);
        z-index: 0;
    }
    .process-step:first-child::before { top: 44px; }
    .process-step:last-child::before  { bottom: auto; height: 44px; }
    .process-step__badge {
        top: 22px; left: -56px; transform: none;
    }
}

/* ─── Person card · photo + name + role/affiliation ────────────────────
   Compact horizontal card: round photo on the left, name + role on the
   right. Used for panelist grids on event pages, future team / about
   pages, future student profile cards. Mint left-edge accent (shares the
   .surface--accent-left family above).
*/
.person-card {
    display: flex;
    align-items: center;
    gap: var(--gap-sm);
    padding: var(--card-pad-md);
    background: #fff;
    border: 1px solid var(--border);
    /* border-left mint comes from the grouped selector above */
}
.person-card__photo {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
}
.person-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.person-card__photo-placeholder {
    color: var(--mint-dark);
    font-weight: 700;
    font-size: 1.25rem;
    text-transform: uppercase;
    line-height: 1;
}
.person-card__info {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.person-card__name {
    color: var(--navy);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.3;
}
.person-card__role {
    color: var(--text-muted);
    font-size: .875rem;
    line-height: 1.4;
    margin-top: 2px;
}

/* ─── Stat callout · big value + small label ───────────────────────────
   Two stacked elements: a bold value (number or short keyword) on top,
   a small muted label below. Used in clusters (trust bars, About-page
   stats, future hero stats, future client reports). Cluster wrapper
   .stat-callout-row centers and gaps the row appropriately.
*/
.stat-callout {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    text-align: center;
}
.stat-callout__value {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.2;
}
.stat-callout__label {
    font-size: .8125rem;
    color: var(--text-muted);
    line-height: 1.4;
}
.stat-callout-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px 36px;
}
/* On-dark — mint value, white-muted label. For use inside .section--navy. */
.stat-callout--on-dark .stat-callout__value { color: var(--mint); }
.stat-callout--on-dark .stat-callout__label { color: rgba(255,255,255,.75); }
/* Large — for hero/About emphasis where the number is the headline */
.stat-callout--lg .stat-callout__value { font-size: 2.5rem; font-weight: 800; }
.stat-callout--lg .stat-callout__label { font-size: .9375rem; }

/* ─── donut-chart · canonical percentage donut ──────────────────────────
   Compact SVG donut for percentage stats (e.g. % international students,
   % boarding, acceptance rate). Visual instead of numeric — for stats
   where the proportion matters more than the raw number.

   Markup: a wrapper, a fixed-size SVG well, the value overlaid in the
   centre, then a label below. Math: a circle of r=15.91 has circumference
   ≈ 100, so stroke-dasharray="X 100" fills X percent.

   Composes:
     .donut-chart                — outer wrapper (centered column)
     .donut-chart__well          — square positioning context for SVG + value
     .donut-chart__svg           — the actual circles
     .donut-chart__bg            — empty (background) ring
     .donut-chart__fill          — filled portion (controlled by stroke-dasharray inline)
     .donut-chart__value         — centred percentage text overlay
     .donut-chart__label         — caption beneath
     .donut-chart--sm            — smaller (for inline use in stat rows)
*/
.donut-chart {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: var(--gap-2xs);
}
.donut-chart__well {
    position: relative;
    width: 100px;
    height: 100px;
}
.donut-chart__svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);  /* start at 12 o'clock */
}
.donut-chart__bg {
    fill: none;
    stroke: var(--border);
    stroke-width: 3;
}
.donut-chart__fill {
    fill: none;
    stroke: var(--mint);
    stroke-width: 3;
    stroke-linecap: round;
    transition: stroke-dasharray .8s ease;
}
.donut-chart__value {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--navy);
    letter-spacing: -.02em;
}
.donut-chart__label {
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-light);
    text-align: center;
    max-width: 140px;
    line-height: 1.3;
}
/* Smaller variant for dense rows */
.donut-chart--sm .donut-chart__well { width: 72px; height: 72px; }
.donut-chart--sm .donut-chart__value { font-size: 1rem; }

/* ─── Sponsored content · canonical school-supplied blocks ────────────────
   Three patterns for school-provided promotional content (only rendered
   when wp_schools.is_sponsored = 1). Each composes with .surface and
   carries a small mint-coloured overline marker — readable as editorial
   "from the school" content rather than banner-ad chrome.

     .school-quote      — pull-quote treatment for message_from_school
     .school-highlights — 2-col point grid for school_reasons_general
     .school-vn-callout — VN-targeted bullet list for school_reasons_vietnamese

   All three live INSIDE their parent section as a final sub-block (visually
   distinct surface card without breaking the section flow).
*/

/* Generic expand/collapse visibility rules.
   Markup convention:
     <wrapper data-expandable>
       <text>preview<span data-collapsed-only>…</span><span data-expanded-only> overflow</span></text>
       <button data-toggle-text data-expand-label="..." data-collapse-label="...">...</button>
     </wrapper>
   JS toggles .is-expanded on the wrapper; CSS below handles visibility.
   Used by sp-about, school-quote (and any future expand/collapse widgets). */
[data-expandable]:not(.is-expanded) [data-expanded-only] { display: none; }
[data-expandable].is-expanded [data-collapsed-only] { display: none; }

/* Common shell + overline + toggle button */
.school-quote,
.school-highlights,
.school-vn-callout {
    padding: var(--card-pad-lg);
    margin-top: var(--gap-lg);
}
.school-quote__overline,
.school-highlights__overline,
.school-vn-callout__overline {
    margin-bottom: var(--gap-md);
    color: var(--mint-dark);
}
.school-quote__toggle,
.school-highlights__toggle,
.school-vn-callout__toggle {
    background: none;
    border: none;
    padding: 0;
    margin-top: var(--gap-md);
    color: var(--navy);
    font: 600 .875rem var(--font);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.school-quote__toggle:hover,
.school-highlights__toggle:hover,
.school-vn-callout__toggle:hover { color: var(--mint-dark); }

/* A) school-quote */
.school-quote {
    position: relative;
}
.school-quote__mark {
    position: absolute;
    top: var(--card-pad-lg);
    left: var(--card-pad-lg);
    width: 36px;
    height: 36px;
    color: var(--mint);
    opacity: .4;
    pointer-events: none;
}
.school-quote__body {
    padding-left: 52px;
    max-width: var(--container-sm);
}
.school-quote__text {
    font-size: 1.0625rem;
    font-style: italic;
    line-height: 1.7;
    color: var(--text);
    margin: 0;
}
.school-quote__attribution {
    font-size: .875rem;
    color: var(--text-muted);
    margin: var(--gap-md) 0 0;
}

/* B) school-highlights */
.school-highlights__grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-md) var(--gap-xl);
}
@media (max-width: 720px) {
    .school-highlights__grid { grid-template-columns: 1fr; }
}
.school-highlights__item {
    display: flex;
    align-items: flex-start;
    gap: var(--gap-xs);
}
.school-highlights__check {
    color: var(--mint-dark);
    font-weight: 800;
    flex-shrink: 0;
    line-height: 1.5;
    font-size: 1rem;
}
.school-highlights__text {
    margin: 0;
    font-size: .9375rem;
    line-height: 1.55;
    color: var(--text);
}
.school-highlights:not(.is-expanded) .school-highlights__item--collapsed { display: none; }

/* C) school-vn-callout */
.school-vn-callout__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--gap-xs);
}
.school-vn-callout__item {
    position: relative;
    padding-left: 22px;
    font-size: .9375rem;
    line-height: 1.6;
    color: var(--text);
}
.school-vn-callout__item::before {
    content: '•';
    position: absolute;
    left: 6px;
    top: -1px;
    color: var(--mint-dark);
    font-size: 1.125rem;
    font-weight: 800;
    line-height: 1.6;
}
.school-vn-callout:not(.is-expanded) .school-vn-callout__item--collapsed { display: none; }

/* ─── Tooltip · canonical hover/tap explainer ─────────────────────────────
   Two pieces:
     .tooltip-trigger  — the inline <button> a user hovers / taps. Markup:
        <button class="tooltip-trigger" type="button" data-tooltip="text..."
                aria-label="Giải thích">
          <svg class="tooltip-icon">…ⓘ…</svg>
        </button>
     .tooltip          — the navy bubble itself. Created on demand by
        assets/js/tooltip.js, positioned above the trigger (or below if
        no room), removed on close.

   Use sparingly — only for terms that genuinely need explanation
   (location_type, IB program, etc.). Don't litter the page with ⓘs.
*/
.tooltip-trigger {
    /* Inline-block + relative top tweak gives reliable cap-height alignment
       across font-sizes (inline-flex + vertical-align was sitting too low
       because the flex baseline = bottom of icon box). */
    display: inline-block;
    background: none;
    border: none;
    padding: 0;
    margin: 0 1px 0 3px;
    cursor: help;
    color: var(--text-light);
    line-height: 1;
    position: relative;
    top: 2px;
    transition: color var(--ease-fast);
}
.tooltip-trigger:hover,
.tooltip-trigger:focus { color: var(--navy); outline: none; }
.tooltip-trigger:focus-visible { outline: var(--focus-outline); outline-offset: var(--focus-offset); }
.tooltip-icon {
    display: block;
    width: 13px;
    height: 13px;
}
.tooltip {
    position: absolute;
    z-index: 100;
    background: var(--navy);
    color: #fff;
    padding: 10px 14px;
    font-size: .8125rem;
    font-weight: 400;
    line-height: 1.5;
    max-width: 240px;
    box-shadow: var(--shadow-md);
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--ease-fast);
}
.tooltip.is-visible { opacity: 1; pointer-events: auto; }
.tooltip::after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    border: 6px solid transparent;
    left: 50%;
    transform: translateX(-50%);
}
.tooltip[data-position="top"]::after    { bottom: -12px; border-top-color: var(--navy); }
.tooltip[data-position="bottom"]::after { top: -12px; border-bottom-color: var(--navy); }

/* ─── Headings — outside .prose ────────────────────────────────────────── */
.heading-display {
    font-size: clamp(2rem, 5vw, 3.25rem);
    font-weight: 800;
    color: var(--navy);
    line-height: 1.2;
    letter-spacing: -.02em;
    margin: 0;
}
.heading-1 {
    font-size: clamp(1.75rem, 4vw, 2.5rem);
    font-weight: 800;
    color: var(--navy);
    line-height: 1.25;
    letter-spacing: -.01em;
    margin: 0;
}
.heading-2 {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1.3;
    margin: 0;
}
.heading-3 {
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1.35;
    margin: 0;
}
.heading-card {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.3;
    margin: 0;
}
.heading-card-sm {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.3;
    margin: 0;
}

/* ─── Section title with mint underline ────────────────────────────────
   Canonical: .section-title-mint (1.5rem) + .section-title-mint--sm (1rem)
   for sidebar contexts. Parent-scoped margin overrides below add the
   bottom gap suited to each layout (school profile, rankings hub, sidebar). */
.section-title-mint {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0;
    letter-spacing: -.01em;
    position: relative;
    padding-bottom: 12px;
    line-height: 1.3;
}
.section-title-mint::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 32px;
    height: 2px;
    background: var(--mint);
}

.section-title-mint--sm {
    font-size: 1rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0;
    letter-spacing: -.01em;
    position: relative;
    padding-bottom: 10px;
    line-height: 1.3;
}
.section-title-mint--sm::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 24px;
    height: 2px;
    background: var(--mint);
}

.section-title-mint--on-dark { color: #fff; }

/* Parent-scoped margin overrides — the title inherits margin:0 from the
   canonical; the parent layout decides the bottom gap. */
.sp-prof-section .section-title-mint     { margin-bottom: 18px; }
.rankings-section .section-title-mint    { margin-bottom: 20px; }
.cat-side-section .section-title-mint--sm { margin-bottom: 14px; }

/* ─── Lists — canonical patterns ───────────────────────────────────────── */
.list-bullet {
    list-style: none;
    padding: 0;
    margin: 0;
}
.list-bullet > li {
    padding-left: 1.25em;
    position: relative;
    margin-bottom: .5em;
}
.list-bullet > li:last-child { margin-bottom: 0; }
.list-bullet > li::before {
    content: '';
    position: absolute;
    left: 0;
    top: .55em;
    width: 5px;
    height: 5px;
    background: var(--mint);
}

.list-counter {
    list-style: none;
    padding-left: 1.75em;
    margin: 0;
    counter-reset: list-counter;
}
.list-counter > li {
    counter-increment: list-counter;
    padding-left: .25em;
    position: relative;
    margin-bottom: .5em;
}
.list-counter > li:last-child { margin-bottom: 0; }
.list-counter > li::before {
    content: counter(list-counter) ".";
    position: absolute;
    left: -1.75em;
    font-weight: 700;
    color: var(--navy);
}

.list-rows {
    list-style: none;
    padding: 0;
    margin: 0;
}
.list-rows > li {
    border-top: 1px solid var(--border);
    padding: 14px 0;
}
.list-rows > li:last-child { border-bottom: 1px solid var(--border); }

/* ─── Action links — "see all", "more", "back" ─────────────────────────── */
.link-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .875rem;
    font-weight: 700;
    color: var(--navy);
    text-decoration: none;
    transition: color var(--ease-fast);
}
.link-action__arrow {
    display: inline-block;
    transition: transform var(--ease-base);
}
.link-action:hover { color: var(--mint-dark); }
.link-action:hover .link-action__arrow { transform: translateX(3px); }

.link-action--back {
    font-size: .8125rem;
    font-weight: 600;
    color: var(--text-muted);
}
.link-action--back:hover { color: var(--navy); }
.link-action--back:hover .link-action__arrow { transform: translateX(-3px); }

/* ─── Inline CTAs — small underlined utility links ─────────────────────── */
.link-inline {
    color: var(--text-muted);
    font-size: .8125rem;
    text-decoration: underline;
    text-decoration-color: var(--mint);
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
    transition: color var(--ease-fast);
}
.link-inline:hover { color: var(--navy); }

.link-inline--on-dark {
    color: var(--mint);
}
.link-inline--on-dark:hover { color: #fff; text-decoration-color: #fff; }

/* ─── Nav ────────────────────────────────────────────────────────── */
/* ── Site header ─────────────────────────────────────────────────── */
.site-nav {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--navy);
    /* V3 Header C — 2px mint accent runs across the bottom of the bar */
    border-bottom: 2px solid var(--mint);
}

.site-nav__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: var(--nav-height);
}

.site-nav__logo {
    display: flex;
    align-items: center;
    gap: 14px;
    color: #fff;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.25rem;
    letter-spacing: -.01em;
    flex-shrink: 0;
}

.site-nav__logo-icon {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    display: block;
}

/* Wordmark hover — mint underline draws left-to-right via background-size
   animation. background-image is a 2px-tall solid mint line; we just
   animate its width from 0 → 100% on parent hover. Keyboard focus on
   the parent link gets the same treatment for a11y. */
.site-nav__wordmark {
    background-image: linear-gradient(var(--mint), var(--mint));
    background-size: 0 2px;
    background-position: 0 100%;
    background-repeat: no-repeat;
    transition: background-size .35s ease-out;
    padding-bottom: 2px;
}
.site-nav__logo:hover .site-nav__wordmark,
.site-nav__logo:focus-visible .site-nav__wordmark {
    background-size: 100% 2px;
}

.site-nav__links {
    display: flex;
    align-items: center;
    gap: 36px;
    list-style: none;
}

.site-nav__links a {
    color: #fff;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: .02em;
    padding-bottom: 6px;
    border-bottom: 2px solid transparent;
    transition: border-color .15s;
}
.site-nav__links a:hover { border-bottom-color: rgba(79,217,164,.5); }
.site-nav__links a.is-active {
    border-bottom-color: var(--mint);
}

.site-nav__actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Nav CTA — amber on navy. Amber is the canonical "primary CTA" color
   (matches .btn--primary). Earlier mint version was a wrong call. */
.site-nav__cta {
    display: inline-block;
    background: var(--amber);
    color: var(--navy);
    padding: 11px 22px;
    border-radius: var(--radius);
    font-weight: 800;
    font-size: .9375rem;
    /* Hover matches canonical .btn--primary: clean color swap, no lift,
       no shadow glow. Compact padding stays for the nav slot. */
    transition: background .15s;
    white-space: nowrap;
}
.site-nav__cta:hover {
    background: var(--amber-dark);
}

/* Hamburger button */
.site-nav__hamburger {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 36px;
    height: 36px;
    padding: 4px;
    background: transparent;
    border: none;
    cursor: pointer;
}
.site-nav__hamburger span {
    display: block;
    width: 100%;
    height: 2px;
    background: #fff;
    border-radius: 2px;
    transition: opacity .2s;
}

/* ── Mobile nav drawer ───────────────────────────────────────────── */
/* Mobile nav drawer — sectioned navy editorial panel.
   Full-screen on phones (100vw), capped at 380px on tablet+.
   Sections (KHÁM PHÁ + TÌM HIỂU) reveal information architecture the
   horizontal desktop nav can't fit. White text on navy bg matches the
   desktop header's brand voice. */
.nav-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(380px, 100vw);
    background: var(--navy);
    color: #fff;
    z-index: 300;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform .25s ease, box-shadow .25s ease;
    /* No box-shadow when closed — even though the drawer itself is
       translated off-screen, the shadow's blur radius would paint back
       INTO the viewport and read as a mysterious dark band on the right
       edge of the page. Shadow appears only when drawer is open. */
}
.nav-drawer.is-open {
    transform: translateX(0);
    box-shadow: -4px 0 24px rgba(0,0,0,.18);
}

.nav-drawer__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px;
    height: var(--nav-height);
    border-bottom: 1px solid rgba(255,255,255,.08);
    flex-shrink: 0;
}
.nav-drawer__header .site-nav__logo { color: #fff; }
.nav-drawer__header .site-nav__wordmark { color: #fff; }

.nav-drawer__close {
    background: transparent;
    border: none;
    color: rgba(255,255,255,.55);
    cursor: pointer;
    padding: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.nav-drawer__close:hover { color: #fff; }

.nav-drawer__nav { flex: 1; padding: 8px 0; overflow-y: auto; }

/* Section grouping with overline labels — reveals IA the desktop nav
   can't expose because of horizontal-strip constraints. */
.nav-drawer__section { padding: 4px 0 6px; }
.nav-drawer__section + .nav-drawer__section { margin-top: 4px; }
.nav-drawer__overline {
    display: block;
    padding: 14px 24px 6px;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255,255,255,.4);
}

.nav-drawer__links {
    list-style: none;
    margin: 0;
    padding: 0;
}
.nav-drawer__links a {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 13px 24px;
    font-size: 1rem;
    font-weight: 600;
    color: #fff;
    border-left: 3px solid transparent;
    transition: color .15s, border-color .15s, background .15s;
    text-decoration: none;
}
.nav-drawer__link-text {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.nav-drawer__link-arrow {
    color: rgba(255,255,255,.3);
    font-size: 1.1rem;
    line-height: 1;
    transition: transform .15s ease, color .15s ease;
}
.nav-drawer__links a:hover {
    background: rgba(255,255,255,.06);
    color: #fff;
}
.nav-drawer__links a:hover .nav-drawer__link-arrow {
    color: var(--mint);
    transform: translateX(2px);
}
/* "You-are-here" — mint left-rail accent persists when the drawer
   opens on the matching page. */
.nav-drawer__links a.is-active {
    color: #fff;
    border-left-color: var(--mint);
    background: rgba(79,217,164,.1);
}
.nav-drawer__links a.is-active .nav-drawer__link-arrow {
    color: var(--mint);
}

/* Live event count badge — sits inline with "Sự kiện sắp tới". */
.nav-drawer__badge {
    display: inline-block;
    padding: 1px 8px;
    font-size: .7rem;
    font-weight: 700;
    line-height: 1.5;
    background: var(--mint);
    color: var(--navy);
    border-radius: 999px;
}

.nav-drawer__footer {
    padding: 24px;
    border-top: 1px solid rgba(255,255,255,.08);
    flex-shrink: 0;
}
.nav-drawer__cta {
    display: block;
    text-align: center;
    width: 100%;
    padding: 13px 20px;
    font-size: 1rem;
}

/* Overlay */
.nav-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.5);
    z-index: 299;
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease;
}
.nav-overlay.is-visible {
    opacity: 1;
    pointer-events: auto;
}

@media (max-width: 768px) {
    .site-nav__desktop { display: none; }
    /* Hide ONLY the desktop header CTA, not the one in the drawer footer
       (which composes .site-nav__cta + .nav-drawer__cta). */
    .site-nav__cta:not(.nav-drawer__cta) { display: none; }
    .site-nav__hamburger { display: flex; }
}

/* ─── Hero ───────────────────────────────────────────────────────── */
.hero {
    background: var(--navy);
    padding: var(--section-lg) 0;
    position: relative;
    overflow: hidden;
}

.hero::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 70% 60% at 110% 50%, var(--overlay-mint-faint) 0%, transparent 70%);
    pointer-events: none;
}

.hero__inner {
    display: grid;
    grid-template-columns: 1fr 420px;
    gap: 60px;
    align-items: center;
}

.hero__overline { margin-bottom: 16px; }

.hero__title {
    color: #fff;
    margin-bottom: 20px;
}

.hero__title span { color: var(--mint); }

.hero__lead {
    color: rgba(255,255,255,.65);
    margin-bottom: 36px;
    font-size: 1.0625rem;
    max-width: var(--container-xs);
}

.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; }

.hero__card {
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.1);
    border-radius: var(--radius-lg);
    padding: 28px;
    backdrop-filter: blur(8px);
}

.hero__stat-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 20px;
}

.hero__stat {
    background: rgba(255,255,255,.05);
    border-radius: var(--radius);
    padding: 16px;
}

.hero__stat-number {
    font-size: 1.75rem;
    font-weight: 800;
    color: var(--mint);
    line-height: 1;
    margin-bottom: 4px;
}

.hero__stat-label {
    font-size: .75rem;
    color: rgba(255,255,255,.5);
    font-weight: 500;
}

.hero__trust {
    font-size: .8125rem;
    color: rgba(255,255,255,.45);
    text-align: center;
}

/* ─── Section header ─────────────────────────────────────────────── */
/* Canonical pattern for the title-block above a content section
   (a grid, a list, a card group). Composes:
   .section-header                 — base wrapper, 32px bottom margin
   .section-header__overline       — optional eyebrow (use .overline classes too)
   .section-header__title          — title (heading-2 default, .heading-3 in --with-action variant)
   .section-header__sub            — subtitle / count (text-muted, .9375rem)
   .section-header--with-action    — flex justify-between, action link goes on the right
   .section-header--center         — centered alignment, larger subtitle
   .section-header__action         — slot on the right for a .link-action

   Old aliases (.section-heading, .hub-section-header, .hub-category__header,
   .related-widget__header, .sp-section__heading) continue to work via grouped
   selectors below. */
.section-header,
.section-heading,
.hub-section-header {
    margin-bottom: var(--gap-lg);  /* 32px canonical */
}
/* Eyebrow spacing — any .overline immediately followed by a heading
   gets 16px gap below it. Catches both the canonical .section-header
   pattern AND bare overline+heading combos (which exist in places we
   haven't migrated yet). Stat labels and column headers aren't followed
   by headings, so they're unaffected. */
.overline:has(+ h1, + h2, + h3, + h4),
.section-header__overline,
.section-heading .overline {
    margin-bottom: var(--gap-xs);  /* 12px */
}
.section-header__title,
.section-heading h2,
.hub-section-header__title {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1.3;
    margin: 0 0 8px;  /* slight gap to subtitle / next content */
}
.section-header__sub,
.section-heading p,
.hub-section-header__sub {
    font-size: .9375rem;
    color: var(--text-muted);
    margin: 0;
    max-width: var(--container-sm);
}

/* With-action variant — title on left, action link on right */
.section-header--with-action,
.hub-category__header,
.related-widget__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--gap-sm);
}
/* Title in with-action variant uses heading-3 size since the section is denser */
.section-header--with-action .section-header__title,
.hub-category__title,
.related-widget__title {
    font-size: 1.25rem;
    font-weight: 800;
    margin: 0 0 4px;
}
.section-header--with-action .section-header__sub,
.hub-category__count {
    font-size: .8125rem;
}

/* Centered variant — larger subtitle, constrained width, used for hero-like
   section intros */
.section-header--center,
.section-heading--center {
    text-align: center;
}
.section-header--center .section-header__sub,
.section-heading--center p {
    margin: 0 auto;
    font-size: 1.0625rem;
}
.section-header--center .section-header__title,
.section-heading--center h2 {
    font-size: clamp(1.75rem, 4vw, 2.5rem);  /* heading-1 size for centered heroes */
}

/* ─── Page-level header ──────────────────────────────────────────── */
/* The hero block at the very top of a page (before any content sections).
   Composes background variant + size variant + optional center/split.
   Old class names (.hub-header, .cat-header, .article-header,
   .listing-hero, .event-hero, .campaign-hero, .event-archive__header,
   .event-form-section__header) route through this via grouped selectors
   below. */
.page-header,
.hub-header,
.cat-header,
.article-header,
.event-archive__header,
.event-form-section__header {
    padding: var(--section-md) 0;
}
.page-header__title,
.hub-header__title,
.cat-header__title,
.article-title,
.listing-hero__title,
.event-archive__title,
.event-form-section__heading,
.event-hero__title,
.campaign-hero__title {
    font-size: clamp(1.75rem, 4vw, 2.5rem);  /* canonical heading-1 */
    font-weight: 800;
    color: var(--navy);
    line-height: 1.25;
    letter-spacing: -.01em;
    margin: 0 0 var(--gap-xs);
}
.page-header__sub,
.hub-header__sub,
.event-archive__sub,
.event-form-section__subheading,
.event-hero__subtitle,
.campaign-hero__subtitle {
    font-size: 1.0625rem;
    color: var(--text-muted);
    line-height: 1.6;
    margin: 0;
    max-width: var(--container-sm);
}

/* Light-bg variant (default — surface or white) */
.page-header--surface { background: var(--surface); border-bottom: 1px solid var(--border); }
.page-header--white { background: var(--bg); border-bottom: 1px solid var(--border); }

/* Compact variant — for headers where content immediately follows
   (article, hub, cat) and we don't need the full --section-md bottom */
.page-header--compact,
.article-header,
.cat-header {
    padding: var(--section-sm) 0 var(--section-xs);
}
/* Hub header — gap-lg bottom keeps the tab-group's border off the
   section divider; no longer flush, since tabs are a segmented control. */
.hub-header {
    padding: var(--section-sm) 0 var(--gap-lg);
}

/* Navy variant — solid navy bg, white title, muted-white subtitle */
.page-header--navy,
.listing-hero,
.event-hero {
    background: var(--navy);
    color: #fff;
    padding: var(--section-md) 0;
}
.event-hero {
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
}
.page-header--navy .page-header__title,
.listing-hero__title,
.event-hero__title {
    color: #fff;
}
.page-header--navy .page-header__sub,
.listing-hero__sub,
.event-hero__subtitle {
    color: rgba(255,255,255,.75);
}

/* Hero variant — for marquee pages (dich-vu, future homepage). Heavier
   padding, larger title, optional eyebrow + CTA slots. Compose with any
   background variant (default is the same surface/navy/etc. rules). */
.page-header--hero {
    padding: var(--section-lg) 0;
}
.page-header--hero .page-header__title {
    font-size: clamp(2.25rem, 5.5vw, 3.5rem);
    line-height: 1.15;
    letter-spacing: -.02em;
}
.page-header--hero .page-header__sub {
    font-size: 1.25rem;
    line-height: 1.55;
    margin-top: var(--gap-sm);
    max-width: var(--container-md);
}
.page-header--hero .page-header__overline {
    display: inline-block;
    font-size: .75rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .08em;
    margin-bottom: var(--gap-sm);
    color: var(--mint);
}
.page-header--hero .page-header__actions {
    margin-top: var(--gap-lg);
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-sm);
}

/* Photo / hero variant — bigger padding, navy gradient bg with optional photo overlay slot */
.page-header--photo,
.campaign-hero {
    position: relative;
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
    color: #fff;
    overflow: hidden;
    padding: var(--section-lg) 0;
}
.page-header--photo .page-header__title,
.campaign-hero__title {
    color: #fff;
}
.page-header--photo .page-header__sub,
.campaign-hero__subtitle {
    color: rgba(255,255,255,.75);
}

/* Centered variant — for marketing-style page intros */
.page-header--center,
.event-archive__header,
.event-form-section__header {
    text-align: center;
}
.page-header--center .page-header__sub,
.event-archive__header,
.event-form-section__header {
    margin-left: auto;
    margin-right: auto;
}
.event-archive__sub,
.event-form-section__subheading {
    margin-left: auto;
    margin-right: auto;
}

/* ─── State patterns — empty / loading / error / success ────────── */
/* Canonical patterns for "this section/page has no content / is loading
   / failed / succeeded". Use these instead of inventing new patterns
   per page. Old class names (.no-results, .cat-empty, .event-archive__empty)
   alias to these via grouped selectors. Field-level error state lives on
   the canonical .form-field.is-error wrapper, not here. */

/* Empty state — centered block with optional icon + title + description + action */
.state-empty,
.no-results {
    text-align: center;
    padding: var(--section-md) var(--gap-md);
    color: var(--text-muted);
}
.state-empty__icon {
    display: inline-block;
    font-size: 1.75rem;
    color: var(--text-light);
    margin-bottom: var(--gap-xs);
}
.state-empty__title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    margin: 0 0 6px;
}
.state-empty__desc,
.no-results p,
.cat-empty,
.event-archive__empty {
    font-size: .9375rem;
    color: var(--text-muted);
    margin: 0 auto var(--gap-md);
    max-width: 36ch;
    line-height: 1.5;
}
.cat-empty,
.event-archive__empty {
    text-align: center;
    padding: var(--section-sm) var(--gap-md);
}

/* Loading state — block-level spinner + text */
.state-loading {
    text-align: center;
    padding: var(--section-md) var(--gap-md);
}
.state-loading__spinner {
    display: inline-block;
    width: 32px;
    height: 32px;
    border: 3px solid var(--surface);
    border-top-color: var(--mint);
    border-radius: 50%;
    animation: state-spin 1s linear infinite;
    margin-bottom: var(--gap-xs);
}
.state-loading__text {
    font-size: .875rem;
    color: var(--text-muted);
    margin: 0;
}
@keyframes state-spin { to { transform: rotate(360deg); } }

/* .is-loading — inline modifier for "this section is being refetched"
   (existing pattern: opacity fade + pointer-events none) */
/* .school-grid.is-loading already exists below; .is-loading promotes to a
   universal modifier any container can use */
.is-loading {
    opacity: .45;
    pointer-events: none;
    transition: opacity var(--ease-fast);
}

/* Skeleton placeholder — shimmer animation for first-load card grids */
.state-skeleton {
    background: linear-gradient(90deg,
        var(--surface) 0%,
        #e6ecf2 50%,
        var(--surface) 100%);
    background-size: 200% 100%;
    animation: state-shimmer 1.5s infinite;
    border-radius: 0;
}
@keyframes state-shimmer {
    0%   { background-position: -200% 0; }
    100% { background-position:  200% 0; }
}

/* Error state (block-level — for API failures, section load errors, etc.) */
.state-error {
    background: var(--danger-light);
    border-left: 3px solid var(--danger);
    padding: 14px 18px;
    display: flex;
    align-items: flex-start;
    gap: var(--gap-xs);
}
.state-error__icon {
    color: var(--danger);
    font-weight: 800;
    font-size: 1.125rem;
    flex-shrink: 0;
    line-height: 1.4;
}
.state-error__title {
    color: var(--danger);
    font-size: .9375rem;
    font-weight: 700;
    display: block;
    margin-bottom: 4px;
}
.state-error__desc {
    font-size: .875rem;
    color: var(--text);
    margin: 0 0 10px;
    line-height: 1.5;
}

/* Success state — same shape as error but in mint */
.state-success {
    background: var(--mint-light);
    border-left: 3px solid var(--mint);
    padding: 14px 18px;
    display: flex;
    align-items: center;
    gap: var(--gap-xs);
}
.state-success__icon {
    color: var(--mint-dark);
    font-weight: 800;
    font-size: 1.125rem;
    flex-shrink: 0;
}
.state-success__title {
    color: var(--mint-dark);
    font-size: .9375rem;
    font-weight: 700;
}

/* ─── Feature cards ──────────────────────────────────────────────── */
.feature-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

/* ─── School cards ───────────────────────────────────────────────── */
/* ─── School Cards Grid ──────────────────────────────────────── */
.school-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-md);
}
@media (max-width: 900px) { .school-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .school-grid { grid-template-columns: minmax(0, 1fr); } }

/* ─── School listing page bg (soft surface so V2 cards read as cards) ──── */
body.page-listing { background: var(--surface-soft); }

/* ─── School Card (V2 lightweight) ────────────────────────────────────── */
.school-card {
    display: block;
    background: #fff;
    border-bottom: 1px solid var(--border);
    padding: var(--card-pad-md);
    color: var(--text);
    text-decoration: none;
    transition: box-shadow .2s ease, transform .15s ease;
}
/* .school-card:hover lift+shadow retired 2026-05-16. Title color shift remains. */
.school-card:hover .school-card__name { color: var(--mint-dark); }

/* Legacy tag-row pattern — kept for the style guide's deprecation reference.
   New cards use canonical .pill chips directly (see .school-card__tags below). */
.tag-row {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    font-size: .75rem;
    color: var(--text-muted);
    margin: 0 0 6px;
}
.tag-row__tag { display: inline-flex; align-items: center; gap: 6px; }
.tag-row__dot { width: 5px; height: 5px; border-radius: 50%; background: var(--mint); flex-shrink: 0; }
.tag-row__feat { color: var(--amber-dark); font-weight: 700; font-size: .75rem; }

/* Card C tag row — flex of canonical .pill chips (level + type + optional
   amber Nổi bật). Replaces the old bullet-eyebrow pattern. */
.school-card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 12px;
}

.school-card__name {
    /* h3 stays a regular block element with its own margins */
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    margin: 0 0 14px;
    line-height: 1.3;
}
/* .school-card__name-text — inner span on the H3. V2 underline rules come
   from the shared card-title canon further down (search "card-title canon").
   This wrapper is kept (rather than dropped) so multi-line titles can get
   per-line underlines via box-decoration-break: clone. */
.school-card__name-text {
    display: inline;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

.school-card__location {
    font-size: .8125rem;
    color: var(--text-muted);
    margin: 0 0 14px;
}

/* Generic card-stats pattern — kept for any other card type using inline
   metrics. School-card has its own footer-style stats below. */
.card-stats {
    display: flex;
    gap: var(--gap-md);
    margin: 0;
}
.card-stat {
    font-size: .8125rem;
    color: var(--text-muted);
}
.card-stat strong {
    color: var(--text-stat);
    font-weight: 700;
    font-size: .9375rem;
    margin-right: 4px;
}

/* Card C stats footer — single inline metadata line with a hairline divider
   above. Reads as intentional "card footer" rather than orphaned numbers.
   Numbers <strong> are navy; labels are text-muted. Bullet separators
   between stats. */
.school-card__stats {
    font-size: .8125rem;
    color: var(--text-muted);
    margin: 0;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}
.school-card__stat {
    color: var(--text-muted);
}
.school-card__stat strong {
    color: var(--navy);
    font-weight: 700;
}
.school-card__stat--sep::before {
    content: "·";
    color: var(--border);
    margin: 0 6px;
}

@media (max-width: 560px) {
    .school-card { padding: 18px 16px; }
}

/* (.tag, .tag--mint, .tag--amber removed — fold into .pill + size + color
   modifier. Use .pill.pill--sm.pill--outline-muted for neutral tags,
   .pill.pill--sm.pill--mint for mint tags, .pill.pill--sm.pill--amber
   for amber tags.) */

/* (.student-card family deleted in the 2026-05-14 sweep. The Student
   Profiles CPT is post-launch backlog — when it ships, the card pattern
   will be designed fresh, not resurrected from this early-days relic.) */

/* ─── Forms · canonical system ──────────────────────────────────────────────
   Compact, restrained input vocabulary. Bordered (clear affordance) but with
   a 2px mint underline focus state instead of a full ring (no clipping in
   tight containers, distinctive moment of attention). 16px input font is
   non-negotiable — anything smaller triggers iOS auto-zoom on focus.
   See style guide page for full vocabulary + button-mapping table.
*/

/* Form layout container (optional — constrains form width) */
.form-stack { max-width: 540px; margin: 0 auto; }

/* Field wrapper */
.form-field { margin-bottom: 16px; }
.form-field:last-child { margin-bottom: 0; }

/* Two-column row pattern — pairs related fields on desktop, stacks on mobile */
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.form-row .form-field { margin-bottom: 0; }
@media (max-width: 600px) { .form-row { grid-template-columns: 1fr; } }

/* Label */
.form-label {
    display: block;
    font-size: .8125rem; font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 4px; letter-spacing: .02em;
}
.form-label .req { color: var(--mint-dark); font-weight: 700; }

/* Input · textarea · select — all share the same body */
.form-input,
.form-textarea,
.form-select {
    width: 100%; box-sizing: border-box;
    padding: 10px 14px;
    font-size: 1rem;  /* 16px — iOS no-zoom on focus */
    font-family: var(--font); color: var(--text);
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 0;
    -webkit-appearance: none; appearance: none;
    transition: border-color .15s, padding .15s;
}
.form-input::placeholder, .form-textarea::placeholder { color: var(--text-light); }

/* Focus — full mint border all around. Padding drops 1px on each side
   so total field height stays stable when the border thickens 1 → 2px. */
.form-input:focus,
.form-textarea:focus,
.form-select:focus {
    outline: none;
    border: 2px solid var(--mint);
    padding: 9px 13px;
}

/* Textarea */
.form-textarea { min-height: 96px; resize: vertical; line-height: 1.5; }

/* Select — custom chevron, no native arrow */
.form-select {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%230D2840' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/></svg>");
    background-repeat: no-repeat;
    background-position: right 12px center;
    padding-right: 32px;
    cursor: pointer;
}

/* Inline meta below input */
.form-hint { font-size: .75rem; color: var(--text-muted); margin: 4px 0 0; }
.form-error { font-size: .75rem; color: var(--danger-dark); margin: 4px 0 0; font-weight: 600; display: none; }
.form-error:empty, .form-field:not(.is-error) .form-error { display: none; }
.form-field.is-error .form-error { display: block; }

/* Validation states — apply .is-error / .is-success on .form-field wrapper */
.form-field.is-error .form-input,
.form-field.is-error .form-textarea,
.form-field.is-error .form-select {
    border: 2px solid var(--danger);
    padding: 9px 13px;
}
.form-field.is-error .form-label { color: var(--danger-dark); }

.form-field.is-success .form-input,
.form-field.is-success .form-textarea,
.form-field.is-success .form-select {
    border: 2px solid var(--mint-dark);
    padding: 9px 13px;
}

/* Disabled */
.form-input:disabled, .form-textarea:disabled, .form-select:disabled {
    background: var(--surface); color: var(--text-light); cursor: not-allowed;
}

/* ─── Radio pills (small inline) — for short choice sets like gender ──── */
.form-pillrow { display: flex; gap: 6px; flex-wrap: wrap; }
.form-pill {
    display: inline-flex; align-items: center;
    cursor: pointer; user-select: none;
}
.form-pill input { position: absolute; opacity: 0; pointer-events: none; }
.form-pill > span {
    display: inline-flex; align-items: center;
    padding: 11px 16px;   /* matches .form-input vertical height (~46px) so
                              pills align with inputs when paired in a .form-row */
    background: #fff;
    border: 1px solid var(--border);
    color: var(--text);
    font-size: .875rem; font-weight: 600;
    line-height: 1.4;
    transition: background .12s, color .12s, border-color .12s;
}
.form-pill:hover > span { border-color: var(--navy); }
.form-pill input:checked + span {
    background: var(--navy); color: #fff; border-color: var(--navy);
}
.form-pill input:focus-visible + span {
    outline: var(--focus-outline); outline-offset: var(--focus-offset);
}

/* ─── Role cards (large block radio — for primary decision steps) ─────── */
.form-cards {
    display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
    margin-bottom: 24px;
}
@media (max-width: 600px) { .form-cards { grid-template-columns: 1fr; } }
.form-card {
    position: relative;
    display: flex; flex-direction: column; gap: 6px;
    padding: 18px;
    background: #fff;
    border: 1px solid var(--border);
    cursor: pointer;
    transition: border-color .15s, background .15s;
}
.form-card input { position: absolute; opacity: 0; pointer-events: none; }
.form-card:hover { border-color: var(--navy); }
.form-card input:checked ~ .form-card__title,
.form-card.is-on .form-card__title { color: var(--navy); }
.form-card:has(input:checked),
.form-card.is-on {
    border-color: var(--mint); background: var(--mint-light);
}
/* Keyboard-only focus ring — :focus-within would also fire on mouse click
   (radio receives focus), creating an unwanted outline alongside the
   border highlight. :has(input:focus-visible) restricts the outline to
   keyboard navigation, which is the only audience that needs it. */
.form-card:has(input:focus-visible) {
    outline: var(--focus-outline);
    outline-offset: var(--focus-offset);
}
.form-card__title { font-size: .9375rem; font-weight: 700; color: var(--navy); }
.form-card__sub { font-size: .8125rem; color: var(--text-muted); }

/* ─── Checkbox group + single ────────────────────────────────────────── */
.form-checkrow { display: flex; flex-direction: column; gap: 8px; }
.form-check {
    display: flex; align-items: flex-start; gap: 10px;
    font-size: .9375rem; color: var(--text);
    cursor: pointer; user-select: none; line-height: 1.45;
}
/* Custom checkbox — native accent-color caused a mint flash during the
   uncheck transition in Chrome. Owning the rendering means the off state
   instantly returns to white with no in-between color. */
.form-check input[type="checkbox"] {
    appearance: none; -webkit-appearance: none;
    width: 18px; height: 18px;
    flex-shrink: 0; margin: 1px 0 0;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 0;
    cursor: pointer;
    position: relative;
    transition: background .12s, border-color .12s;
}
.form-check input[type="checkbox"]:hover { border-color: var(--navy); }
.form-check input[type="checkbox"]:checked {
    background: var(--mint);
    border-color: var(--mint);
}
.form-check input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    top: 2px; left: 5px;
    width: 5px; height: 9px;
    border: solid var(--navy);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.form-check input[type="checkbox"]:focus-visible {
    outline: var(--focus-outline); outline-offset: var(--focus-offset);
}
.form-check--inline { display: inline-flex; }

/* Consent variant — surface-tinted with internal padding */
.form-check--consent {
    font-size: .8125rem; line-height: 1.55;
    padding: 12px 14px; background: var(--surface);
}
.form-check--consent a { color: var(--mint-dark); font-weight: 600; }

/* ─── Search input (text input with leading icon) ────────────────────── */
.form-search { position: relative; }
.form-search__icon {
    position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
    color: var(--text-muted); pointer-events: none;
}
.form-search .form-input { padding-left: 36px; }
.form-search .form-input:focus { padding-left: 36px; }

/* ─── File input (styled label triggering hidden native input) ───────── */
.form-file {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 9px 14px;
    background: #fff;
    border: 1px dashed var(--border);
    font-size: .875rem; font-weight: 600; color: var(--text);
    cursor: pointer;
}
.form-file:hover { border-color: var(--navy); border-style: solid; }
.form-file input { display: none; }
.form-file__name { color: var(--text-muted); font-weight: 400; margin-left: 8px; }

/* ─── Required-fields legend (above first field) ─────────────────────── */
.form-legend {
    font-size: .6875rem; color: var(--text-muted); margin: 0 0 16px;
}
.form-legend .req { color: var(--mint-dark); font-weight: 700; }

/* ─── Thematic subhead within a step (for forms with 6+ fields that group) */
.form-subhead {
    font-size: .6875rem; font-weight: 800; letter-spacing: .1em;
    text-transform: uppercase; color: var(--mint-dark);
    margin: 28px 0 12px; padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}
.form-subhead:first-child { margin-top: 0; }

/* ─── Step indicator · canonical = pill dots (mint = done, navy = active) ─── */
.form-progress {
    display: flex; justify-content: center; gap: 8px;
    list-style: none; margin: 0 0 24px; padding: 0;
}
.form-progress__dot {
    width: 28px; height: 8px;
    background: var(--border); border-radius: 999px;
    transition: background .2s;
}
.form-progress__dot.is-done   { background: var(--mint); }
.form-progress__dot.is-active { background: var(--navy); }

/* Step title (h2-equivalent for the step heading) */
.form-step-title {
    font-size: 1.25rem; font-weight: 800; color: var(--navy); margin: 0 0 24px;
}
.form-step-sub {
    font-size: .9375rem; color: var(--text-muted); margin: -16px 0 24px;
}

/* ─── Form nav (Back ← / Next → row at bottom of each step) ──────────── */
.form-nav {
    display: flex; gap: 12px; justify-content: space-between; align-items: center;
    margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--border);
}
/* Used on step 1 (no Back button) — pushes the lone Next to the right edge */
.form-nav--end { justify-content: flex-end; }
/* Mobile: stay in a row, with Back + Next at matching height. Override
   .btn--sm's smaller vertical padding + font so the two buttons read as
   equal-weight side-by-side; Back stays compact horizontally; Next stretches
   to fill the rest. (On desktop the .btn--sm vs .btn--primary size contrast
   is the intentional hierarchy and stays untouched.) */
@media (max-width: 600px) {
    .form-nav .btn {
        padding: 14px 16px;
        font-size: .9375rem;
        justify-content: center;
    }
    .form-nav [data-action="back"]  { flex: 0 0 auto; }
    .form-nav [data-action="next"],
    .form-nav [type="submit"]       { flex: 1; }
}

/* ─── Form review · canonical xác nhận pattern ──────────────────────────
   "Confirm what you entered before submit" page on multi-step forms.
   Two variants of the same component family:

     .form-review                  · base wrapper
     .form-review--flat            · label/value rows (single-person forms)
       .form-review__row
       .form-review__label
       .form-review__value
     .form-review--blocks          · segmented blocks (multi-person forms)
       .form-review__block
         .form-review__block-head    · eyebrow + edit button row
         .form-review__block-eyebrow · uppercase mint label
         .form-review__edit          · ✎ Sửa button (jumps to edit step)
         .form-review__block-body    · block content
   .form-review-consent             · soft mint callout with checkbox

   Used on event-form step 5 (--blocks) and volunteer-form step 4 (--flat).
   Future shorter forms (service-tier inquiry, callback request) extend
   --flat. Pair with canonical .form-nav for Back/Submit row below. */
.form-review {
    background: var(--surface);
    border: 1px solid var(--border);
    margin-bottom: var(--gap-md);
}
/* Flat variant: label/value rows separated by hairlines */
.form-review--flat { padding: 0 var(--card-pad-md); }
.form-review__row {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: var(--gap-sm);
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
    font-size: .9375rem; line-height: 1.4;
}
.form-review__row:last-child { border-bottom: 0; }
.form-review__label { color: var(--text-muted); flex-shrink: 0; }
.form-review__value {
    color: var(--navy); font-weight: 600;
    text-align: right; word-break: break-word;
}
/* Segmented variant: stacked .form-review__block cards */
.form-review--blocks { padding: 0; background: transparent; border: none; }
.form-review__block {
    background: #fff;
    border: 1px solid var(--border);
    border-left: 4px solid var(--mint);
    padding: 18px 22px;
    margin-bottom: var(--gap-xs);
    position: relative;
}
.form-review__block:last-child { margin-bottom: 0; }
.form-review__block-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: var(--gap-2xs);
}
.form-review__block-eyebrow {
    font-size: .6875rem; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
    color: var(--mint-dark);
}
.form-review__edit {
    background: transparent; border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: .75rem; font-weight: 600;
    padding: 4px 10px; cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}
.form-review__edit:hover { background: var(--navy); color: #fff; border-color: var(--navy); }
.form-review__block-body {
    color: var(--navy);
    font-size: .9375rem; line-height: 1.5;
}
.form-review__block-body strong { display: block; font-weight: 700; margin-bottom: 2px; }
.form-review__block-body p { margin: 0; }
.form-review__block-body p + p { margin-top: 4px; color: var(--text-muted); font-size: .875rem; }

/* Consent callout · soft mint tint with mint left accent. Distinct from
   .form-check.form-check--consent (a plain checkbox row used in mid-form
   contexts) — this is the higher-emphasis consent that appears just
   before the final submit on the xác nhận page. */
.form-review-consent {
    display: flex; align-items: flex-start; gap: 10px;
    background: var(--mint-light);
    border-left: 4px solid var(--mint);
    padding: 14px 16px;
    margin-bottom: var(--gap-md);
    font-size: .9375rem; line-height: 1.5; color: var(--navy);
    cursor: pointer;
}
.form-review-consent input { margin-top: 4px; flex-shrink: 0; }

/* Mobile: flat-variant rows stack label-above-value (otherwise long values
   wrap awkwardly under narrow screens). */
@media (max-width: 600px) {
    .form-review__row {
        flex-direction: column; gap: 4px; align-items: flex-start;
    }
    .form-review__value { text-align: left; }
}

/* ─── Form confirmation · canonical post-submit pattern ─────────────────
   "Thank you, here's what's next" page rendered after a successful form
   submit. Single component, content varies per form:

     .form-confirm                  · wrapper (centered text)
     .form-confirm__header          · success icon + title + greeting
       .form-confirm__icon          · mint square with navy ✓
       .form-confirm__title         · large heading
       .form-confirm__greeting      · "Cảm ơn {Name}" + context line
     .form-confirm__section         · each content block (separated by
                                       hairline divider above)
       .form-confirm__section-title · h3-equivalent uppercase-ish heading
       .form-confirm__section-body  · paragraphs / supporting text
     .form-confirm__list            · ✓-bulleted list (left-aligned in body)
     .form-confirm__cta-stack       · vertical button stack, centered
     .form-confirm__event-card      · mint-accented event-summary card
                                       (used on event-signup confirmation
                                       to show date/time/venue) */
.form-confirm { text-align: center; }

.form-confirm__header { margin-bottom: var(--gap-lg); }
.form-confirm__icon {
    width: 56px; height: 56px;
    background: var(--mint); color: var(--navy);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 1.75rem; font-weight: 800;
    margin: 0 auto var(--gap-md);
}
.form-confirm__title {
    font-weight: 800; font-size: 1.5rem; color: var(--navy);
    margin: 0 0 var(--gap-2xs);
}
.form-confirm__greeting {
    color: var(--text-muted); font-size: 1rem; line-height: 1.5; margin: 0;
}

.form-confirm__section {
    text-align: center;
    padding: var(--gap-lg) 0;
    border-top: 1px solid var(--border);
}
.form-confirm__section-title {
    font-weight: 800; font-size: 1.125rem; color: var(--navy);
    margin: 0 0 var(--gap-xs);
}
.form-confirm__section-body {
    color: var(--text-muted); font-size: .9375rem; line-height: 1.55;
    max-width: 480px; margin: 0 auto;
}
.form-confirm__section-body p { margin: 0 0 var(--gap-2xs); }
.form-confirm__section-body p:last-child { margin-bottom: 0; }
.form-confirm__section-body strong { color: var(--navy); }

.form-confirm__list {
    list-style: none; margin: 0 auto; padding: 0;
    max-width: 480px; text-align: left;
}
.form-confirm__list li {
    font-size: .9375rem; color: var(--navy);
}
.form-confirm__list li strong { color: var(--navy); }

/* ─── Mint-checkmark list · canonical pattern ───────────────────────────
   Bulleted list with a mint ✓ glyph to the left of each item. Use
   .list-check as the new canonical class on the <ul>; --on-dark
   modifier flips the glyph to the brighter --mint for navy backgrounds.

   The four legacy class names that predate this canon
   (.form-confirm__list, .tier-card__features, .trust-sidebar__list,
   .tier-preview-card__bullets) are wired into the grouped selectors
   below so templates don't need touching. Each consumer's <ul> rule
   keeps its own bespoke layout (max-width, flex, margin, etc.); only
   the li chrome + glyph become canonical. */
.list-check,
.list-check--on-dark,
.form-confirm__list,
.tier-card__features,
.trust-sidebar__list,
.tier-preview-card__bullets {
    list-style: none;
}
.list-check,
.list-check--on-dark {
    padding: 0;
    margin: 0;
}
.list-check li,
.list-check--on-dark li,
.form-confirm__list li,
.tier-card__features li,
.trust-sidebar__list li,
.tier-preview-card__bullets li {
    position: relative;
    padding: 8px 0 8px 24px;
    line-height: 1.5;
}
.list-check li::before,
.form-confirm__list li::before,
.tier-card__features li::before,
.trust-sidebar__list li::before {
    content: '✓';
    position: absolute;
    left: 0;
    top: 8px;
    color: var(--mint-dark);
    font-weight: 800;
}
.list-check--on-dark li::before,
.tier-preview-card__bullets li::before {
    content: '✓';
    position: absolute;
    left: 0;
    top: 8px;
    color: var(--mint);
    font-weight: 800;
}

.form-confirm__cta-stack {
    display: flex; flex-direction: column; align-items: center;
    gap: var(--gap-xs); margin-top: var(--gap-md);
}
.form-confirm__cta-stack .btn { min-width: 280px; justify-content: center; }

.form-confirm__event-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 4px solid var(--mint);
    padding: 18px 22px;
    text-align: left;
    margin: 0 auto; max-width: 480px;
}
.form-confirm__event-card h4 {
    font-weight: 800; font-size: 1rem; color: var(--navy);
    margin: 0 0 var(--gap-2xs);
}
.form-confirm__event-card ul { list-style: none; padding: 0; margin: 0; }
.form-confirm__event-card li {
    font-size: .9375rem; color: var(--navy); padding: 4px 0;
    display: flex; gap: 10px;
}
.form-confirm__event-card li span:first-child {
    color: var(--text-muted); min-width: 80px;
}

@media (max-width: 600px) {
    .form-confirm__cta-stack { align-items: stretch; }
    .form-confirm__cta-stack .btn { min-width: 0; }
}

/* ─── Lead capture: drawer + inline form ──────────────────────────────
   Drawer modeled on .nav-drawer (right-side slide-in desktop, full-width
   bottom-sheet mobile). Used by the admissibility CTA from the school
   profile context card + mobile sticky.
   The inline variant is used by the registration CTA at the bottom of
   the school profile (lives inside .cta-banner). */

.lead-drawer {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: min(440px, 92vw);
    background: #fff;
    z-index: 310;
    display: flex; flex-direction: column;
    transform: translateX(100%);
    transition: transform .25s ease, box-shadow .25s ease;
    /* Shadow only when open — its blur radius would otherwise paint back
       into the viewport from the off-screen drawer and read as a dark
       band on the page edge. There are several lead-drawer instances on
       this page; their shadows would compound. */
}
.lead-drawer.is-open {
    transform: translateX(0);
    box-shadow: -4px 0 24px rgba(0,0,0,.14);
}

@media (max-width: 600px) {
    /* Bottom-sheet on mobile */
    .lead-drawer {
        top: auto; right: 0; bottom: 0; left: 0;
        width: 100%;
        /* dvh (dynamic viewport height) updates when the iOS keyboard pops
           up — vh doesn't, which caused the keyboard to overlap the drawer +
           hide the form header. Fall back to vh for browsers without dvh
           support (covers ~95%+ as of 2026; the rest just see the old behavior). */
        max-height: 92vh;
        max-height: 92dvh;
        border-radius: 14px 14px 0 0;
        transform: translateY(100%);
        /* Shadow only when open — see desktop note above. */
    }
    .lead-drawer.is-open {
        transform: translateY(0);
        box-shadow: 0 -8px 30px rgba(0,0,0,.18);
    }
}

.lead-drawer__overlay {
    position: fixed; inset: 0;
    background: rgba(13, 40, 64, .42);
    z-index: 305;
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease;
}
.lead-drawer__overlay.is-open { opacity: 1; pointer-events: auto; }
body.lead-drawer-open { overflow: hidden; }

.lead-drawer__header {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--gap-md);
    padding: 20px 24px 12px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.lead-drawer__title {
    font-size: 1.125rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0 0 4px;
    line-height: 1.3;
}
.lead-drawer__sub {
    font-size: .875rem;
    color: var(--text-muted);
    margin: 0;
    line-height: 1.45;
}
.lead-drawer__close {
    background: transparent; border: 0;
    color: var(--text-muted);
    cursor: pointer;
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    font-size: 24px; line-height: 1;
    flex-shrink: 0;
    border-radius: 4px;
}
.lead-drawer__close:hover { color: var(--navy); background: var(--surface); }

.lead-drawer__body {
    padding: 20px 24px 28px;
    overflow-y: auto;
    flex: 1;
}

/* ─── Lead form (drawer + inline shared) ──────────────────────────── */
.lead-form { display: block; }
/* [hidden] beats explicit display: block — without these overrides the
   form stays visible after submit even when JS sets .hidden = true. */
.lead-form[hidden],
.lead-form-success[hidden],
.cta-banner__form-trigger[hidden] { display: none !important; }

.lead-form__heading {
    font-size: 1.125rem; font-weight: 800; color: var(--navy);
    margin: 0 0 4px;
}
.lead-form__sub {
    font-size: .875rem; color: var(--text-muted);
    margin: 0 0 var(--gap-md);
    line-height: 1.5;
}
.lead-form__fields { margin-bottom: var(--gap-md); }
.lead-form__contact-hint {
    margin-top: -8px; margin-bottom: var(--gap-md);
}
.lead-form__general-error {
    display: block;
    background: var(--danger-light); color: var(--danger-dark);
    border-radius: 4px;
    padding: 10px 14px;
    margin: 0 0 var(--gap-md);
    font-size: .875rem;
}
.lead-form__submit { margin-top: var(--gap-md); }
.lead-form__legal {
    font-size: .75rem; color: var(--text-muted);
    text-align: center;
    margin: var(--gap-md) 0 0;
    line-height: 1.5;
}

/* On-dark variant — for the form inside the navy .cta-banner */
.lead-form--on-dark { color: #fff; }
.lead-form--on-dark .lead-form__heading { color: #fff; }
.lead-form--on-dark .lead-form__sub { color: rgba(255,255,255,.78); }
.lead-form--on-dark .form-label { color: rgba(255,255,255,.85); }
.lead-form--on-dark .form-hint,
.lead-form--on-dark .lead-form__contact-hint,
.lead-form--on-dark .lead-form__legal { color: rgba(255,255,255,.65); }
.lead-form--on-dark .form-input,
.lead-form--on-dark .form-select,
.lead-form--on-dark .form-textarea {
    background: rgba(255,255,255,.08);
    border-color: rgba(255,255,255,.22);
    color: #fff;
}
.lead-form--on-dark .form-input::placeholder,
.lead-form--on-dark .form-textarea::placeholder {
    color: rgba(255,255,255,.45);
}
.lead-form--on-dark .form-input:focus,
.lead-form--on-dark .form-select:focus,
.lead-form--on-dark .form-textarea:focus {
    /* background-color (not the shorthand) — preserves the chevron
       background-image set on .form-select. The shorthand wipes it. */
    background-color: rgba(255,255,255,.14);
    border-color: var(--mint);
}
.lead-form--on-dark .form-error { color: #ffb4b6; }

/* ─── Inline lead form host (sits inside .cta-banner) ──────────────── */
.cta-banner__form {
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.14);
    /* No border-radius — canon prefers sharp corners on surface containers */
    padding: 24px 28px;
    max-width: 540px;
    margin: var(--gap-lg) auto 0;
    text-align: left;
}
@media (max-width: 600px) {
    .cta-banner__form { padding: 20px; margin-top: var(--gap-md); }
}
/* "Show form on click" trigger button — appears initially, hides when form opens */
.cta-banner__form-trigger {
    text-align: center;
    margin-top: var(--gap-lg);
}
@media (max-width: 600px) {
    .cta-banner__form-trigger { margin-top: var(--gap-md); }
}

/* Custom dropdown chevron for selects on the dark navy form (default
   browser dropdown indicator is invisible on dark backgrounds). */
.lead-form--on-dark .form-select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5l5 5 5-5' stroke='%23ffffff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 12px 8px;
    padding-right: 36px;
}

/* Success state inside cta-banner stays light-on-dark */
.cta-banner .lead-form-success .form-confirm__title { color: #fff; }
.cta-banner .lead-form-success .form-confirm__greeting { color: rgba(255,255,255,.78); }
.cta-banner .lead-form-success .form-confirm__section { border-top-color: rgba(255,255,255,.18); }
.cta-banner .lead-form-success .form-confirm__section-title { color: #fff; }
.cta-banner .lead-form-success .form-confirm__section-body { color: rgba(255,255,255,.85); }
.cta-banner .lead-form-success .form-confirm__section-body strong { color: #fff; }
.cta-banner .lead-form-success .form-confirm__section-body a { color: var(--mint); }

/* (Removed scoped white-bg override. Use .btn--secondary in the success
   state markup — it's canonical, mint background reads great on navy,
   and it ships with the canonical hover behavior. See parts/lead-form.php.) */

/* ═══ Service tiers page (Phase 10) — canonical components ═══════════════
   Used by: page-dich-vu.php (the /dich-vu/ service-tiers landing).
   Designed to be reusable: any pricing/tier listing page can compose
   these atoms (.tier-grid + .tier-card + .compare-table + .faq-list
   + .trust-strip + .why-grid).
*/

/* ─── Trust band (compact stats strip just below hero) ───────────────
   Wrapper-only class. Provides bg + border-bottom so the band visually
   separates from the hero above and the section below. The stats themselves
   use the canonical .stat-callout-row + .stat-callout pattern (single
   source of truth for "small inline stat" typography). */
.trust-band {
    background: var(--surface-soft);
    border-bottom: 1px solid var(--border);
}

/* ─── Tier grid (3-up pricing cards) ──────────────────────────────────── */
.tier-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gap-md);
    align-items: stretch;
    margin-top: var(--gap-lg);
}
/* [hidden] override — explicit display rules beat the attribute. */
.tier-grid[hidden],
.compare-table-wrap[hidden] { display: none !important; }
@media (max-width: 960px) {
    .tier-grid { grid-template-columns: 1fr; max-width: 480px; margin-left: auto; margin-right: auto; }
}

/* ─── Tier card (canonical pricing card) ──────────────────────────────── */
.tier-card {
    padding: var(--card-pad-lg);
    display: flex;
    flex-direction: column;
    position: relative;
    transition: box-shadow var(--ease-base), transform var(--ease-base);
    scroll-margin-top: calc(var(--nav-height) + 24px);
}
/* .tier-card:hover lift+shadow retired 2026-05-16. */

/* Recommended variant — mint top stripe + slight elevation always-on */
.tier-card--recommended {
    border-top: 3px solid var(--mint);
    box-shadow: var(--shadow-card);
    /* Push badge above the card edge */
    margin-top: -2px;
}
.section--surface .tier-card--recommended {
    /* On surface bg, top stripe flips navy per the canon accent rule */
    border-top-color: var(--navy);
}

.tier-card__badge {
    position: absolute;
    top: -12px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--mint);
    color: var(--navy);
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .08em;
    padding: 4px 12px;
    white-space: nowrap;
}
.section--surface .tier-card--recommended .tier-card__badge {
    background: var(--navy);
    color: #fff;
}

.tier-card__head { margin-bottom: var(--gap-md); }
.tier-card__name {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0 0 var(--gap-xs);
    line-height: 1.2;
}
.tier-card__tagline {
    font-size: .9375rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 0;
    min-height: 2.85em;  /* hold space so 3 cards align even with shorter copy */
}

.tier-card__price {
    display: flex;
    align-items: baseline;
    gap: 4px;
    padding-top: var(--gap-md);
    border-top: 1px solid var(--border);
}
.tier-card__price-amount {
    font-size: 2.5rem;
    font-weight: 800;
    color: var(--navy);
    letter-spacing: -.02em;
    line-height: 1;
}
.tier-card__price-unit {
    font-size: .875rem;
    color: var(--text-muted);
    font-weight: 600;
}
.tier-card__price-note {
    font-size: .75rem;
    color: var(--text-light);
    margin: 4px 0 0;
}

.tier-card__features {
    list-style: none;
    margin: var(--gap-md) 0 var(--gap-lg);
    padding: 0;
    flex: 1;  /* push CTA to bottom regardless of feature count */
}
.tier-card__features li {
    font-size: .9375rem;
    color: var(--text);
}
.tier-card__features li strong { color: var(--navy); font-weight: 700; }

.tier-card__cta { margin-top: auto; }

/* ─── Canonical segmented toggle ─────────────────────────────────────────
   ONE component, three places: /dich-vu/ (Đại học/THPT), articles hub
   (Đại học/THPT, link-based), campaign hero (city tabs, on-dark, --sm).

   Markup shapes:

     Button-based, 2-way (dich-vu):
       <div class="seg-toggle-wrap">
         <div class="seg-toggle" data-tier-group data-active="uni">
           <button class="seg-toggle__btn is-active" data-tier-pane="uni">…</button>
           <button class="seg-toggle__btn" data-tier-pane="thpt">…</button>
           <span class="seg-toggle__ind" aria-hidden="true"></span>
         </div>
       </div>

     Link-based, 2-way (articles hub — visually a toggle, behaviorally nav):
       <div class="seg-toggle">
         <a href="…" class="seg-toggle__btn is-active">Đại học</a>
         <a href="…" class="seg-toggle__btn">THPT</a>
         <span class="seg-toggle__ind" aria-hidden="true"></span>
       </div>

     On-dark, --sm, n-way (campaign hero city tabs):
       <div class="seg-toggle seg-toggle--on-dark seg-toggle--sm" data-…>
         <button class="seg-toggle__btn is-active" …>HN</button>
         <button class="seg-toggle__btn" …>HCM</button>
         <button class="seg-toggle__btn" …>ĐN</button>
         <span class="seg-toggle__ind" aria-hidden="true"></span>
       </div>

   Indicator slides via JS (positions itself under .is-active). For the
   2-way Đại học/THPT pattern there's a CSS-only fallback driven by
   [data-active="thpt"] on an ancestor — see bottom of this block.
*/
.seg-toggle-wrap {
    display: flex;
    justify-content: center;
    margin: 0 0 var(--gap-lg);
}
.seg-toggle {
    position: relative;
    display: inline-flex;
    background: rgba(13,40,64,.08);
    padding: 4px;
    border-radius: 14px;
}
.seg-toggle__btn {
    position: relative;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: transparent;
    padding: 12px 24px;
    font-family: inherit;
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    opacity: .55;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    line-height: 1;
    border-radius: 10px;
    transition: opacity var(--ease-base), color var(--ease-base);
    min-width: 160px;
    text-align: center;
}
.seg-toggle__btn:hover { opacity: .85; color: var(--navy); }
.seg-toggle__btn.is-active { opacity: 1; }
.seg-toggle__btn:focus-visible {
    outline: var(--focus-outline);
    outline-offset: 2px;
}

/* Static variant — no .seg-toggle__ind span. Active button gets the pill
   styling directly (no JS, no animation). Used for link-based toggles
   (articles hub) where each click is a full page nav so an animated
   slide makes no sense and the indicator span was capturing clicks. */
.seg-toggle:not(:has(.seg-toggle__ind)) .seg-toggle__btn.is-active {
    background: #fff;
    box-shadow: 0 2px 8px var(--overlay-navy-faint);
}
.seg-toggle__ind {
    position: absolute;
    top: 4px;
    bottom: 4px;
    z-index: 1;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 2px 8px var(--overlay-navy-faint);
    /* Decorative — must NEVER intercept clicks meant for the buttons. */
    pointer-events: none;
    transition: left .25s cubic-bezier(.4,0,.2,1),
                width .25s cubic-bezier(.4,0,.2,1);
}

/* Small modifier — for in-card / hero use (campaign city tabs) */
.seg-toggle--sm { padding: 3px; border-radius: 12px; }
.seg-toggle--sm .seg-toggle__btn {
    padding: 8px 14px;
    font-size: .8125rem;
    min-width: 0;
    border-radius: 9px;
}
.seg-toggle--sm .seg-toggle__ind {
    top: 3px;
    bottom: 3px;
    border-radius: 9px;
}

/* On-dark modifier — for navy hero. Indicator stays white (not mint) to
   match the light variant; active text reads navy on white pill. */
.seg-toggle--on-dark { background: rgba(255,255,255,.12); }
.seg-toggle--on-dark .seg-toggle__btn { color: rgba(255,255,255,.65); }
.seg-toggle--on-dark .seg-toggle__btn:hover { color: #fff; opacity: .9; }
.seg-toggle--on-dark .seg-toggle__btn.is-active {
    color: var(--navy);
    opacity: 1;
}
.seg-toggle--on-dark .seg-toggle__ind { background: #fff; }

/* CSS-only fallback for the 2-way Đại học/THPT case (used on /dich-vu/).
   When no JS has positioned the indicator yet, this keeps the pill
   aligned to whichever pane is currently selected. JS overrides via
   inline left/width once it runs. */
.seg-toggle:not([style*="--ind-x"]) .seg-toggle__ind {
    left: 4px;
    width: calc(50% - 4px);
}
[data-active="thpt"] .seg-toggle:not([style*="--ind-x"]) .seg-toggle__ind,
.seg-toggle:not([style*="--ind-x"])[data-active="thpt"] .seg-toggle__ind {
    transform: translateX(100%);
}

/* Locked state — used by the campaign hero city tabs when registration
   has been submitted for one city. Other cities fade + lose pointer. */
.seg-toggle.is-locked .seg-toggle__btn { cursor: not-allowed; }
.seg-toggle.is-locked .seg-toggle__btn:not(.is-active) { opacity: .35; }
.seg-toggle.is-locked .seg-toggle__btn:hover { opacity: .35; }
.seg-toggle.is-locked .seg-toggle__btn.is-active:hover { opacity: 1; }

@media (max-width: 600px) {
    .seg-toggle__btn { padding: 10px 18px; min-width: 0; flex: 1; font-size: .875rem; }
    .seg-toggle { width: 100%; max-width: 360px; }
    .seg-toggle--sm { width: auto; }
    .seg-toggle--sm .seg-toggle__btn { flex: 1; }
}


/* ─── Comparison table ────────────────────────────────────────────────── */
.compare-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--border);
    background: #fff;
}
.compare-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .9375rem;
    min-width: 600px;
}
.compare-table thead th {
    background: var(--surface);
    color: var(--navy);
    font-weight: 700;
    text-align: center;
    padding: var(--gap-md) var(--gap-sm);
    border-bottom: 2px solid var(--border);
    vertical-align: top;
    line-height: 1.3;
}
.compare-table thead th.compare-table__feature-col {
    text-align: left;
}
.compare-table thead th.compare-table__col-recommended {
    background: var(--mint-light);
    color: var(--mint-dark);
    border-bottom-color: var(--mint);
}
.compare-table__price {
    display: block;
    margin-top: 4px;
    font-size: .875rem;
    font-weight: 600;
    color: var(--text-muted);
}
.compare-table thead th.compare-table__col-recommended .compare-table__price { color: var(--mint-dark); }
.compare-table tbody td {
    padding: 14px var(--gap-sm);
    border-bottom: 1px solid var(--border);
    text-align: center;
    color: var(--text);
}
.compare-table tbody td:first-child {
    text-align: left;
    color: var(--text);
    font-weight: 500;
}
.compare-table tbody tr:last-child td { border-bottom: none; }
.compare-table tbody tr:hover td { background: var(--surface-soft); }

/* Green checkmarks in cells — match the tier-card feature-list ✓ color.
   Also gives the em-dash "—" a muted color so positives pop. */
.compare-table .compare-yes {
    color: var(--mint-dark);
    font-weight: 800;
    font-size: 1.0625rem;
}
.compare-table .compare-no {
    color: var(--text-light);
    font-weight: 400;
}

/* Mobile: freeze the first column. The frozen column has high z-index +
   transform: translateZ(0) to force a new compositing layer (works around
   position:sticky quirks on table cells where siblings can leak).
   ALSO: the recommended col's 2px mint border-bottom was the actual
   visual leak (still rendered alongside the cell as it scrolled past).
   Mobile fix: replace the bottom border with an inset top border via
   box-shadow on the recommended col header. The visual highlight is
   preserved (mint bg + accent line) but moved to the TOP of the cell
   so there's no border line at the row boundary that can leak. */
@media (max-width: 720px) {
    /* Smaller type so the squeezed columns aren't comically cramped. */
    .compare-table { table-layout: fixed; border-collapse: separate; border-spacing: 0; font-size: .8125rem; }
    .compare-table thead th { padding: var(--gap-sm) var(--gap-xs); }
    .compare-table tbody td  { padding: 10px var(--gap-xs); }
    .compare-table__price    { font-size: .75rem; }
    .compare-table .compare-yes { font-size: .9375rem; }

    .compare-table thead th:first-child,
    .compare-table tbody td:first-child {
        position: sticky;
        left: 0;
        z-index: 10;
        transform: translateZ(0);
        text-align: left;
        min-width: 150px;
        max-width: 150px;
        width: 150px;
        box-shadow: 6px 0 8px -4px var(--overlay-navy-faint);
    }
    .compare-table thead th:first-child {
        background: var(--surface);
        border-bottom: 2px solid var(--border);
    }
    .compare-table tbody td:first-child { background: #fff; }
    .compare-table tbody tr:hover td:first-child { background: var(--surface-soft); }
    /* Recommended col: highlight via inset top border (box-shadow), not
       a bottom border. Removes the leaky bottom-border element entirely. */
    .compare-table thead th.compare-table__col-recommended {
        border-bottom: 2px solid var(--border);
        box-shadow: inset 0 3px 0 0 var(--mint);
    }
}

/* "Why DHTC" 3-up grid (uses canonical .feature-card composition) */
.why-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gap-md);
    margin-top: var(--gap-lg);
}
@media (max-width: 720px) {
    .why-grid { grid-template-columns: 1fr; }
}

/* Process steps — 5-up variant of the canonical .process-steps (which is
   default 4-up). Just overrides the grid columns + line position. */
.process-steps--5 {
    grid-template-columns: repeat(5, 1fr);
}
.process-steps--5::before {
    left: 10%;  /* (1/5)/2 — center under first/last badges */
    right: 10%;
}
@media (max-width: 960px) {
    .process-steps--5 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
    .process-steps--5 { grid-template-columns: 1fr; }
}

/* ─── FAQ list (native <details>, styled to canon) ───────────────────── */
.faq-list {
    max-width: var(--container-sm);
    margin: var(--gap-lg) auto 0;
}
.faq-item {
    background: #fff;
    border: 1px solid var(--border);
    border-bottom: none;
}
.faq-item:last-child { border-bottom: 1px solid var(--border); }
.faq-item[open] { background: var(--surface-soft); }

.faq-item__q {
    cursor: pointer;
    list-style: none;
    padding: var(--gap-md) var(--card-pad-md);
    font-size: 1rem;
    font-weight: 700;
    color: var(--navy);
    position: relative;
    padding-right: 48px;
    line-height: 1.4;
}
.faq-item__q::-webkit-details-marker { display: none; }
.faq-item__q::after {
    content: '+';
    position: absolute;
    right: var(--card-pad-md);
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.5rem;
    color: var(--mint-dark);
    font-weight: 400;
    transition: transform var(--ease-fast);
    line-height: 1;
}
.faq-item[open] .faq-item__q::after {
    content: '−';
}
.faq-item__q:hover { color: var(--mint-dark); }
.faq-item__q:focus-visible {
    outline: var(--focus-outline);
    outline-offset: -3px;
}

.faq-item__a {
    padding: 0 var(--card-pad-md) var(--gap-md);
    color: var(--text-muted);
    line-height: 1.65;
    font-size: .9375rem;
}
.faq-item__a p { margin: 0; }
.faq-item__a strong { color: var(--navy); }

/* ─── Page header on navy variant (used by page-dich-vu hero) ────────── */
/* (page-header is canonical — adding navy variant here for completeness.
   If page-header--navy already exists earlier in this file as a grouped
   selector, this is a no-op append-only safety net.) */

/* ─── CTA banner · navy gradient end-of-detail-page CTA ──────────────
   Paired with .home-cta-band (see ~line 8195) as the two canonical
   full-bleed CTA bands. The navy gradient + mint glow gives a "premium,
   considered" feel — used at the bottom of school profile, article
   single, services, and lead-form pages. The mint flat variant lives on
   the homepage as a brighter, lighter closer. Different on purpose;
   not drift. */
.cta-banner {
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-light) 100%);
    padding: var(--section-lg) 0;
    text-align: center;
    position: relative;
    overflow: hidden;
    scroll-margin-top: var(--nav-height);
}

.cta-banner::before {
    content: '';
    position: absolute;
    width: 400px;
    height: 400px;
    background: radial-gradient(circle, rgba(79,217,164,.15) 0%, transparent 70%);
    top: -100px;
    right: -100px;
    pointer-events: none;
}

.cta-banner h2 { color: #fff; margin-bottom: 12px; }
.cta-banner p { color: rgba(255,255,255,.6); margin-bottom: 32px; }
.cta-banner__actions { display: flex; gap: 12px; justify-content: center; }

/* ═══════════════════════════════════════════════════════════════════════
   V3 Footer B — full marketing footer (shipped 2026-05-12)
   Top: offices band (full-bleed darker navy stripe) — DHTC wordmark +
        per-office address/phone/hours/email with mint SVG icons.
   Middle: 4-col grid — brand+blurb, Khám phá, Dịch vụ, Hỗ trợ.
   Bottom: copyright + social SVG icons (FB, IG, YT, TT) — only renders
           when their URL is set in DHTC settings.
   ═══════════════════════════════════════════════════════════════════════ */
.site-footer {
    background: var(--navy);
    color: rgba(255,255,255,.85);
}

/* ── Offices band (top stripe) ────────────────────────────────────────── */
.site-footer__offices {
    background: rgba(0,0,0,.18);
    padding: 32px 0 28px;
}
.site-footer__offices-inner { display: flex; flex-direction: column; gap: 18px; }
.site-footer__wordmark {
    font-size: 1.125rem;
    font-weight: 800;
    color: #fff;
    margin: 0;
    letter-spacing: -.01em;
}
.site-footer__offices-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 32px;
}
.site-footer__office { min-width: 0; }
.site-footer__office-label {
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--mint);
    margin: 0 0 8px;
}
.site-footer__office-line {
    font-size: .875rem;
    color: rgba(255,255,255,.85);
    line-height: 1.5;
    margin: 0 0 6px;
    display: flex;
    align-items: flex-start;
    gap: 8px;
}
.site-footer__office-line--inline {
    flex-wrap: wrap;
    gap: 4px 18px;
}
.site-footer__office-line a {
    color: rgba(255,255,255,.85);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: color .15s;
}
.site-footer__office-line a:hover { color: var(--mint); }
.site-footer__office-meta {
    color: rgba(255,255,255,.65);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.site-footer__office-icon {
    display: inline-flex;
    align-items: center;
    color: var(--mint);
    flex-shrink: 0;
}
.site-footer__office-icon svg {
    width: 13px;
    height: 13px;
    display: block;
}

/* ── Main 4-col grid ──────────────────────────────────────────────────── */
.site-footer__main { padding: 40px 0 24px; }
.site-footer__grid {
    display: grid;
    grid-template-columns: 1.5fr repeat(3, 1fr);
    gap: 36px;
    margin-bottom: 32px;
}
.site-footer__brand-name {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 1.25rem;
    font-weight: 800;
    color: #fff;
    margin: 0 0 12px;
    letter-spacing: -.01em;
}
.site-footer__brand-name img { width: 40px; height: 40px; flex-shrink: 0; }
.site-footer__brand-blurb {
    font-size: .875rem;
    color: rgba(255,255,255,.7);
    line-height: 1.6;
    margin: 0;
    max-width: 320px;
}
.site-footer__col h4 {
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--mint);
    margin: 0 0 14px;
}
.site-footer__col ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.site-footer__col a {
    color: rgba(255,255,255,.85);
    text-decoration: none;
    font-size: .875rem;
    transition: color .15s;
}
.site-footer__col a:hover { color: var(--mint); }

/* ── Full-width rule between main grid and bottom strip ───────────────── */
.site-footer__divider {
    border: 0;
    border-top: 1px solid rgba(255,255,255,.1);
    margin: 0;
    height: 0;
}

/* ── Bottom strip (copyright + social) ────────────────────────────────── */
.site-footer__bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding-top: 20px;
    font-size: .8125rem;
    color: rgba(255,255,255,.5);
}
.site-footer__social {
    display: flex;
    align-items: center;
    gap: 16px;
    list-style: none;
    padding: 0;
    margin: 0;
}
.site-footer__social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: rgba(255,255,255,.7);
    transition: color .15s;
}
.site-footer__social a:hover { color: var(--mint); }
.site-footer__social svg { width: 18px; height: 18px; display: block; }

/* ── Mobile (≤720px) ──────────────────────────────────────────────────── */
@media (max-width: 720px) {
    .site-footer__offices { padding: 24px 0 20px; }
    .site-footer__offices-grid { grid-template-columns: 1fr; gap: 22px; }
    .site-footer__office-line--inline { flex-direction: column; align-items: flex-start; gap: 6px; }

    .site-footer__main { padding: 28px 0 20px; }
    .site-footer__grid { grid-template-columns: 1fr 1fr; gap: 24px 20px; margin-bottom: 24px; }
    .site-footer__brand { grid-column: 1 / -1; }
    .site-footer__brand-blurb { max-width: none; }

    .site-footer__bottom {
        flex-direction: column;
        align-items: flex-start;
        gap: 14px;
        text-align: left;
    }
}
@media (max-width: 420px) {
    .site-footer__grid { grid-template-columns: 1fr; }
}

/* ─── School Profile Page ─────────────────────────────────────────── */

/* Header */
.sp-header {
    position: relative;
    background: var(--navy);
    overflow: hidden;
    min-height: 360px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

.sp-header--sponsored {
    border-top: 4px solid var(--amber);
}

.sp-header__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
}

.sp-header__bg--placeholder {
    background: linear-gradient(135deg, var(--navy) 0%, #0e3a28 100%);
}

.sp-header--sponsored .sp-header__bg--placeholder {
    background: linear-gradient(135deg, var(--navy) 0%, #2a1a00 60%, #1a2840 100%);
}

.sp-header__bg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: .4;
}

.sp-header__overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top,
        rgba(13,40,64,.97) 0%,
        rgba(13,40,64,.7) 45%,
        rgba(13,40,64,.25) 100%);
    z-index: 1;
}

.sp-header__content {
    position: relative;
    z-index: 2;
    padding: 52px 0 44px;
}

.sp-header__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.sp-header__name {
    font-size: clamp(1.75rem, 4vw, 2.875rem);
    font-weight: 800;
    color: #fff;
    line-height: 1.2;
    letter-spacing: -.02em;
    margin-bottom: 14px;
}

.sp-header__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: center;
}

.sp-header__meta-item {
    display: flex;
    align-items: center;
    gap: 6px;
    color: rgba(255,255,255,.6);
    font-size: .875rem;
    font-weight: 500;
}

.sp-header__meta-item svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
}

.sp-header__rating {
    display: flex;
    align-items: center;
    gap: 5px;
    color: var(--mint);
    font-weight: 700;
    font-size: .875rem;
}

.sp-header__rating-count {
    color: rgba(255,255,255,.45);
    font-weight: 400;
}

.sp-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 22px;
}

.sp-header__btn {
    font-size: .875rem;
    padding: 10px 20px;
}

/* Stats Bar — mobile-only. Desktop uses the .context-card right-rail
   which carries the same role (snapshot + CTA). On mobile this keeps
   the elegant fade animation from stat callouts → school name as you
   scroll past the hero. */
.sp-stats-bar {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow);
    position: sticky;
    top: var(--nav-height);
    z-index: 50;
}
@media (min-width: 961px) {
    .sp-stats-bar { display: none; }
}

.sp-stats-bar__inner {
    display: flex;
    align-items: stretch;
}

.sp-stats-bar__name {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    white-space: nowrap;
    overflow: hidden;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    /* collapsed by default */
    max-width: 0;
    padding: 14px 0;
    opacity: 0;
    transform: translateY(-5px);
    transition: max-width .25s ease, padding .25s ease, opacity .2s ease, transform .2s ease;
}
.sp-stats-bar__name--visible {
    max-width: 280px;
    padding: 14px 20px 14px 0;
    border-right: 1px solid var(--border);
    margin-right: 4px;
    opacity: 1;
    transform: translateY(0);
}

.sp-stats-bar__scroll {
    display: flex;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    flex: 1;
}
.sp-stats-bar__scroll::-webkit-scrollbar { display: none; }

.sp-stat {
    flex: 1;
    min-width: 120px;
    padding: 14px 20px;
    border-right: 1px solid var(--border);
    text-align: center;
    white-space: nowrap;
}
.sp-stat:last-child { border-right: none; }

.sp-stat__label {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-light);
    margin-bottom: 4px;
}

.sp-stat__value {
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1.2;
}

.sp-stat__value--sm   { font-size: 1rem; }
.sp-stat__value--mint { color: var(--mint-dark); }

/* (Section dividers removed — the section padding + colored backgrounds
   already provide enough visual separation in the 2-col layout.) */

/* Rankings · compact-row design (Direction C, locked 2026-05-12).
   Standalone component — no longer composes onto .pill. Three pieces:
   filled navy rank chip on the left, label in the middle, source · year
   meta line on the right. Single line on desktop, scales down cleanly
   on mobile (label wraps; chip + meta stay aligned). */
.sp-rankings {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.sp-ranking-badge {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px 8px 8px;
    background: #fff;
    border: 1px solid var(--border);
    color: var(--navy);
    font-size: .875rem;
    line-height: 1.3;
    text-decoration: none;
    transition: border-color var(--ease-fast), transform var(--ease-fast);
}
/* Anchor variant — when the badge links to a per-list page (most rankings
   now). Slight hover lift + mint border to signal interactivity. */
a.sp-ranking-badge:hover {
    border-color: var(--mint);
    transform: var(--lift-sm);
}

.sp-ranking-badge__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 36px;
    height: 28px;
    padding: 0 8px;
    background: var(--navy);
    color: #fff;
    font-weight: 800;
    font-size: .9375rem;
    line-height: 1;
}

/* Body wraps label + meta. Row layout on desktop (label inline, meta to
   the right). Stacks to column on mobile so meta sits BELOW the wrapped
   label instead of clinging to the top-right corner. */
.sp-ranking-badge__body {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
}

.sp-ranking-badge__label {
    font-weight: 600;
}

.sp-ranking-badge__meta {
    color: var(--text-muted);
    font-size: .75rem;
    font-weight: 500;
    white-space: nowrap;
}

@media (max-width: 480px) {
    .sp-ranking-badge { align-items: flex-start; padding-top: 8px; padding-bottom: 10px; }
    .sp-ranking-badge__num { margin-top: 2px; }
    .sp-ranking-badge__body { flex-direction: column; gap: 4px; }
    .sp-ranking-badge__label { line-height: 1.35; }
    .sp-ranking-badge__meta { white-space: normal; }
}

/* About text */
.sp-about__text {
    font-size: .9375rem;
    line-height: 1.85;
    color: var(--text-muted);
    max-width: var(--container-sm);
    margin-bottom: 0;
}

.sp-about__toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font);
    font-size: .875rem;
    font-weight: 600;
    color: var(--navy);
    padding: 0;
    margin: var(--gap-md) 0 var(--gap-md);  /* match the sponsored-block toggles */
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.sp-about__toggle:hover { color: var(--mint-dark); }

/* Video */
.sp-video {
    position: relative;
    aspect-ratio: 16 / 9;
    background: var(--navy);
    overflow: hidden;
    max-width: var(--container-sm);
    margin-top: 24px;
}
.sp-video iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
}

/* (Two-column layout moved to canonical .layout-2col / --wide-left.) */

/* ─── School profile editorial body · Direction A canon ─────────────────────
   New layout for single-school.php (2026-05-11 rebuild). Sections are clean
   white, separated by .section--xs padding (32px top + bottom = 64px between
   sections). Title gets a tight 32px mint underline tucked beneath. Body
   lives in the main column of .detail-layout. Minor typography drift vs
   article body is documented in style-consolidation deferred memo. */
.sp-prof-section { /* hook only — padding from `.section.section--xs` */ }

/* First section after stats bar gets larger top padding so the gap from
   hero-bottom to "Giới thiệu" reads like the original design (pre-rebuild). */
.detail-layout__main .sp-prof-section:first-of-type {
    padding-top: var(--section-md);
}

/* ── School photos gallery (sponsored-only) ────────────────────────────────
   Thin horizontal strip of thumbnails below Lời nhắn từ trường. Click any
   thumb opens the .school-lightbox overlay. Strip wraps on desktop;
   horizontal-scrolls on narrow viewports. */
.school-photos__strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-sm);
    margin-top: var(--gap-md);
}
.school-photos__thumb {
    flex: 0 0 auto;
    width: 180px;
    height: 120px;
    padding: 0;
    border: 1px solid var(--border);
    background: none;
    cursor: pointer;
    overflow: hidden;
    transition: transform .15s ease, box-shadow .15s ease;
}
.school-photos__thumb:hover,
.school-photos__thumb:focus-visible {
    outline: none;  /* shadow retired 2026-05-16 */
}
.school-photos__thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
@media (max-width: 600px) {
    .school-photos__strip {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        padding-bottom: 8px; /* room for scrollbar */
    }
    .school-photos__thumb { scroll-snap-align: start; }
}

/* ── Lightbox overlay (mounted by school-lightbox.js) ──────────────────── */
.school-lightbox {
    position: fixed;
    inset: 0;
    background: rgba(13, 40, 64, .92);
    z-index: 9999;
    display: none;
    align-items: center;
    justify-content: center;
}
.school-lightbox.is-open { display: flex; }
.school-lightbox__stage {
    width: 100vw;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    overflow: hidden;
}
/* Track: all slides side-by-side. Translates left/right via JS. */
.school-lightbox__track {
    display: flex;
    width: 100%;
    will-change: transform;
}
.school-lightbox__slide {
    flex: 0 0 100vw;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 80vh;
}
.school-lightbox__slide img {
    max-width: 90vw;
    max-height: 80vh;
    object-fit: contain;
    user-select: none;
    -webkit-user-drag: none;
    /* Note: NO `pointer-events: none` — that breaks the close-on-backdrop
       handler (clicks on img bubble to slide and trigger close). The
       browser's native image drag is already neutralized by user-select +
       webkit-user-drag + the draggable=false attribute set in the JS. */
}
.school-lightbox__meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    color: #fff;
    font-size: .9rem;
    gap: 16px;
    padding: 0 20px;
    box-sizing: border-box;
}
.school-lightbox__caption { flex: 1; opacity: .9; }
.school-lightbox__counter { opacity: .7; font-variant-numeric: tabular-nums; }
.school-lightbox__close,
.school-lightbox__nav {
    position: absolute;
    background: rgba(0, 0, 0, .35);
    color: #fff;
    border: none;
    cursor: pointer;
    font-size: 28px;
    line-height: 1;
    padding: 12px 16px;
    transition: background .15s ease;
    z-index: 2;  /* explicitly above the slide track */
}
.school-lightbox__close:hover,
.school-lightbox__nav:hover { background: rgba(0, 0, 0, .65); }
.school-lightbox__close { top: 16px; right: 20px; padding: 8px 14px; font-size: 32px; }
.school-lightbox__nav--prev { left: 20px; top: 50%; transform: translateY(-50%); }
.school-lightbox__nav--next { right: 20px; top: 50%; transform: translateY(-50%); }
@media (max-width: 600px) {
    .school-lightbox__nav { padding: 8px 10px; font-size: 22px; }
    .school-lightbox__close { padding: 6px 10px; font-size: 26px; }
}

/* Info bar — clean horizontal stats row directly below hero.
   Desktop = 5-col even grid, non-sticky.
   Mobile = horizontal scroll strip, sticky below nav, school name slides
   in from the left once the hero scrolls out of view. */
.sp-prof-stats {
    background: #fff;
    border-bottom: 1px solid var(--border);
}
.sp-prof-stats__inner {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0;
}
/* School name element — hidden on desktop. Mobile collapse behavior
   defined in the @media block below. */
.sp-prof-stats__name {
    display: none;
}
.sp-prof-stats__cell {
    overflow: hidden;
}
.sp-prof-stats__cell {
    padding: 22px 24px;
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.sp-prof-stats__cell:last-child { border-right: none; }
.sp-prof-stats__label {
    font-size: .6875rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .08em;
}
.sp-prof-stats__value {
    font-size: 1.5rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1.1;
    letter-spacing: -.01em;
}
.sp-prof-stats__value--sm  { font-size: 1.125rem; }
.sp-prof-stats__value--mint { color: var(--mint-dark); }

@media (max-width: 720px) {
    /* Sticky below the nav as user scrolls. When the hero leaves the
       viewport, the bar collapses to a compact single-line school name —
       cells vanish entirely (both width and height), name takes over. */
    .sp-prof-stats {
        position: sticky;
        top: var(--nav-height);
        z-index: 50;
        box-shadow: var(--shadow);
    }
    .sp-prof-stats__inner {
        display: flex;
        overflow-x: auto;
        scrollbar-width: none;
        align-items: center;
    }
    .sp-prof-stats__inner::-webkit-scrollbar { display: none; }
    .sp-prof-stats__cell {
        flex: 0 0 auto;
        min-width: 130px;
        padding: 12px 18px;
        max-height: 80px;
        transition: max-width .3s ease, max-height .3s ease,
                    min-width .3s ease, padding .3s ease, opacity .2s ease;
    }
    .sp-prof-stats__value { font-size: 1.125rem; }

    /* School name — flex child, collapsed to 0 width/height by default.
       Expands to fill the bar when .sp-prof-stats--collapsed is toggled. */
    .sp-prof-stats__name {
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 1rem;
        font-weight: 700;
        color: var(--navy);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        flex: 0 0 auto;
        max-width: 0;
        max-height: 0;
        padding: 0;
        opacity: 0;
        transition: max-width .3s ease, max-height .3s ease,
                    padding .3s ease, opacity .2s ease, flex-grow .3s ease;
    }

    /* Collapsed state — hero scrolled out. */
    .sp-prof-stats--collapsed .sp-prof-stats__cell {
        max-width: 0;
        min-width: 0;
        max-height: 0;
        padding: 0;
        opacity: 0;
    }
    .sp-prof-stats--collapsed .sp-prof-stats__name {
        flex: 1 1 100%;
        max-width: 100%;
        max-height: 60px;
        padding: 10px 18px;
        opacity: 1;
    }
}

/* About paragraph — slightly larger than global p, full --text color so the
   description reads as informational rather than the article's softer
   reading-tone --text-muted. Drift documented; deferred reconciliation. */
.sp-prof-about {
    font-size: 1.0625rem;
    line-height: 1.75;
    color: var(--text);
    max-width: 660px;
}

/* Facts grid — 2-col k/v pairs. Lighter visual weight than the old
   bordered-row pattern; scans like a passport detail panel. */
.sp-prof-facts {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px 32px;
    font-size: .9375rem;
    color: var(--text);
}
.sp-prof-facts__row { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.sp-prof-facts__k {
    color: var(--text-muted);
    font-weight: 500;
    flex-shrink: 0;
}
.sp-prof-facts__v {
    color: var(--navy);
    font-weight: 700;
    word-break: break-word;
}
.sp-prof-facts__v--mint { color: var(--mint-dark); }
.sp-prof-facts__v--muted { color: var(--text-muted); font-weight: 600; }

/* Data-state note — italic footnote under a section whose backing data is
   incomplete (e.g. "renders only when junction table has rows"). */
.sp-prof-data-note {
    font-size: .8125rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 14px 0 0;
    font-style: italic;
}

/* Sponsored quote — "Lời nhắn từ trường". Slightly larger body text, optional
   italic feel via the attribution line below it. Renders inside an .sp-prof-section
   like every other section — no surface chrome, no extra card. */
.sp-prof-quote {
    /* Inherits .sp-prof-about sizing/color */
    max-width: 720px;
}
.sp-prof-quote__attribution {
    font-size: .9375rem;
    font-weight: 600;
    color: var(--text-muted);
    margin: 14px 0 0;
    font-style: italic;
}

/* Sponsored bullets — "Điểm nổi bật" + "Phù hợp với học sinh Việt Nam".
   Clean bulleted list with green check + body text. No card chrome. */
.sp-prof-bullets {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 14px 32px;
}
.sp-prof-bullets__item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 1rem;
    line-height: 1.55;
    color: var(--text);
}
.sp-prof-bullets__check {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--mint-dark);
    font-weight: 800;
    font-size: .875rem;
    margin-top: 2px;
}
.sp-prof-bullets__text {
    flex: 1;
}

@media (max-width: 720px) {
    .sp-prof-bullets { grid-template-columns: 1fr; gap: 10px; }
}

@media (max-width: 720px) {
    .sp-prof-facts { grid-template-columns: 1fr; gap: 10px; }
}

/* ─── Rankings hub + per-list canon (2026-05-12) ────────────────────────────
   Templates: page-xep-hang.php (hub) + template-ranking-list.php (per-list).
   Patterns: hero band like school profile, mint-underlined section titles,
   editorial text rows for hub list, big-rank editorial rows for per-list,
   sticky right-rail navy CTA on per-list (matches school profile context-card). */

.container--narrow { max-width: 800px; }

.rankings-page { background: #fff; }

/* Hero band */
.rankings-hero {
    background: linear-gradient(135deg, #0D2840 0%, #1a3a55 100%);
    color: #fff;
    padding: 48px 0 40px;
}
.rankings-hero__crumb {
    font-size: .75rem;
    font-weight: 700;
    color: var(--overlay-mint-strong);
    text-transform: uppercase;
    letter-spacing: .1em;
    margin: 0 0 12px;
}
.rankings-hero__crumb a {
    color: inherit;
    opacity: .7;
    text-decoration: none;
    transition: opacity var(--ease-fast);
}
.rankings-hero__crumb a:hover { opacity: 1; }
.rankings-hero__title {
    font-size: clamp(1.75rem, 3.5vw, 2.5rem);
    font-weight: 800;
    color: #fff;
    line-height: 1.2;
    letter-spacing: -.02em;
    margin: 0 0 14px;
}
.rankings-hero__intro {
    color: rgba(255,255,255,.8);
    font-size: 1rem;
    line-height: 1.6;
    max-width: 680px;
    margin: 0;
}
.rankings-hero__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 22px;
    font-size: .8125rem;
    color: rgba(255,255,255,.65);
}
.rankings-hero__meta-item strong { color: #fff; font-weight: 600; }
.rankings-hero__source-link { color: var(--mint); text-decoration: none; font-weight: 600; font-size: inherit; }
.rankings-hero__source-link:hover { color: #fff; }

/* Body wrapper */
.rankings-body {
    padding: 48px 0 72px;
    background: var(--bg);
}

/* Hub: section titles + editorial row list */
.rankings-section { margin-bottom: 48px; }
.rankings-section:last-child { margin-bottom: 0; }

/* Hub list — pad rows symmetrically at base so the hover background can
   change without shifting the row's layout box (the previous margin/padding
   swap caused horizontal "bouncing" on hover). */
.rankings-list { display: flex; flex-direction: column; margin: 0 -16px; }
.rankings-list__row {
    display: grid;
    grid-template-columns: 150px 1fr auto;
    gap: 20px;
    align-items: baseline;
    padding: 18px 16px;
    border-top: 1px solid var(--border);
    color: var(--navy);
    text-decoration: none;
    transition: background var(--ease-fast);
}
.rankings-list__row:first-child { border-top: none; }
/* Unified row hover canon: title underline only — no bg-change.
   (Removed `background: var(--surface)` on hover 2026-05-12.) */
.rankings-list__row:hover .rankings-list__label { text-decoration-color: var(--mint-dark); color: var(--mint-dark); }
.rankings-list__source {
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .06em;
    line-height: 1.35;
    min-width: 0;
    overflow-wrap: break-word;
}
.rankings-list__main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.rankings-list__label {
    font-size: 1rem; font-weight: 700; color: var(--navy); line-height: 1.3;
    /* Card-title canon: transparent underline at rest, mint on parent :hover */
    text-decoration: underline; text-decoration-color: transparent;
    text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.rankings-list__desc  { font-size: .8125rem; color: var(--text-muted); line-height: 1.55; }
.rankings-list__count {
    font-size: .75rem;
    font-weight: 600;
    color: var(--text-muted);
    white-space: nowrap;
}

@media (max-width: 600px) {
    .rankings-list__row { grid-template-columns: 1fr auto; gap: 12px; }
    .rankings-list__source { grid-column: 1 / -1; padding-bottom: 4px; }
}

/* Ranked rows — editorial big-number style. Same stable-geometry trick as
   the hub list: pad rows always, hover only changes background. */
.ranking-rows { display: flex; flex-direction: column; margin: 0 -16px; }
.ranking-row {
    display: grid;
    /* 72px on the rank column accommodates 3-digit ranks (#100, #999)
       without overlapping the title — 56px was tight on lists that go
       past #99 (Top 100 universities, etc.). */
    grid-template-columns: 72px 1fr auto;
    gap: 16px;
    align-items: center;
    padding: 18px 16px;
    border-top: 1px solid var(--border);
    color: var(--navy);
    text-decoration: none;
    transition: background var(--ease-fast);
}
.ranking-row:first-child { border-top: none; }
/* Row hover canon: title underline only — no bg-change. Aligns with
   .sc-row + .hub-article-row treatment. (Removed `background: var(--surface)`
   on hover 2026-05-12 per unified-row-hover canon.) */
.ranking-row__rank {
    font-size: 1.75rem;
    font-weight: 800;
    color: var(--navy);
    line-height: 1;
    letter-spacing: -.02em;
}
.ranking-row__main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ranking-row__title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.3;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.ranking-row__sponsor {
    color: var(--amber);
    font-size: .875rem;
    font-weight: 700;
}
.ranking-row__loc { font-size: .8125rem; color: var(--text-muted); }
.ranking-row__stat { text-align: right; min-width: 80px; }
.ranking-row__stat-num { font-size: 1.125rem; font-weight: 800; color: var(--navy); line-height: 1; }
.ranking-row__stat-label {
    font-size: .625rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .08em;
    margin-top: 4px;
}

@media (max-width: 600px) {
    .ranking-row { grid-template-columns: 56px 1fr auto; gap: 12px; padding: 14px 0; }
    .ranking-row__rank { font-size: 1.375rem; }
    .ranking-row__title { font-size: .9375rem; }
}

/* Right-rail CTA — matches school profile context-card--navy shape */
.ranking-cta {
    background: var(--navy);
    color: #fff;
    padding: 24px 22px;
}
.ranking-cta__eyebrow {
    font-size: .6875rem;
    font-weight: 800;
    letter-spacing: .1em;
    color: var(--mint);
    text-transform: uppercase;
    margin: 0 0 10px;
}
.ranking-cta__head {
    font-size: 1.125rem;
    font-weight: 800;
    color: #fff;
    margin: 0 0 12px;
    line-height: 1.25;
}
.ranking-cta__body {
    font-size: .875rem;
    color: rgba(255,255,255,.72);
    line-height: 1.55;
    margin: 0 0 18px;
}
.ranking-cta__btn {
    display: block;
    width: 100%;
    text-align: center;
    background: var(--amber);
    color: var(--navy);
    padding: 11px 16px;
    text-decoration: none;
    font-weight: 800;
    font-size: .9375rem;
    font-family: inherit;
    border: 0;
    cursor: pointer;
    transition: background var(--ease-fast);
}
.ranking-cta__btn:hover { background: var(--amber-dark); }

.sp-photo-placeholder {
    aspect-ratio: 4 / 3;
    background: linear-gradient(135deg, var(--navy) 0%, #1a4d38 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: .4;
}
.sp-photo-placeholder svg {
    width: 28px;
    height: 28px;
    color: #fff;
}

/* Inline variant — sits inside the body container right after the school
   detail sections, just before the CTA banner. Quieter than the footer
   variant, container-constrained so it aligns to the body content. */
.sp-verified-inline {
    max-width: var(--container-narrow, 1200px);
    margin: 0 auto;
    padding: 0 var(--gap-md) var(--gap-md);
    font-size: .75rem;
    color: var(--text-light);
    text-align: left;
}

/* Community section stats — big total-students card on the left,
   donut charts for the percentage breakdowns on the right. Wraps
   to stacked layout when the column gets narrow. */
.sp-community-stats {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--gap-md) var(--gap-xl);
    margin-bottom: 28px;
}
.sp-community-donuts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-md) var(--gap-lg);
    align-items: flex-start;
    padding: var(--card-pad-lg);
}

/* Sub-heading within a section (sports, clubs labels) */
.sp-sub-heading {
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 28px 0 10px;
}
.sp-sub-heading:first-of-type { margin-top: 4px; }

/* Tag cloud */
.sp-tag-cloud {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* Majors-cloud toggle: tags past the 15th get .is-hidden by default and
   reveal when the parent .sp-tag-cloud gets .is-expanded (via JS toggle on
   the .sp-majors-toggle inline link). */
.sp-tag-cloud .tag.is-hidden { display: none; }
.sp-tag-cloud.is-expanded .tag.is-hidden { display: inline-flex; }
.sp-majors-toggle {
    color: var(--mint-dark);
    text-decoration: none;
    font-weight: 700;
    border-bottom: 2px solid var(--mint);
    padding-bottom: 1px;
}
.sp-majors-toggle:hover { color: var(--navy); }

/* (Old amber-section sponsored chrome removed — replaced by canonical
   .school-quote / .school-highlights / .school-vn-callout interleaved
   into About / Academics / Community.) */

/* Reviews */
.sp-demo-notice {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--amber);
    padding: 10px 16px;
    font-size: .8125rem;
    color: var(--text-muted);
    margin-bottom: 20px;
}

.sp-review-card {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 20px 22px;
}

.sp-review-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.sp-review-card__name {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    margin-bottom: 2px;
}

.sp-review-card__meta {
    font-size: .8125rem;
    color: var(--text-muted);
}

.sp-review-card__stars { display: flex; gap: 2px; flex-shrink: 0; }

.review-star       { color: var(--amber); font-size: .9rem; }
.review-star--empty { color: var(--border); }

.sp-review-card__text {
    font-size: .9rem;
    line-height: 1.75;
    color: var(--text-muted);
    margin: 0;
}

.sp-review-card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 14px;
}

/* ─── Profile responsive ──────────────────────────────────────────── */
@media (max-width: 768px) {
    .sp-header { min-height: 300px; }
    .sp-header__content { padding: 36px 0 32px; }
    .sp-header__name { font-size: clamp(1.5rem, 7vw, 2rem); }

    .sp-stat { min-width: 105px; padding: 12px 14px; }
    .sp-stat__value { font-size: 1.0625rem; }

    /* When name is visible on mobile, hide stats — not enough room for both */
    .sp-stats-bar__name--visible + .sp-stats-bar__scroll { display: none; }
    .sp-stats-bar__name--visible {
        max-width: 100%;
        padding: 12px 0;
        border-right: none;
        margin-right: 0;
    }
}

@media (max-width: 480px) {
    .sp-header__meta { gap: 10px; }
    .sp-header__meta-item { font-size: .8125rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LISTING PAGE
   ═══════════════════════════════════════════════════════════════════════════ */

/* (.listing-hero — bg, padding, title, subtitle all from canonical
   .page-header--navy grouped selectors at top of stylesheet.
   Subtitle changed from mint to muted-white per consolidation.) */

/* Mobile top bar (hidden on desktop) */
.listing-mobile-top { display: none; }

/* Layout */
.listing-layout {
    display: flex;
    gap: var(--gap-lg);
    padding: var(--section-xs) 0 var(--section-md);
    align-items: flex-start;
}

/* ─── Sidebar ──────────────────────────────────────────────────── */
.listing-sidebar {
    width: 230px;
    flex-shrink: 0;
    position: sticky;
    top: calc(var(--nav-height) + 24px);
    max-height: calc(100vh - var(--nav-height) - 40px);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Desktop filter header */
.sidebar-desktop-header {
    flex-shrink: 0;
    padding-bottom: 12px;
    border-bottom: 2px solid var(--navy);
    margin-bottom: 4px;
}
.sidebar-desktop-header__title {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--navy);
}

/* Scrollable body — overflow goes here, NOT on the sticky parent */
.sidebar-body {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
    padding-right: 14px;
}
.sidebar-body::-webkit-scrollbar { width: 4px; }
.sidebar-body::-webkit-scrollbar-thumb { background: var(--border); }

.sidebar-mobile-header { display: none; }

/* Filter groups */
.filter-group {
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
}
.filter-group--last { border-bottom: none; }

.filter-group__title {
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--navy);
    margin-bottom: 10px;
}

.filter-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .875rem;
    color: var(--text);
    cursor: pointer;
    padding: 3px 0;
    user-select: none;
    line-height: 1.4;
}
.filter-check input[type="checkbox"] {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    accent-color: var(--mint-dark);
    cursor: pointer;
}

/* Filter sidebar inputs — canonical class for any text input that lives
   inside .sidebar-body (state search, sport / club / major autocompletes).
   Distinct from the sitewide .form-input canon: filters are sculpting a
   list, not entering data — the boxed/inset visual marks "navigation,
   not data entry" (same pattern GitHub, Linear, Stripe Dashboard use).
   Inset focus outline is deliberate — the canonical 2px bottom-rule
   focus from .form-input gets clipped by .sidebar-body's overflow-x:hidden,
   so we use a full mint ring on all four sides instead. 14px font is the
   compromise (we'd love 16px for iOS no-zoom, but it crowds the sidebar). */
.filter-input {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--border);
    border-radius: 0;
    background: var(--surface);
    padding: 8px 12px;
    font-size: .875rem;
    font-family: var(--font);
    color: var(--text);
    margin-bottom: 8px;
}
.filter-input:focus {
    outline: 2px solid var(--mint);
    outline-offset: -2px;
    border-color: var(--mint);
    box-shadow: none;
}

.filter-scroll {
    max-height: 190px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.filter-scroll::-webkit-scrollbar { width: 4px; }
.filter-scroll::-webkit-scrollbar-thumb { background: var(--border); }

/* Sport picker (autocomplete + chips, sidebar filter) */
.sport-picker { position: relative; }
.sport-picker__chips { display: flex; flex-wrap: wrap; gap: 6px; min-height: 0; margin-bottom: 8px; }
.sport-picker__chips:not(:empty) { margin-bottom: 10px; }
/* (.sport-chip family migrated to canonical .chip in the 2026-05-14 atoms
   sweep — markup now uses .chip / .chip__label / .chip__close.)
   (.sport-picker__search rules removed — the search input uses the
   canonical .filter-input class shared with other sidebar filter inputs.) */
.sport-picker__dropdown {
    position: absolute; z-index: 50;
    background: #fff; border: 1px solid var(--border);
    max-height: 260px; overflow-y: auto;
    width: 100%; margin-top: 2px;
    box-shadow: 0 4px 12px rgba(0,0,0,.08);
    border-radius: 6px;
}
.sport-picker__option {
    padding: 7px 12px; cursor: pointer;
    display: flex; flex-direction: column; gap: 1px;
    font-size: .875rem;
    line-height: 1.3;
}
.sport-picker__option:hover { background: var(--surface); }
.sport-picker__option.is-selected { display: none; }
.sport-picker__option-vi { font-weight: 600; color: var(--navy); }
.sport-picker__option-en {
    color: var(--text-muted);
    font-size: .7rem;
    font-style: italic;
}
.sport-picker__option-count { display: none; } /* admin only — hidden on user-facing filter */
.sport-picker__popular {
    margin-top: 10px;
    display: flex; flex-wrap: wrap; gap: 5px;
    align-items: center;
}
.sport-picker__popular-label {
    font-size: .75rem; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: .04em;
    margin-right: 4px;
}
.sport-quick-add {
    border: 1px solid var(--border);
    background: #fff;
    border-radius: 12px;
    padding: 3px 10px;
    font-size: .8125rem;
    color: var(--navy);
    cursor: pointer;
    font-family: inherit;
    line-height: 1.4;
}
.sport-quick-add:hover {
    background: var(--navy); color: #fff; border-color: var(--navy);
}

/* Sliders */
.filter-slider-display {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    margin-bottom: 10px;
}
input[type="range"] {
    -webkit-appearance: none;
    width: 100%;
    height: 3px;
    background: var(--border);
    cursor: pointer;
    outline: none;
}
input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 18px;
    height: 18px;
    background: var(--navy);
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 0 0 2px var(--navy);
    cursor: pointer;
}
input[type="range"]:focus::-webkit-slider-thumb {
    box-shadow: 0 0 0 3px var(--mint);
}

/* (.sidebar-cta block removed 2026-05-14 — the in-sidebar lead CTA on
   listing pages was dropped per Brett's call. The listing-uni / listing-thpt
   lead_source values are no longer canonical surfaces; see
   docs/lead-form-taxonomy.md.) */

/* Sidebar footer — always visible, outside the scroll body */
.sidebar-footer {
    flex-shrink: 0;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.filter-reset {
    background: transparent;
    border: 1px solid var(--border);
    padding: 9px;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
    font-family: var(--font);
    transition: color .15s, border-color .15s;
    text-align: center;
}
.filter-reset:hover { color: var(--navy); border-color: var(--navy-light); }

.sidebar-apply { display: none; } /* shown on mobile only */

/* ─── Results area ─────────────────────────────────────────────── */
.listing-results { flex: 1; min-width: 0; }

.results-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
    scroll-margin-top: calc(var(--nav-height) + 16px);
}
.results-count {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
}

/* ── View toggle ──────────────────────────────────────────────── */
.view-toggle { display: flex; gap: 2px; }
.view-toggle--mobile { display: none; }
.view-toggle__btn {
    width: 30px; height: 30px;
    display: flex; align-items: center; justify-content: center;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}
.view-toggle__btn:hover { border-color: var(--navy); color: var(--navy); }
.view-toggle__btn.is-active { background: var(--navy); border-color: var(--navy); color: #fff; }

/* ── Image grid layout ────────────────────────────────────────── */
/* minmax(0, 1fr) prevents wide content (e.g. .school-card data cards present
   for a frame after toggling to image view, before AJAX swaps them) from
   pushing columns past their share of the row, which used to cause the grid
   to briefly overflow the right margin during the view-toggle transition. */
.school-grid--image { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 1100px) { .school-grid--image { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 700px)  { .school-grid--image { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 420px)  { .school-grid--image { grid-template-columns: minmax(0, 1fr); } }

/* ── List view · editorial-row pattern (shipped 2026-05-12, Row A canon) ─
   Same chrome family as cat-article-row, hub-article-row, ranking-row:
   16px symmetric padding, hairline border-top between rows, whole-row
   hover bg → surface, name shifts mint-dark, chevron animates right.
   Three fixed-width stat columns let the eye scan vertically. */

/* Column header — only shown when list view is active (toggled by JS).
   5-column grid: [main] [rate] [cost] [students] [chev-spacer]. Sticky
   below the nav. */
.sc-row-header {
    display: none;
    grid-template-columns: 1fr repeat(3, 78px) 18px;
    gap: 18px;
    align-items: center;
    padding: 14px 16px 10px;
    background: #fff;
    border-bottom: 1px solid var(--border);
    font-size: .6875rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    position: sticky;
    top: var(--nav-height, 68px);
    z-index: 5;
}
.sc-row-header.is-visible { display: grid; }
.sc-row-header__stat { text-align: right; }

.school-grid--list {
    display: flex;
    flex-direction: column;
    gap: 0;  /* override .school-grid base gap so rows hang flush */
    background: #fff;
}

.sc-row {
    display: grid;
    grid-template-columns: 1fr repeat(3, 78px) 18px;
    gap: 18px;
    align-items: center;
    padding: 16px;
    border-top: 1px solid var(--border);
    color: var(--navy);
    text-decoration: none;
    transition: background var(--ease-fast);
}
.school-grid--list .sc-row:first-child { border-top: none; }
/* Row hover canon: title underline only — no bg-change. .sc-row:hover
   .sc-row__name color + underline come from the shared card-title canon
   (search "card-title canon"). (Removed `background: var(--surface)`
   on hover 2026-05-12 per unified-row-hover canon.) */

.sc-row__main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.sc-row__name {
    font-size: 1rem;
    font-weight: 700;
    /* color + text-decoration come from the shared card-title canon */
    line-height: 1.3;
}
.sc-row__meta {
    font-size: .8125rem;
    color: var(--text-muted);
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    align-items: baseline;
}
.sc-row__stat { text-align: right; line-height: 1.2; }
.sc-row__stat strong {
    font-size: .9375rem;
    font-weight: 700;
    color: var(--navy);
    display: inline;
}
.sc-row__stat--empty { color: var(--text-light); font-weight: 400; }

.sc-row__chev {
    color: var(--text-muted);
    transition: color var(--ease-fast), transform var(--ease-fast);
}
.sc-row:hover .sc-row__chev { color: var(--mint-dark); transform: translateX(3px); }

@media (max-width: 720px) {
    /* Mobile: hide column header + the cost/students stats. Keep name +
       acceptance-rate + chevron for scannable single-line rows. */
    .sc-row-header { display: none !important; }
    .sc-row {
        grid-template-columns: 1fr 60px 18px;
        gap: 12px;
        padding: 12px 16px;
    }
    .sc-row__name { font-size: .9375rem; }
    .sc-row__meta { font-size: .75rem; gap: 8px; }
    .sc-row__stat--cost,
    .sc-row__stat--students { display: none; }
    .sc-row__stat strong { font-size: .8125rem; }
}

/* ── Image card (photo-forward grid) ─────────────────────────────────── */
.sc-img {
    background: #fff;
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: transform .2s ease, box-shadow .2s ease;
}
/* .sc-img:hover lift+shadow retired 2026-05-16. Image-zoom (above) is the
   sole hover affordance. Title color shift comes from shared card-title canon. */
/* Hover underline + color shift come from the shared card-title canon
   (search "card-title canon"). */

/* Photo / initials placeholder — the primary visual.
   Navy bg fills the area when no image is present (e.g. featured-school
   cards on event campaign pages where image is optional). */
.sc-img__photo {
    position: relative;
    aspect-ratio: 4 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    overflow: hidden;
    background: var(--navy);
}
.sc-img__photo img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.sc-img__initials {
    font-size: 2.5rem;
    font-weight: 800;
    color: rgba(255, 255, 255, .18);
    font-family: var(--font);
    letter-spacing: -.02em;
    user-select: none;
    position: relative;
    z-index: 1;
}

/* Position helper for the sponsored badge overlaid on the school card
   photo. Pairs with .badge .badge--amber for chrome — this class only
   handles absolute positioning over the image. */
.sc-img__badge-pos {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 2;
}

/* Body — minimal: just name + location */
.sc-img__body {
    padding: 16px 18px 18px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.sc-img__name {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    margin: 0;
    line-height: 1.3;
}
/* .sc-img__name-text — inner span on the H3. V2 underline rules come from
   the shared card-title canon further up. The clone wrapper is kept so
   multi-line titles wrap with per-line underlines. */
.sc-img__name-text {
    display: inline;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}

.sc-img__location {
    font-size: .8125rem;
    color: var(--text-muted);
    line-height: 1.4;
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
}
.sc-img__location-flag {
    font-size: 1rem;
    line-height: 1;
}

/* ── Active filter pills ──────────────────────────────────────── */
.active-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 16px;
}
/* (.filter-pill family deleted in the 2026-05-14 atoms sweep — was
   dead code, no templates or JS referenced it.)
   (.school-grid.is-loading and .no-results — both now use canonical
   state patterns from the State patterns section at top.) */

.load-more-wrap { text-align: center; margin-top: 36px; }

/* ─── Overlay ──────────────────────────────────────────────────── */
.listing-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--overlay-navy-light);
    z-index: 199;
}
.listing-overlay.is-visible { display: block; }

/* ─── Filter toggle (mobile only) ──────────────────────────────── */
.filter-toggle-btn {
    display: none;
    align-items: center;
    gap: 7px;
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 9px 14px;
    font-size: .875rem;
    font-weight: 700;
    color: var(--navy);
    cursor: pointer;
    font-family: var(--font);
}

.filter-badge {
    background: var(--mint);
    color: var(--navy);
    font-size: .625rem;
    font-weight: 800;
    padding: 2px 6px;
    border-radius: 20px;
    min-width: 18px;
    text-align: center;
    line-height: 1.5;
}

/* ─── Related X widget · canonical pattern ─────────────────────────── */
/* Canonical wrapper for "related items" surfaces — used at the bottom
   of detail pages (related schools on school profile, related articles
   on article single, future related events / students / etc.).

   Composes with canonical components:
   - Header: .section-header.section-header--with-action (title + see-all action)
   - Layout: .related-widget__grid (3-column cards) OR .related-widget__strip (horizontal scroll)

   Stack multiple widgets inside .related-widgets-section. */

.related-widgets-section {
    background: var(--surface);
    padding: var(--section-md) 0 var(--section-lg);
    border-top: 1px solid var(--border);
}

.related-widget + .related-widget {
    margin-top: var(--section-sm);  /* space between stacked widgets */
}

/* Header — uses canonical .section-header.section-header--with-action
   via grouped selectors at top of stylesheet. .related-widget__header is
   an alias of those. Margin-bottom for the gap to the content layout. */
.related-widget__header {
    margin-bottom: var(--gap-md);
}

/* Layout: 3-column grid of cards (article-card, etc.).
   Breakpoints: 3 → 2 cols at 900px → 1 col at 540px. Keeps cards from
   ballooning to full container width on narrow desktop / tablet windows. */
.related-widget__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gap-md);
}
@media (max-width: 900px) {
    .related-widget__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 540px) {
    .related-widget__grid { grid-template-columns: 1fr; }
}

/* Layout: horizontal scroll strip (sc-img cards on school profile) */
.related-widget__strip {
    display: flex;
    gap: var(--gap-sm);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: var(--gap-md);
    scrollbar-width: none;
}
.related-widget__strip::-webkit-scrollbar { display: none; }
.related-widget__strip > * {
    flex-shrink: 0;
    scroll-snap-align: start;
}
.related-widget__strip .sc-img { width: 220px; }

/* Old .related-widget__see-all aliases to canonical .link-action via
   markup migration; this rule kept for any legacy markup not yet updated */
.related-widget__see-all {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: .875rem;
    font-weight: 700;
    color: var(--navy);
    white-space: nowrap;
    flex-shrink: 0;
    transition: color var(--ease-fast);
}
.related-widget__see-all svg { transition: transform var(--ease-base); }
.related-widget__see-all:hover { color: var(--mint-dark); }
.related-widget__see-all:hover svg { transform: translateX(3px); }

/* ─── Mobile (≤ 768px) ─────────────────────────────────────────── */
@media (max-width: 768px) {

    /* Sticky controls bar — pinned below the site nav so users can always
       reach Bộ lọc + see result count + flip view without scrolling up.
       Negative margin lets the white background extend edge-to-edge while
       the bar's content stays within the .container's 24px padding. */
    .listing-mobile-top {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 12px 24px;
        margin: 0 -24px;
        background: #fff;
        border-bottom: 1px solid var(--border);
        position: sticky;
        top: var(--nav-height);
        z-index: 50;
    }

    .listing-mobile-top .results-count { flex: 1; text-align: center; }

    /* Push the scroll-into-view target below the sticky controls bar so
       fetched results don't land hidden behind it. */
    .results-header {
        scroll-margin-top: calc(var(--nav-height) + 64px);
    }

    .filter-toggle-btn { display: flex; flex-shrink: 0; }

    .view-toggle--mobile { display: flex; flex-shrink: 0; }

    .listing-layout { padding-top: 12px; }

    /* Sidebar becomes a fixed drawer */
    .listing-sidebar {
        position: fixed;
        left: 0;
        top: 0;
        bottom: 0;
        width: min(300px, 85vw);
        max-height: 100vh;
        background: var(--bg);
        z-index: 200;
        padding: 0 20px 20px;
        transform: translateX(-100%);
        transition: transform .25s ease;
        box-shadow: none;
    }
    .listing-sidebar.is-open {
        transform: translateX(0);
        box-shadow: var(--shadow-md);
    }

    .sidebar-desktop-header { display: none; }

    .sidebar-mobile-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 18px 0 14px;
        border-bottom: 1px solid var(--border);
        margin-bottom: 4px;
        position: sticky;
        top: 0;
        background: var(--bg);
        z-index: 1;
    }
    .sidebar-mobile-header__title { font-weight: 800; color: var(--navy); font-size: 1rem; }

    .sidebar-close {
        background: none;
        border: none;
        cursor: pointer;
        color: var(--text-muted);
        padding: 4px;
        display: flex;
        align-items: center;
    }

    .sidebar-apply { display: block; }

    /* Results take full width */
    .listing-results { width: 100%; }

    .results-header { display: none; } /* count shown in mobile top bar instead */

}


/* ═══════════════════════════════════════════════════════════════════════════
   ARTICLE SINGLE PAGE
   ═══════════════════════════════════════════════════════════════════════════ */

/* (.article-cat-badge / .article-level-badge family deleted in the
   2026-05-14 atoms sweep — only consumer was page-article-demo.php
   which was also retired. Real article single uses .tag--mint for
   category and .tag--level-* for level.) */

/* ─── Article header ────────────────────────────────────────────────────── */
/* .article-header — bg/padding/title from canonical .page-header at top.
   Article-specific layout below: badges row above title, byline below. */
.article-header {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}
.article-header__inner {
    max-width: var(--container-sm);
}
.article-header__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-2xs);
    margin-bottom: var(--gap-md);
}
.article-title {
    /* Reading Mode: article H1 scales fluidly between 30px → 42px.
       text-wrap:balance evens out multi-line wraps so long Vietnamese
       titles look intentional rather than orphaned. */
    font-size: clamp(1.875rem, 4vw + .5rem, 2.625rem);
    line-height: 1.15;
    letter-spacing: -.025em;
    text-wrap: balance;
    margin: 0 0 var(--gap-md);
}
.article-byline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: .875rem;
    color: var(--text-muted);
}
.article-byline__author { font-weight: 600; color: var(--text); }
.article-byline__sep    { color: var(--border); }

/* ─── Hero image ────────────────────────────────────────────────────────── */
.article-hero {
    width: 100%;
    max-height: 500px;
    overflow: hidden;
    background: var(--surface);
}
.article-hero__img,
.article-hero img {
    width: 100%;
    height: 500px;
    object-fit: cover;
    display: block;
}

/* Article-single page wrapper — vertical padding for the body+sidebar
   layout. Canonical .detail-layout doesn't own padding; consumers do. */
.article-page { padding: var(--section-md) 0 var(--section-lg); }
@media (max-width: 768px) {
    .article-page { padding: 32px 0 48px; }
}

/* ─── Article body prose — READING MODE ─────────────────────────────────── */
/* Reading Mode: 640px column, larger body, looser breathing room, mint
   kicker bars on H2, gradient pull-quote on blockquote, subtle hover-fill
   on links. Paragraphs deliberately fall through to the global `p` rule
   (16px / 1.75 / muted) — gives the softer reading tone. Other elements
   (lede, lists, blockquote) match that rhythm so the page reads as one. */
.prose {
    max-width: 640px;
    margin-left: auto;
    margin-right: auto;
    font-size: 1.125rem;       /* 18px — applies to non-<p> elements like li, blockquote */
    line-height: 1.75;
    letter-spacing: -.005em;
    color: var(--text);
}
.prose .lede {
    font-size: 1.375rem;
    line-height: 1.5;
    color: var(--navy);
    font-weight: 500;
    margin: 0 0 1.75em;
    padding-bottom: 1.5em;
    border-bottom: 1px solid var(--border);
}
.prose h2 {
    font-size: 2rem;
    font-weight: 800;
    color: var(--navy);
    margin: 2.5em 0 .6em;
    line-height: 1.2;
    letter-spacing: -.02em;
}
.prose h2::before {
    content: "";
    display: block;
    width: 32px;
    height: 3px;
    background: var(--mint);
    margin-bottom: 20px;
}
.prose h3 {
    font-size: 1.375rem;
    font-weight: 800;
    color: var(--navy);
    margin: 2em 0 .5em;
    line-height: 1.3;
    letter-spacing: -.01em;
}
.prose h4 {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    margin: 1.5em 0 .4em;
}
.prose p {
    margin: 0 0 1.5em;
    /* font-size / line-height / color fall through to global `p` rule at
       style.css:166 — 16px / 1.75 / --text-muted — for the softer reading
       tone. */
}
.prose p:last-child { margin-bottom: 0; }

.prose strong { font-weight: 700; color: var(--navy); }
.prose em     { font-style: italic; }

.prose a {
    color: var(--navy);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid var(--mint);
    transition: border-color .15s, background .15s;
}
.prose a:hover {
    background: #e7f8f0;
    border-bottom-color: var(--navy);
}

.prose blockquote {
    margin: 2em -24px;
    padding: 32px 40px;
    background: linear-gradient(135deg, var(--mint-light) 0%, var(--surface) 100%);
    border: none;
    font-style: normal;
    font-size: 1.3125rem;
    line-height: 1.5;
    color: var(--navy);
    font-weight: 500;
    position: relative;
}
.prose blockquote::before {
    content: "\201C";  /* opening curly quote */
    position: absolute;
    top: -8px;
    left: 16px;
    font-size: 4rem;
    color: var(--mint);
    font-family: Georgia, serif;
    line-height: 1;
    font-weight: 700;
}
.prose blockquote p {
    margin: 0;
    padding-left: 30px;
    color: var(--navy);    /* override the global muted p color inside pull-quotes */
    font-size: 1.3125rem;
    line-height: 1.5;
    font-weight: 500;
}
/* Multi-paragraph pull-quotes — give sibling <p>s breathing room
   instead of jamming them together with margin: 0. */
.prose blockquote p + p { margin-top: .9em; }
/* The blockquote IS the emphasis — neutralize redundant <em>/<strong>
   wrappers some authors add inside, which otherwise stack italic+bold
   on top of the canonical navy weight-500 treatment and look heavy. */
.prose blockquote em,
.prose blockquote strong {
    font-style: inherit;
    font-weight: inherit;
}
.prose blockquote cite {
    display: block;
    margin-top: 16px;
    padding-left: 30px;
    font-style: normal;
    font-size: .9375rem;
    color: var(--text-muted);
    font-weight: 600;
}

.prose img {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 1.75em 0;
}

.prose hr {
    border: none;
    border-top: 2px solid var(--border);
    margin: 2.5em 0;
}

.prose table {
    width: 100%;
    border-collapse: collapse;
    font-size: .9375rem;
    margin: 1.75em 0;
}
.prose th {
    background: var(--navy);
    color: #fff;
    padding: 10px 14px;
    text-align: left;
    font-weight: 700;
    font-size: .875rem;
}
.prose td {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
}
.prose tr:nth-child(even) td { background: var(--surface); }

/* ─── Sidebar ───────────────────────────────────────────────────────────── */
/* .article-sidebar is a marker class on the article-single aside, used
   only for the mobile reordering tricks below (CTA above body, widgets
   below body). Desktop sticky behavior comes from .detail-layout__aside. */
.article-cta-card {
    background: var(--navy);
    color: #fff;
    padding: 28px 24px 32px;
}
/* Spacing below the CTA card when sidebar widgets follow it. .cat-side-section
   has margin-bottom but no margin-top, so the gap has to come from above.
   Matches the equivalent rule on .detail-layout__aside .context-card. */
.article-sidebar .article-cta-card { margin-bottom: var(--gap-lg); }
.article-cta-card__eyebrow {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mint);
    margin: 0 0 10px;
}
.article-cta-card__headline {
    font-size: 1.1875rem;
    font-weight: 800;
    color: #fff;
    line-height: 1.3;
    margin: 0 0 12px;
}
.article-cta-card__body {
    font-size: .9rem;
    line-height: 1.6;
    color: rgba(255,255,255,.75);
    margin: 0 0 24px;
}
/* (Was .article-cta-card__btn / .btn--cta — replaced with .btn.btn--primary.btn--block) */

/* ─── Post-article CTA banner ────────────────────────────────────────────── */
.article-cta-banner {
    background: var(--navy);
    padding: var(--section-sm) 0;
}
.article-cta-banner__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
}
.article-cta-banner__text strong {
    display: block;
    font-size: 1.25rem;
    font-weight: 800;
    color: #fff;
    margin-bottom: 8px;
}
.article-cta-banner__text p {
    font-size: .9375rem;
    color: rgba(255,255,255,.75);
    margin: 0;
    max-width: 520px;
}
.article-cta-banner .btn--block {
    flex-shrink: 0;
    width: auto;
}

/* (.related-articles removed — single-articles now uses canonical
   .related-widgets-section + .related-widget pattern at top of stylesheet.) */

/* ─── Article card ────────────────────────────────────────────────────────── */
.article-card {
    display: flex;
    flex-direction: column;
    background: var(--bg);
    border: 1px solid var(--border);
    text-decoration: none;
    color: inherit;
    transition: box-shadow .18s, transform .18s;
}
/* .article-card:hover lift+shadow retired 2026-05-16. */
.article-card__img {
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--surface);
}
.article-card__img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .3s ease;
}
.article-card:hover .article-card__img img { transform: scale(1.03); }

.article-card__body {
    padding: var(--card-pad-md);
    display: flex;
    flex-direction: column;
    gap: var(--gap-2xs);
    flex: 1;
}
.article-card__cat {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--mint-dark, #1a9270);
}
/* ── card-title canon (shipped V2 hover, 2026-05-12) ──────────────────────
   Single hover treatment shared across all card types: invisible underline at
   rest (transparent), switches to mint-dark + title text color shifts navy →
   mint-dark on parent :hover. No fade transition (immediate). Each title keeps
   its own font-size set by its component rule.

   Rationale: prior canon used a fade transition + mint underline; was too
   subtle on .hub-featured-card. V2 chose immediate switch + mint-dark for
   higher contrast. See git log + (now-deleted) /card-hover-mockup/ for the
   three variants compared.

   .school-card__name-text and .sc-img__name-text are inner spans on the title
   H3s in those partials; using them lets multi-line titles wrap with per-line
   underlines via box-decoration-break: clone (set on those spans elsewhere). */
.article-card__title,
.hub-featured-card__title,
.hub-article-row__title,
.cat-article-row__title,
.event-archive-card__title,
.school-card__name-text,
.sc-img__name-text,
.sc-row__name,
.ranking-row__title {
    color: var(--navy);
    text-decoration: underline;
    text-decoration-color: transparent;
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}
.article-card__title,
.hub-featured-card__title,
.event-archive-card__title {
    font-weight: 700;
    line-height: 1.3;
    margin: 0;
}
.article-card__title,
.hub-featured-card__title { font-size: 1.0625rem; }
.event-archive-card__title { font-size: 1.25rem; }
.article-card:hover .article-card__title,
.hub-featured-card:hover .hub-featured-card__title,
.event-archive-card:hover .event-archive-card__title,
.school-card:hover .school-card__name-text,
.sc-img:hover .sc-img__name-text,
.sc-row:hover .sc-row__name,
.hub-article-row:hover .hub-article-row__title,
.hub-article-row:hover .hub-featured-card__title,
.cat-article-row:hover .cat-article-row__title,
.ranking-row:hover .ranking-row__title {
    text-decoration-color: var(--mint-dark);
    color: var(--mint-dark);
}
.article-card__date {
    font-size: .8125rem;
    color: var(--text-muted);
    margin-top: auto;
}

/* ─── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
    .article-header { padding: 32px 0 24px; }
    .article-title  { font-size: 1.625rem; }

    .article-hero__img,
    .article-hero img { height: 260px; }

    /* On mobile: dissolve the article-sidebar wrapper so children
       participate in the parent grid directly. This lets the CTA stay
       above content (order: -1) while the cross-content widgets fall
       below content (order: 1). */
    .article-sidebar {
        display: contents;
    }
    /* CTA card stays above the article body — converts mobile readers
       before they decide to scroll. Switches to horizontal flex strip. */
    .article-cta-card {
        order: -1;
        margin-bottom: 32px;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 16px;
        padding: 20px;
    }
    /* Cross-content sidebar widgets fall below the article body on mobile.
       First widget gets a top margin so it doesn't bump into article body. */
    .detail-layout > .cat-side-section {
        order: 1;
    }
    .detail-layout > .cat-side-section:first-of-type {
        margin-top: 32px;
    }
    .article-cta-card__eyebrow { display: none; }
    .article-cta-card__headline { font-size: 1rem; margin: 0; flex: 1; min-width: 200px; }
    .article-cta-card__body     { display: none; }
    .article-cta-card .btn--block {
        width: auto;
        flex-shrink: 0;
        padding: 12px 20px;
        font-size: .875rem;
    }

    .article-cta-banner__inner  {
        flex-direction: column;
        align-items: flex-start;
        gap: 20px;
    }
    .article-cta-banner .btn--block { width: 100%; justify-content: center; }
}

/* ─── Sidebar widgets ────────────────────────────────────────────────────── */
.sidebar-widget {
    background: var(--bg);
    border: 1px solid var(--border);
    padding: var(--card-pad-md);
    margin-top: var(--gap-sm);
}
.sidebar-widget__title {
    /* Uses .heading-card spec (1.0625rem · weight 700 · navy · mixed case)
       paired with .surface--accent-top on the parent widget for visual identity. */
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.3;
    margin: 0 0 var(--gap-md);
}

/* (.popular-list canonical block lives further down — see the cat-archive
   section. The duplicate definition that used to live here was producing
   a stuck "0." counter from a stale counter-reset.) */

/* ─── Essay analysis articles ──────────────────────────────────────────────── */

/* Full essay card — Group block with additional CSS class "essay-full" via block pattern.
   Body text in Crimson Pro (humanist serif) to give English essay content a
   distinct typographic voice from the surrounding Vietnamese commentary.
   Kicker label stays in Be Vietnam Pro for UI consistency. */
.essay-full {
    background: #fff;
    border: 1px solid rgba(13,40,64,.14);
    padding: 32px 40px;
    margin: 32px 0;
    box-shadow: 0 1px 6px rgba(0,0,0,.06);
}
.essay-full .essay-full__label {
    font-family: "Be Vietnam Pro", sans-serif;
    font-size: .6875rem;
    font-weight: 800;
    letter-spacing: .1em;
    color: var(--mint);
    margin: 0 0 24px;
    text-transform: uppercase;
}
.essay-full p:not(.essay-full__label) {
    font-family: "Crimson Pro", "Georgia", serif;
    font-size: 1.1875rem;     /* 19px */
    line-height: 1.65;
    color: #2a3c4a;
    margin: 0 0 1.1em;
    letter-spacing: .003em;
    font-weight: 400;
}
.essay-full p:last-child { margin-bottom: 0; }
.essay-full em {
    font-family: "Crimson Pro", serif;
    font-style: italic;
}
.essay-full strong {
    font-family: "Crimson Pro", serif;
    font-weight: 600;
    color: var(--navy);
}

/* Essay quote snippet — Quote block with "Essay Quote" block style.
   "Variant C" — white card with thin border + mint left accent rail, soft
   shadow. Crimson Pro text (matches essay-full) so reader recognizes both
   as the same English-essay typographic voice. No italic — clean, confident. */
.wp-block-quote.is-style-essay-quote {
    background: #fff;
    border: 1px solid var(--overlay-navy-faint);
    border-left: 3px solid var(--mint);
    padding: 16px 22px;
    margin: 24px 0;
    box-shadow: 0 1px 3px rgba(13,40,64,.04);
    font-style: normal;
}
.wp-block-quote.is-style-essay-quote p {
    font-family: "Crimson Pro", "Georgia", serif;
    font-size: 1.0625rem;     /* 17px */
    color: #2a3c4a;
    line-height: 1.55;
    margin: 0;
    font-weight: 400;
    font-style: normal;
}
.wp-block-quote.is-style-essay-quote cite { display: none; }

/* Article hero placeholder */
.article-hero--placeholder {
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
    height: 320px;
}
.article-hero__placeholder-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    color: var(--text-muted);
    font-size: .875rem;
}

/* Article card image placeholder */
.article-card__img--placeholder {
    background: var(--surface);
    aspect-ratio: 16/9;
}

/* ─── Prose list improvements ────────────────────────────────────────────── */
.prose ul,
.prose ol {
    margin: 0 0 1.25em;
}
.prose ul {
    list-style: none;
    padding-left: 0;
}
.prose ul li {
    padding-left: 1.25em;
    position: relative;
    margin-bottom: .6em;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1.75;
}
.prose ul li:last-child { margin-bottom: 0; }
.prose ul li::before {
    content: '';
    position: absolute;
    left: 0;
    top: .65em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--mint);
}
.prose ol {
    padding-left: 1.75em;
    counter-reset: prose-ol;
    list-style: none;
}
.prose ol li {
    counter-increment: prose-ol;
    padding-left: .25em;
    position: relative;
    margin-bottom: .6em;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1.75;
}
.prose ol li:last-child { margin-bottom: 0; }
.prose ol li::before {
    content: counter(prose-ol) ".";
    position: absolute;
    left: -1.75em;
    font-weight: 700;
    color: var(--navy);
    font-size: 1rem;
}

/* ─── Overline — for sequential/series section headings ─────────────────── */
/*
 * Use: add a paragraph with class "overline" immediately before an h2/h3.
 * Best for: numbered steps (Giai đoạn 1/2/3), named series, structured guides.
 * Do NOT use for decorative labeling — only when the content is genuinely sequential.
 */
/* Prose-context overline — when authors put an .overline before a heading
   inside .prose long-form content, give it a clear "section break" rhythm:
   big top margin (separating from prior paragraph), small gap to the
   heading below. Scoped to .prose so it doesn't override the canonical
   .overline + .section-header__overline rules used outside prose. */
.prose .overline {
    margin: 2em 0 .25em;
}
.prose .overline + h2,
.prose .overline + h3 {
    margin-top: 0;
}

/* ─── Mobile sidebar: hide popular widget, show compact CTA only ─────────── */
@media (max-width: 768px) {
    .sidebar-widget { display: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   ARTICLES HUB — /bai-viet/
   Hero band + mint-underlined section titles + clean white throughout +
   whole-row hover article rows + text-row directory.
   ═══════════════════════════════════════════════════════════════════════════ */

.hub-page { background: #fff; }

/* Hero band — same pattern as .rankings-hero (navy gradient, mint crumb,
   on-dark seg-toggle for level switcher). */
.hub-header {
    background: linear-gradient(135deg, #0D2840 0%, #1a3a55 100%);
    color: #fff;
    padding: 48px 0 40px;
}
.hub-header__inner { max-width: var(--container-sm); }
.hub-header .overline {
    color: var(--overlay-mint-strong);
    margin: 0 0 12px;
}
.hub-header__title {
    font-size: clamp(1.75rem, 3.5vw, 2.5rem);
    font-weight: 800;
    color: #fff;
    line-height: 1.2;
    letter-spacing: -.02em;
    margin: 0 0 14px;
}
.hub-header__sub {
    color: rgba(255,255,255,.8);
    font-size: 1rem;
    line-height: 1.6;
    max-width: 680px;
    margin: 0 0 22px;
}

/* Section header row — title left, optional action link right. */
.hub-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 18px;
}

/* ─── Featured / Bắt đầu từ đây ─────────────────────────────────────────── */
.hub-featured {
    padding: var(--section-md) 0 var(--section-sm);
}
.hub-featured__grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    gap: 14px;
}
.hub-featured-card {
    display: block;
    background: #fff;
    border: 1px solid var(--border);
    color: var(--navy);
    text-decoration: none;
    transition: transform .15s, box-shadow .15s;
}
/* .hub-featured-card:hover lift+shadow retired 2026-05-16. */
.hub-featured-card__img {
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--surface);
}
.hub-featured-card__img--placeholder {
    background: linear-gradient(135deg, #0D2840 0%, #1a4d38 100%);
    opacity: .85;
}
.hub-featured-card__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hub-featured-card--primary .hub-featured-card__img { aspect-ratio: 16 / 10; }
.hub-featured-card__body {
    padding: 14px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.hub-featured-card__cat {
    font-size: .6875rem;
    font-weight: 800;
    color: var(--mint-dark, #1a9270);
    text-transform: uppercase;
    letter-spacing: .08em;
    display: block;
}
.hub-featured-card__title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.35;
    margin: 0;
}
.hub-featured-card--primary .hub-featured-card__title { font-size: 1.25rem; }
.hub-featured-card__date {
    /* Matches .ranking-row__loc (.8125rem) so the meta typography under
       row titles reads consistent across article rows + ranking rows. */
    font-size: .8125rem;
    color: var(--text-light, var(--text-muted));
}

/* ─── Category sections ──────────────────────────────────────────────────── */
.hub-category {
    padding: var(--section-sm) 0;
}
.hub-category + .hub-category { padding-top: 0; }
.hub-category__count { /* legacy — count now lives inside the action link */ display: none; }

/* Article row — used in hub category sections AND on the cat archive page.
   Stable geometry: rows always have horizontal padding; the parent .hub-rows
   uses negative margin so hover bg fills past the content edge without
   shifting layout. */
.hub-rows {
    display: flex;
    flex-direction: column;
    margin: 0 -16px;
}
.hub-article-row {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 16px;
    align-items: center;
    padding: 16px;
    color: var(--navy);
    text-decoration: none;
    transition: background var(--ease-fast);
}
/* Row hover canon: title underline only — no bg-change. Title underline
   on hover comes from the shared card-title canon (search "card-title
   canon"). (Removed `background: var(--surface)` on hover 2026-05-12.) */
.hub-article-row__img {
    width: 110px;
    height: 78px;
    flex-shrink: 0;
    overflow: hidden;
    background: var(--surface);
}
.hub-article-row__img--placeholder {
    background: linear-gradient(135deg, #0D2840 0%, #1a4d38 100%);
    opacity: .85;
}
.hub-article-row__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hub-article-row__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.hub-article-row__title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.35;
    margin: 0;
}
.hub-article-row__excerpt {
    font-size: .875rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.hub-article-row__date { font-size: .75rem; color: var(--text-light, var(--text-muted)); }

/* ─── All topics directory ───────────────────────────────────────────────── */
.hub-directory {
    padding: var(--section-sm) 0 var(--section-md);
}
.hub-directory__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 28px;
}
.hub-dir-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
    color: var(--navy);
    text-decoration: none;
    transition: color var(--ease-fast), padding var(--ease-fast);
}
.hub-dir-link:hover { color: var(--mint-dark); padding-left: 8px; }
.hub-dir-link__label { font-size: .9375rem; font-weight: 600; }
.hub-dir-link__count { font-size: .75rem; color: var(--text-muted); font-weight: 600; }

/* ─── Hub responsive ─────────────────────────────────────────────────────── */
@media (max-width: 900px) {
    .hub-featured__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 600px) {
    .hub-header { padding: 32px 0 28px; }
    .hub-featured { padding: 32px 0 24px; }
    .hub-featured__grid { grid-template-columns: 1fr; }
    .hub-category { padding: 24px 0; }
    .hub-directory__grid { grid-template-columns: 1fr; }
    .hub-article-row {
        grid-template-columns: 80px 1fr;
        gap: 12px;
        padding: 14px 16px;
    }
    .hub-article-row__img { width: 80px; height: 56px; }
    .hub-article-row__title { font-size: .9375rem; }
    .hub-article-row__excerpt { -webkit-line-clamp: 1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CATEGORY ARCHIVE — /chu-de/{slug}/
   Same hero band + mint-underlined section title + whole-row hover articles +
   clean text-row sidebar widgets (no card chrome).
   ═══════════════════════════════════════════════════════════════════════════ */

.cat-page { background: #fff; }

/* Hero band — mirrors .hub-header / .rankings-hero */
.cat-header {
    background: linear-gradient(135deg, #0D2840 0%, #1a3a55 100%);
    color: #fff;
    padding: 48px 0 40px;
}
.cat-back-wrap {
    margin: 0 0 12px;
    font-size: .75rem;
    line-height: 1;
}
.cat-back {
    /* link-action--back canonical handles arrow animation; we tune color +
       typography for the dark hero bg here. */
    color: var(--overlay-mint-strong);
    font-size: inherit;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
}
.cat-back:hover { color: var(--mint); }
.cat-header__title {
    font-size: clamp(1.75rem, 3.5vw, 2.5rem);
    font-weight: 800;
    color: #fff;
    line-height: 1.2;
    letter-spacing: -.02em;
    margin: 0 0 12px;
}
.cat-header__meta {
    color: rgba(255,255,255,.7);
    font-size: .875rem;
    margin: 0;
}
.cat-header__tabs { margin-top: 18px; }

/* Page-level vertical padding for category pages (canonical .detail-layout
   doesn't own padding; consumers do). */
.cat-page { padding: var(--section-md) 0; }

/* Article list — reuses hub article-row pattern. .cat-list is the wrapper
   so the negative margin doesn't double up if the hub class moves. */
.cat-list {
    display: flex;
    flex-direction: column;
    /* Negative-margin only on the left — the right side now respects the
       column edge so the gap to the sidebar reads at full --gap-xl (48px).
       (Left-margin extension preserved so the row aligns visually with
       the section header above, which itself has 0 left-padding.) */
    margin: 0 0 0 -16px;
}
.cat-article-row {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 16px;
    align-items: center;
    padding: 20px 16px;
    color: var(--navy);
    text-decoration: none;
    transition: background var(--ease-fast);
}
/* Row hover canon (unified-row-hover, 2026-05-12): title underline only, no
   bg-change. Aligns with .sc-row + .hub-article-row + .ranking-row. */
.cat-article-row__img {
    width: 110px;
    height: 78px;
    flex-shrink: 0;
    overflow: hidden;
    background: var(--surface);
}
.cat-article-row__img--placeholder {
    background: linear-gradient(135deg, #0D2840 0%, #1a4d38 100%);
    opacity: .85;
}
.cat-article-row__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cat-article-row__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cat-article-row__title {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--navy);
    line-height: 1.35;
    margin: 0;
}
.cat-article-row__excerpt {
    font-size: .875rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.cat-article-row__date { font-size: .75rem; color: var(--text-light, var(--text-muted)); }

/* Sidebar — clean text-row widgets, no card chrome. */
.cat-side-section { margin-bottom: 32px; }
.cat-side-section:last-child { margin-bottom: 0; }

/* Category nav rows — text rows with hover bg + active mint-light state.
   Stable geometry: parent has negative margin, items keep symmetric padding. */
.cat-nav {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.cat-nav__item { /* legacy wrapper — items style their <a> directly now */ }
.cat-nav__item a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 0;
    color: var(--navy);
    text-decoration: none;
    font-size: .875rem;
    transition: color var(--ease-fast);
}
.cat-nav__label {
    font-weight: 600;
    border-bottom: 1px solid transparent;
    transition: border-color var(--ease-fast), color var(--ease-fast);
    padding-bottom: 1px;
}
.cat-nav__item a:hover .cat-nav__label {
    border-bottom-color: var(--mint-dark);
}
.cat-nav__count {
    font-size: .75rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--surface);
    padding: 1px 8px;
    flex-shrink: 0;
}
.cat-nav__item--active .cat-nav__label {
    color: var(--mint-dark);
    border-bottom-color: var(--mint-dark);
    font-weight: 700;
}

/* Popular articles list — numbered counter + clean text rows. */
.popular-list {
    list-style: none;
    padding: 0 10px;
    margin: 0 -10px;
    counter-reset: pop;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.popular-list__item {
    counter-increment: pop;
    list-style: none;
}
.popular-list__link {
    display: flex;
    gap: 10px;
    color: var(--navy);
    text-decoration: none;
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1.4;
    transition: color var(--ease-fast);
}
.popular-list__link::before {
    content: counter(pop);
    flex-shrink: 0;
    font-size: 1rem;
    font-weight: 800;
    color: var(--text-muted);
    width: 18px;
    line-height: 1.4;
}
.popular-list__link:hover { color: var(--mint-dark); }

/* Bullet variant — for chronological / unranked lists where the counter
   would imply ranking. Used by the recently-viewed-schools widget. */
.popular-list--bullets .popular-list__link::before {
    content: "•";
    font-size: 1rem;
    width: 12px;
    text-align: left;
}

/* "Xem tất cả →" footer link on sidebar widgets that wrap popular-list.
   Tight margin to feel like a footer of the list, not a new section. */
.cat-side-section__see-all {
    margin: 14px 0 0;
    font-size: .8125rem;
}
.cat-side-section__see-all a {
    color: var(--mint-dark);
    text-decoration: none;
    font-weight: 700;
    border-bottom: 1px solid transparent;
    transition: border-color var(--ease-fast);
}
.cat-side-section__see-all a:hover {
    border-bottom-color: var(--mint-dark);
}

/* (.cat-empty — uses canonical .state-empty styles from top of stylesheet.) */

/* Pagination */
.cat-pagination {
    margin-top: 40px;
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}
.cat-pagination .page-numbers {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding: 0 10px;
    font-size: .875rem;
    font-weight: 600;
    color: var(--navy);
    text-decoration: none;
    border: 1px solid var(--border);
    transition: background .15s, border-color .15s;
}
.cat-pagination .page-numbers:hover { background: var(--surface); }
.cat-pagination .page-numbers.current {
    background: var(--navy);
    color: #fff;
    border-color: var(--navy);
}
.cat-pagination .page-numbers.dots { border: none; }

/* ── Category responsive ───────────────────────────────────────────────────── */
@media (max-width: 900px) {
    .cat-page { padding: 32px 0 48px; }
}
@media (max-width: 600px) {
    .cat-header { padding: 32px 0 28px; }
    .cat-article-row {
        grid-template-columns: 80px 1fr;
        gap: 12px;
        padding: 14px 16px;
    }
    .cat-article-row__img { width: 80px; height: 56px; }
    .cat-article-row__title { font-size: .9375rem; }
    .cat-article-row__excerpt { -webkit-line-clamp: 1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * Event registration form (page-form-preview.php and future campaign pages)
 * Modern, completion-encouraging, mobile-first single-column.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── Preview chrome (only on /form-preview/, harmless on real pages) ────── */
.form-preview__chrome {
    background: #0a0a0a;
    color: rgba(255,255,255,.6);
    padding: 10px 0;
    font-size: .75rem;
    font-family: 'Courier New', monospace;
}
.form-preview__chrome-inner {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.form-preview__chrome-label {
    color: var(--mint);
    border: 1px solid var(--mint);
    padding: 2px 8px;
    font-weight: 700;
    letter-spacing: .15em;
}
.form-preview__chrome-meta code {
    background: rgba(255,255,255,.08);
    padding: 1px 6px;
    color: #fff;
}
.form-preview__chrome-switch { margin-left: auto; display: flex; gap: 8px; }
.form-preview__chrome-switch a {
    color: rgba(255,255,255,.5);
    border: 1px solid rgba(255,255,255,.15);
    padding: 2px 10px;
    text-decoration: none;
}
.form-preview__chrome-switch a.is-active {
    color: var(--mint);
    border-color: var(--mint);
}

/* ── Hero (form preview placeholder; real campaign hero will come later) ── */
/* Bg, padding, title, subtitle all from canonical .page-header--navy at top.
   Padding tokenized: --section-md 0 --section-lg (was hardcoded 64/80). */
.event-hero {
    padding: var(--section-md) 0 var(--section-lg);
}
.event-hero__title {
    max-width: var(--measure-sm);
}
.event-hero__subtitle {
    max-width: var(--measure-lg);  /* 56ch */
}
.event-hero__cities {
    color: var(--mint);
    font-size: .9375rem;
    font-weight: 600;
    margin-top: 24px;
    letter-spacing: .02em;
}
.event-hero__cta { margin-top: 32px; }

/* ── Form section wrapper ──────────────────────────────────────────────── */
.event-form-section {
    padding: var(--section-md) 0 var(--section-lg);
    /* Min-height ensures the section + content below the city bar always has
       enough runway for scrollIntoView to land the city bar at the top of
       viewport, regardless of how short the active step is. The empty space
       sits OUTSIDE the form box (between form and footer), invisible. */
    min-height: 100vh;
}
/* The shared page-header grouped selector gives __header its own
   var(--section-md) top padding — but the section wrapper above already
   provides that. Zero out the header's top padding so the title isn't
   double-spaced from the section top. */
.event-form-section .event-form-section__header { padding-top: 0; }
.event-form { scroll-margin-top: var(--nav-height, 68px); }

.event-form {
    max-width: var(--container-sm);
    margin: 0 auto;
    background: #fff;
    box-shadow: var(--shadow-md);
    border: 1px solid var(--border);
    padding: 0;
}
/* Inside .form-with-sidebar (or any 2-col grid), the column constrains
   width — drop the panel's max-width so it fills the column consistently
   regardless of step content. */
.form-with-sidebar .event-form {
    max-width: none;
    margin: 0;
}

/* Navy header bar at top of the form panel. Visible on every step,
   doubles as the scrollIntoView target on showStep() so users always
   land at the form's chrome on advance (no jumping around). */
.event-form__bar {
    background: var(--navy);
    color: #fff;
    padding: 14px 20px;
    margin: 0;
}
.event-form__bar-title {
    margin: 0;
    color: #fff;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* (.event-form__city-bar / __city-compact / __city-expanded / __city-tab /
   __city-meta-* — all retired. City picker is now Step 1 of the form
   itself, using canonical .form-cards / .form-card markup.) */

/* When .form-cards is used for the city step (3+ options that don't pack
   evenly into the canonical 2-column layout), stack to 1 column so each
   city card has room for date + time + venue. Bespoke override; if a
   second 3+ option group needs the same shape we'll promote to a
   canonical .form-cards--stack modifier. */
.form-cards--cities {
    grid-template-columns: 1fr;
}

/* (.event-form__steps + .event-form__step-pill — replaced by canonical
   .form-progress at the top of style.css. JS now updates step number/name
   text in the indicator on every showStep().) */

/* ── Step content ──────────────────────────────────────────────────────── */
/* Step containers — display only; field/label/input styling now lives in
   the canonical .form-* system at the top of style.css. */
/* Form chrome — horizontal padding lives on the form so the progress dots
   share it with the step content (no jog when steps swap). */
.event-form__form { padding: 20px 32px 32px; }
.event-form__step { border: none; padding: 0; }
.event-form__step-hint {
    color: var(--text-light);
    font-size: .8125rem;
    margin-top: 12px;
}

/* (.event-form__step-title, .event-form__step-sub — replaced by canonical
   .form-step-title / .form-step-sub.)
   (.role-cards, .role-card, .role-card__inner/__title/__sub — replaced by
   canonical .form-cards / .form-card / .form-card__title / .form-card__sub.)
   (.event-form__field, .event-form__label, .event-form__input + states,
   .event-form__hint, .event-form__error, .event-form__radio-row,
   .radio-pill, .check-pill — all replaced by canonical .form-* equivalents.) */

/* "Shared" input state — used by the guest sub-form when a parent ticks
   "trẻ không có email/SĐT riêng — dùng email/SĐT của tôi" and the field
   becomes locked to the parent's value. Specific to the event form's
   guest-sharing flow; not a generic state worth promoting to canon. */
.form-input.is-shared {
    background: var(--mint-light);
    color: var(--mint-dark);
    cursor: not-allowed;
}

/* VN-school autocomplete dropdown — typeahead under the school field */
.event-form__autocomplete {
    position: relative;
}
.event-form__autocomplete-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    margin-top: 4px;
    background: #fff;
    border: 1px solid var(--border);
    box-shadow: 0 4px 16px rgba(13,40,64,.08);
    max-height: 280px;
    overflow-y: auto;
}
.event-form__autocomplete-item {
    padding: 10px 14px;
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.event-form__autocomplete-item:last-child { border-bottom: none; }
.event-form__autocomplete-item:hover,
.event-form__autocomplete-item.is-focus {
    background: var(--surface);
}
.event-form__autocomplete-name {
    font-weight: 600;
    color: var(--navy);
    font-size: .9375rem;
    line-height: 1.3;
}
.event-form__autocomplete-meta {
    font-size: .8125rem;
    color: var(--text-muted);
}

/* (.event-form__input:disabled, .event-form__hint, .event-form__error,
   .event-form__radio-row, .event-form__check-grid (unused),
   .radio-pill, .check-pill (unused) — all replaced by canonical
   .form-input:disabled, .form-hint, .form-error, .form-pillrow,
   .form-pill at the top of style.css.)
   .event-form__input.is-shared (and the .form-input.is-shared rule above
   in the autocomplete section) is the only state genuinely specific to
   the event form's guest-sharing flow. */

/* ── Step 3: guests ────────────────────────────────────────────────────── */
/* Cleaner card styling: 1px border (matches canonical), tighter rhythm,
   subtle mint left-edge accent for saved/collapsed state instead of full
   mint-light fill. No border between body and foot — buttons read as
   distinct on their own. */
.event-form__guest-list { margin-bottom: 16px; }
.event-form__guest-card {
    border: 1px solid var(--border);
    margin-bottom: 12px;
    background: #fff;
    transition: border-color .15s, box-shadow .15s;
}
.event-form__guest-card.is-collapsed {
    border-color: var(--mint);
    box-shadow: inset 3px 0 0 var(--mint);
    background: #fff;
    cursor: default;
}
.event-form__guest-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 18px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.event-form__guest-card.is-collapsed .event-form__guest-card-head {
    background: transparent;
    border-bottom: none;
}
.event-form__guest-card-title {
    font-size: .8125rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0;
}
.event-form__guest-remove {
    background: transparent;
    border: none;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--text-light);
    padding: 0 4px;
    transition: color .15s;
}
.event-form__guest-remove:hover { color: var(--danger); }
.event-form__guest-card-body {
    padding: 18px;
}
.event-form__guest-card-foot {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 16px;
}
.event-form__share-check {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    cursor: pointer;
    font-size: .875rem;
    color: var(--text-muted);
}
.event-form__share-check[hidden] { display: none; }
/* Custom-styled mint checkbox — matches the canonical .form-check
   rendering so the share-check doesn't show a default browser blue. */
.event-form__share-check input[type="checkbox"] {
    appearance: none; -webkit-appearance: none;
    width: 16px; height: 16px;
    flex-shrink: 0; margin: 0;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 0;
    cursor: pointer;
    position: relative;
    transition: background .12s, border-color .12s;
}
.event-form__share-check input[type="checkbox"]:hover { border-color: var(--navy); }
.event-form__share-check input[type="checkbox"]:checked {
    background: var(--mint);
    border-color: var(--mint);
}
.event-form__share-check input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    top: 1px; left: 4px;
    width: 4px; height: 8px;
    border: solid var(--navy);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.event-form__share-check input[type="checkbox"]:focus-visible {
    outline: var(--focus-outline); outline-offset: var(--focus-offset);
}
.event-form__guest-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
}
.event-form__guest-summary[hidden] { display: none; }
.event-form__guest-summary-line {
    margin: 0;
    color: var(--navy);
    font-size: .9375rem;
}
.event-form__guest-edit {
    background: transparent;
    border: 1px solid var(--mint);
    color: var(--mint-dark);
    cursor: pointer;
    padding: 4px 10px;
    font-family: var(--font);
    font-size: .8125rem;
    font-weight: 600;
}
.event-form__guest-edit:hover { background: var(--mint); color: var(--navy); }

/* (.event-form__add-guest — replaced by canonical .btn .btn--outline
   .btn--block. The bespoke dashed-border + mint-plus-tile pattern was
   visually distinctive but didn't cohere with the rest of the form.) */

/* (.event-form__review-* and .event-form__review — replaced by canonical
   .form-review family near the top of style.css. Both event and volunteer
   forms now use it via --blocks and --flat modifiers respectively.) */

/* ── Consent + submit ──────────────────────────────────────────────────── */
/* (.event-form__consent — replaced by canonical .form-check.form-check--consent
   at the top of style.css.)
   (.event-form__nav — replaced by canonical .form-nav.) */

/* Submit button — disabled state visible when consent isn't checked */
.event-form__submit:disabled {
    opacity: .5;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

/* ── Confirmation page wrapper · provides padding around the canonical
   .form-confirm content. The form-confirm internals live near the top of
   style.css with the rest of the .form-* canon. */
.event-form__confirmation {
    padding: 40px 28px 48px;
}
/* (All bespoke .event-form__confirm-* classes — confirm-check, confirm-
   title, confirm-greeting, confirm-card, confirm-meta, confirm-section,
   confirm-agenda, confirm-bring, confirm-email-note — replaced by the
   canonical .form-confirm family. Same for the bespoke .volunteer-confirm__
   interviewer-buttons stack which is now .form-confirm__cta-stack.) */

/* Back-button two-affordance pattern · canonical
   Back buttons on the submit step have BOTH a "← Quay lại" label span and
   a chevron-only icon span. Default: show the label, hide the icon. On
   mobile (≤600px) the label is hidden and the icon shows in its place —
   gives the long submit button enough horizontal room to not wrap. */
.event-form__back-icon { display: none; }

/* ── Responsive tweaks ─────────────────────────────────────────────────── */
@media (max-width: 600px) {
    .event-form { box-shadow: none; border-left: none; border-right: none; }
    .event-form__city-select { padding: 24px 20px 22px; }
    .event-form__form { padding: 16px 20px 28px; }
    .event-form__confirmation { padding: 32px 20px; }
    /* On the submit step (step 5 of event form, step 4 of volunteer form),
       hide the Back button's label and show its chevron icon instead. */
    .event-form__step[data-step="5"] [data-action="back"] .event-form__back-label,
    .event-form__step[data-step="4"] [data-action="back"] .event-form__back-label {
        display: none;
    }
    .event-form__step[data-step="5"] [data-action="back"] .event-form__back-icon,
    .event-form__step[data-step="4"] [data-action="back"] .event-form__back-icon {
        display: inline;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * Event campaign page (page-event-campaign.php)
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── Hero — bg/padding/title/subtitle from canonical .page-header--photo at top ── */
.campaign-hero__bg {
    position: absolute; inset: 0;
    background-size: cover;
    background-position: center;
    opacity: .35;
}
.campaign-hero__overlay {
    position: absolute; inset: 0;
    background: linear-gradient(180deg, var(--overlay-navy-light) 0%, rgba(13,40,64,.85) 100%);
}
.campaign-hero__inner {
    position: relative;
    z-index: 2;
}
.campaign-hero__title {
    /* font-size + color from canonical; just keep max-width for line-break control */
    max-width: var(--measure-sm);  /* 18ch */
}
.campaign-hero__subtitle {
    /* font-size + color from canonical; just keep max-width */
    max-width: var(--measure-lg);  /* 56ch */
}
/* (.campaign-hero__cta margin-top removed — the CTA is now in its own
   grid cell, so the row gap handles spacing. Leaving the old margin
   would double-up against the gap on mobile.) */

/* ── Hero split · 3-area grid (copy / card / cta) ─────────────────────
   Three siblings, not two — copy (top-left), card (full-height right),
   CTA (bottom-left). On mobile they stack as copy → card → cta so the
   user sees the event info before being asked to register. .layout-2col
   doesn't cover this 3-area pattern so we use a bespoke grid here.
*/
.campaign-hero__split {
    display: grid;
    grid-template-columns: 3fr 2fr;
    grid-template-areas:
        "copy card"
        "cta  card";
    gap: var(--gap-md) var(--gap-lg);
    align-items: start;
}
.campaign-hero__copy     { grid-area: copy; }
.campaign-hero__event-card {
    grid-area: card;
    /* Center vertically within the right column's available height
       (which spans both grid rows = copy height + gap + cta height).
       Gives the card breathing room above when the left column is
       shorter than the card. */
    align-self: center;
}
.campaign-hero__cta-wrap { grid-area: cta; }

@media (max-width: 720px) {
    .campaign-hero__split {
        grid-template-columns: 1fr;
        grid-template-areas:
            "copy"
            "card"
            "cta";
    }
    /* Full-width CTA on mobile — bigger tap target. */
    .campaign-hero__cta { display: flex; width: 100%; justify-content: center; }
    /* (Meta-row mobile overrides live AFTER the base rules below, otherwise
       source-order would let the base rules override them.) */
}

/* Right-side event-info card — translucent navy panel that inhabits the
   hero color family. Stacked metadata layout: small mint label on top,
   bold white value below. No icons (typography carries it). */
.campaign-hero__event-card {
    padding: 18px 22px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    color: #fff;
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.12);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* Hero city tabs use canonical .seg-toggle.seg-toggle--sm.seg-toggle--on-dark.
   The card is display:flex column → align-items defaults to stretch, which
   would force the toggle to full-card-width. Center it so it sizes to
   content while sitting in the middle of the card. */
.campaign-hero__event-card .seg-toggle { align-self: center; }

.campaign-hero__event-meta {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    /* Reserve enough vertical room to fit a 2-line venue so the card
       doesn't change size when user clicks a different city tab. */
    min-height: 150px;
}
.campaign-hero__event-meta-row {
    padding: 12px 0;
    border-top: 1px solid rgba(255,255,255,.12);
}
.campaign-hero__event-meta-row:first-child { border-top: none; padding-top: 0; }
.campaign-hero__event-meta-label {
    display: block;
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--mint);
    margin: 0 0 3px;
}
.campaign-hero__event-meta-value {
    display: block;
    font-size: .9375rem;
    color: #fff;
    line-height: 1.4;
    font-weight: 600;
}

/* (Locked state for the campaign hero city tabs is now handled by
   .seg-toggle.is-locked in the canonical seg-toggle block above.) */

/* (.campaign-body, .campaign-body__content — retired. The free-text rich
   editor field on the campaign meta box has been removed in favor of
   constrained .feature-card highlights only.) */

/* Campaign section heading row spacing — title styling is the canonical
   .section-title-mint (see top of file); this just sets the gap below
   the header row on event-detail / volunteer / about sections. */
.campaign-section-head { margin-bottom: 24px; }

/* ── Highlights · numbered list (newspaper style) ─────────────────────
   Each item: thick navy top-rule + large mint counter (01, 02, 03…) +
   heading + description. No card chrome, no icons. Section sits on
   surface bg per Brett's call. */
.campaign-highlights-section {
    padding: var(--section-md) 0;
}
.campaign-highlights-section__title { margin-bottom: 32px; }

.campaign-highlights-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
}
/* 4-col variant — used on volunteer page where there are exactly 4 cards */
.campaign-highlights-grid--4col { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
    .campaign-highlights-grid--4col { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
    .campaign-highlights-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    .campaign-highlights-grid,
    .campaign-highlights-grid--4col { grid-template-columns: 1fr; }
}

/* Highlight card · V2 chrome (border + 1px lift + box-shadow on hover).
   Mint icon badge at the top, heading + description below. Informational
   <div> (not clickable) — no title underline canon needed.
   TODO: meta-box currently has no icon picker — icons cycle by position
   from a default set in single-event_campaign.php. Future enhancement:
   extend the meta box with an icon field so editors can choose. */
.campaign-highlight {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 22px;
    transition: transform .15s, box-shadow .15s;
}
/* .campaign-highlight:hover lift+shadow retired 2026-05-16. */
.campaign-highlight__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: var(--mint-light);
    color: var(--mint-dark);
    margin-bottom: 14px;
}
.campaign-highlight__icon svg { width: 18px; height: 18px; }
.campaign-highlight__heading {
    font-size: 1rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0 0 8px;
    line-height: 1.3;
}
.campaign-highlight__description {
    font-size: .875rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 0;
}

/* ── Tọa đàm (Panel) section ──────────────────────────────────────────
   Section chrome only — section header uses canonical .section-header,
   panelists use canonical .person-card inside a 3-col grid. */
.campaign-panel {
    padding: var(--section-md) 0;
}
/* Small eyebrow above the panel title that provides the "Tọa đàm" context
   label (canonical .overline--sm.overline--muted). Sits with a tight gap
   so it reads as a kicker on the H2 below it. */
.campaign-panel__eyebrow { margin: 0 0 var(--gap-2xs); }

/* Sponsored-school banner slot between schools list and mid-CTA. Padding
   is tight (--section-xs) — the adjacent sections (schools above, mid-CTA
   below) already provide --section-md padding, so a tighter banner section
   prevents stacked-padding pile-up between content blocks. */
.campaign-sponsor-banner {
    padding: var(--section-xs) 0;
}
.campaign-panel__time {
    color: var(--mint-dark);
    font-weight: 600;
    font-size: 1rem;
    margin: var(--gap-2xs) 0 0;
}
.campaign-panel__description {
    max-width: var(--container-sm);
    margin: 0 0 var(--gap-lg);
    font-size: 1rem;
    color: var(--text);
    line-height: 1.6;
}
/* Margin-only utility class — color comes from .overline--muted canonical. */
.campaign-panel__panelists-label {
    margin: 0 0 var(--gap-xs);
}
.campaign-panel__panelists-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gap-sm);
}
@media (max-width: 720px) { .campaign-panel__panelists-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .campaign-panel__panelists-grid { grid-template-columns: 1fr; } }

/* ── Schools attending ─────────────────────────────────────────────────── */
.campaign-schools {
    padding: var(--section-md) 0;
}
.campaign-schools__featured {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    margin-bottom: var(--gap-md);
}

/* Alphabetical directory — same canonical .sc-img cards as the featured
   row but laid out smaller (4-col desktop), then collapsing to a compact
   text-only list on mobile (the photos would create a runaway scroll). */
.campaign-schools__directory {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--gap-sm);
    margin-top: var(--gap-md);
}
.campaign-schools__directory .sc-img.is-hidden { display: none; }
@media (max-width: 900px) {
    .campaign-schools__directory { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 600px) {
    .campaign-schools__directory { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    /* Mobile: collapse to a single-column compact text list — hide each
       card's photo, drop card chrome, render as flag + name + loc rows
       with a thin divider between. Same .sc-img markup, different shape. */
    .campaign-schools__directory {
        display: flex;
        flex-direction: column;
        gap: 0;
    }
    .campaign-schools__directory .sc-img {
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: var(--gap-sm);
        padding: 12px 0;
        background: transparent;
        /* Strip the .surface family's full border, keep only a thin
           bottom divider so the rows read as a directory list. */
        border: none;
        border-bottom: 1px solid var(--border);
    }
    .campaign-schools__directory .sc-img:last-child { border-bottom: none; }
    .campaign-schools__directory .sc-img__photo { display: none; }
    .campaign-schools__directory .sc-img__body { padding: 0; gap: 2px; }
    .campaign-schools__directory .sc-img__name { font-size: .9375rem; }
    .campaign-schools__directory .sc-img__location { font-size: .8125rem; }
}

/* Wrapper centers the canonical .btn .btn--outline .btn--sm — no bespoke
   button styling here. */
.campaign-schools__show-more-wrap {
    margin-top: 28px;
    text-align: center;
}

/* (.campaign-school-card and .campaign-school-card--featured deleted —
   featured event-campaign cards now use canonical .sc-img pattern.) */

/* ── Gallery strip ─────────────────────────────────────────────────────── */
.campaign-gallery {
    padding: var(--section-md) 0;
}
.campaign-gallery__strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    margin-top: 16px;
}
.campaign-gallery__strip img {
    width: 100%;
    height: 160px;
    object-fit: cover;
}

/* ── Past event video ──────────────────────────────────────────────────── */
.campaign-video {
    padding: var(--section-md) 0;
}
.campaign-video__wrap {
    margin-top: 16px;
    max-width: 800px;
    aspect-ratio: 16 / 9;
}
.campaign-video__wrap iframe,
.campaign-video__wrap video,
.campaign-video__wrap embed {
    width: 100%;
    height: 100%;
}

/* ── Events archive (/su-kien/) ────────────────────────────────────────── */
.event-archive {
    padding: 0 0 var(--section-lg);  /* header has its own --section-md padding */
}
/* .event-archive__header — bg/padding/title/subtitle from canonical
   .page-header--center grouped selectors at top. Title now uses
   canonical clamp(1.75-2.5rem) instead of bespoke clamp(2-2.75). */
.event-archive__header {
    max-width: var(--container-sm);
    margin: 0 auto 40px;
}
.event-archive__title {
    margin: var(--gap-2xs) 0 var(--gap-md);  /* slight overline gap above + space to subtitle */
}
/* (.event-archive__empty — uses canonical .state-empty styles from top of stylesheet.) */
.event-archive__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 24px;
    max-width: 1024px;
    margin: 0 auto;
}
.event-archive-card {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
    overflow: hidden;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
/* .event-archive-card:hover lift+shadow retired 2026-05-16. */
.event-archive-card__media {
    height: 180px;
    background-size: cover;
    background-position: center;
    background-color: var(--surface);
}
.event-archive-card__media--placeholder {
    background: linear-gradient(135deg, var(--navy), #1A3D5C);
}
.event-archive-card__body {
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
}
.event-archive-card__title {
    /* font-size + hover come from the grouped image-led card title rule above */
    margin: 0 0 4px;
}
.event-archive-card__date {
    font-size: .875rem;
    color: var(--text-muted);
    margin: 0;
}
.event-archive-card__cities {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.event-archive-card__cta {
    margin-top: auto;
    padding-top: 14px;
    color: var(--mint-dark);
    font-weight: 600;
    font-size: .9375rem;
}
.event-archive-card__cta-arrow {
    display: inline-block;
    transition: transform var(--ease-base);
}
.event-archive-card:hover .event-archive-card__cta-arrow {
    transform: translateX(3px);
}
@media (max-width: 600px) {
    .event-archive { padding: 48px 0 64px; }
    .event-archive__grid { grid-template-columns: 1fr; }
}

/* ── Volunteer signifier banner (top of TNV page only) ─────────────────
   Slim mint band that sits between the site header and the volunteer
   page hero. Says "you are on the volunteer signup page" so users don't
   confuse this with the regular event signup. Bespoke (one use case);
   promote to canonical .page-banner if a second context appears. */
.volunteer-banner {
    background: var(--mint);
    color: var(--navy);
    padding: 10px 0;
    border-bottom: 1px solid var(--overlay-navy-faint);
}
.volunteer-banner__inner {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px;
    font-size: .8125rem;
    line-height: 1.4;
}
.volunteer-banner__mark {
    color: var(--navy);
    font-weight: 700;
}
.volunteer-banner__label {
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    font-size: .75rem;
}
.volunteer-banner__sep { opacity: .4; }
.volunteer-banner__copy { font-weight: 500; }
@media (max-width: 600px) {
    .volunteer-banner { padding: 8px 0; }
    .volunteer-banner__inner { gap: 6px; font-size: .75rem; }
    .volunteer-banner__sep { display: none; }
    .volunteer-banner__copy { width: 100%; text-align: center; font-size: .75rem; opacity: .85; }
}

/* (Trust bar removed 2026-05-12 — felt like vague filler. Real trust
   signals can integrate near the CTA when needed.) */

/* ── About DHTC section · navy bg, copy left + photo right ────────────
   Composes from canonical primitives: .section--navy, .layout-2col--wide-left,
   .stat-callout--lg --on-dark, .link-inline--on-dark. Bespoke overrides here
   are small: white heading on navy, lead-paragraph styling, photo placeholder. */
.campaign-about__heading {
    color: #fff;
    margin: var(--gap-2xs) 0 var(--gap-md);
}
.campaign-about__lead {
    color: rgba(255,255,255,.85);
    font-size: 1.0625rem;
    line-height: 1.6;
    margin: 0 0 var(--gap-lg);
    max-width: var(--measure-lg);
}
.campaign-about__stats {
    margin: 0;
    /* Override the flex-wrap behavior of .stat-callout-row — with 4
       stats and variable-length labels, flex-wrap produces a staggered
       ladder where each row's items are different widths. Use an
       explicit 2-column grid so the 4 stats sit in a clean 2x2 block. */
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gap-md) var(--gap-xl);
    justify-content: unset;  /* clear inherited flex prop */
}
/* On mobile, stack 1 per row. */
@media (max-width: 720px) {
    .campaign-about__stats { grid-template-columns: 1fr; }
}
/* Team photo frame — 4:3 landscape so it sits compact next to the copy
   column rather than dominating it. Thin subtle border + tiny radius
   reads as "framed photo" against the navy bg. */
.campaign-about__photo {
    aspect-ratio: 4 / 3;
    max-width: 360px;
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 2px;
    overflow: hidden;
}
.campaign-about__photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ── Mid-page CTA (between schools and gallery) ───────────────────────── */
.campaign-midcta {
    background: var(--navy);
    padding: var(--section-md) 0;
    color: #fff;
}
.campaign-midcta__inner { text-align: center; }
.campaign-midcta__heading {
    font-size: clamp(1.5rem, 3vw, 2rem);
    color: #fff;
    margin: 0 0 12px;
}
.campaign-midcta__sub {
    font-size: 1rem;
    color: rgba(255,255,255,.75);
    margin: 0 0 28px;
}
.campaign-midcta__btn {
    width: auto;
}

/* ── Form section heading — bg/title/subtitle from canonical
   .page-header--center at top of stylesheet. */
.event-form-section__header {
    margin-bottom: var(--gap-lg);  /* 32px before form (canonical) */
}

/* (.event-form__city-line + __city-line-change — retired. The "subtle
   inline city confirmation" approach was replaced by making city the
   form's Step 1 — explicit choice up front beats inline confirmation.) */

/* ─── Form with sidebar · canonical layout ─────────────────────────────
   Two-column form layout: form panel on the left, trust/info sidebar
   on the right. Stacks to single column on mobile with the sidebar
   ABOVE the form (so users see reassurance before being asked for
   info). Used on event signup, volunteer signup, future service-tier
   inquiry forms. Pair with .trust-sidebar in the right column.
*/
.form-with-sidebar {
    display: grid;
    grid-template-columns: 3fr 2fr;
    gap: var(--gap-lg);
    align-items: start;
}
@media (max-width: 720px) {
    .form-with-sidebar {
        display: flex;
        flex-direction: column;
        gap: var(--gap-md);
    }
    /* In flex column, default item sizing is content-based. Force both
       form panel and sidebar to fill the container width — without this
       a short form step (e.g. step 1 with just city cards) collapses
       narrower than expected. */
    .form-with-sidebar > * { width: 100%; }
}

/* ─── Trust sidebar · canonical sidebar component ───────────────────────
   Reassurance panel for the right column of .form-with-sidebar. Lists
   benefits / safety items with mint checkmarks; optional "need help?"
   contact block at the bottom.
*/
.trust-sidebar {
    align-self: start;
    padding: var(--card-pad-lg);
    background: #fff;
    border: 1px solid var(--border);
}
.trust-sidebar__eyebrow {
    margin: 0 0 var(--gap-xs);
}
.trust-sidebar__list {
    margin: 0 0 var(--gap-lg);
    font-size: .9375rem;
    color: var(--text);
}
.trust-sidebar__help {
    padding-top: var(--gap-md);
    border-top: 1px solid var(--border);
    font-size: .875rem;
    color: var(--text-muted);
    line-height: 1.6;
}
.trust-sidebar__help p { margin: 0; }
.trust-sidebar__help a {
    color: var(--mint-dark);
    text-decoration: underline;
}

/* ── Mobile ────────────────────────────────────────────────────────────── */
@media (max-width: 600px) {
    .campaign-hero { padding: 64px 0 80px; }
    .campaign-hero__title { font-size: 1.75rem; }
    .campaign-hero__event-card { padding: var(--card-pad-md); }
    .campaign-body, .campaign-panel, .campaign-schools, .campaign-gallery, .campaign-video {
        padding: 48px 0;
    }
    /* Stack featured cards 1-up on mobile — 3-up crams unreadably. */
    .campaign-schools__featured { grid-template-columns: 1fr; }
    /* (Section header titles get their canonical sizing from .heading-2 —
       no per-section override needed.) */
}


/* ═══════════════════════════════════════════════════════════════════════════
   SPONSOR BANNER — inline sponsored placement (parts/sponsor-banner.php)
   Two variants: compact (badge + name + value prop) and editorial (pull
   quote + attribution). Canonical navy → navy-deep gradient — no invented
   colors, no mint left rail. CTA always amber for visibility.
   ═══════════════════════════════════════════════════════════════════════════ */
.sponsor-banner {
    display: block;
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
    color: #fff;
    text-decoration: none;
    margin: 36px 0;
    transition: transform .15s, box-shadow .15s;
    /* Defensive: when rendered inside .prose (article body), the
       generic .prose a + .prose a:hover rules would otherwise add an
       underline-style border-bottom and a light-mint hover background.
       Banner is its own component — override both. */
    border: 0;
}
.sponsor-banner:hover,
.prose .sponsor-banner:hover {
    /* lift+shadow retired 2026-05-16; bg gradient + border are the affordance now. */
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
    border-bottom: 0;
}
.sponsor-banner__eyebrow {
    font-size: .6875rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--mint);
    margin: 0;
}
.sponsor-banner__cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--amber);
    color: var(--navy);
    padding: 10px 20px;
    font-weight: 800;
    font-size: .9375rem;
    transition: background .15s;
    flex-shrink: 0;
}
.sponsor-banner:hover .sponsor-banner__cta { background: var(--amber-dark); }

/* ── Compact variant — badge + name + value prop + CTA ──────────────────── */
.sponsor-banner--compact {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 18px 24px;
}
.sponsor-banner--compact .sponsor-banner__badge {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    background: var(--mint);
    color: var(--navy);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    font-weight: 800;
    overflow: hidden;
}
/* When the badge contains a logo image, swap to a white container so
   transparent logos read cleanly. */
.sponsor-banner--compact .sponsor-banner__badge:has(img) {
    background: #fff;
    padding: 4px;
}
.sponsor-banner--compact .sponsor-banner__badge img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
.sponsor-banner--compact .sponsor-banner__main { flex: 1; min-width: 0; }
.sponsor-banner--compact .sponsor-banner__eyebrow { margin-bottom: 2px; }
.sponsor-banner--compact .sponsor-banner__name {
    font-size: 1.125rem;
    font-weight: 800;
    color: #fff;
    margin: 0 0 2px;
    line-height: 1.3;
}
.sponsor-banner--compact .sponsor-banner__meta {
    font-size: .8125rem;
    color: rgba(255,255,255,.7);
    margin: 0;
    line-height: 1.4;
    /* Truncate the value-prop line to keep banner height stable */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
@media (max-width: 600px) {
    .sponsor-banner--compact { flex-direction: column; align-items: flex-start; gap: 14px; padding: 18px 20px; }
    .sponsor-banner--compact .sponsor-banner__cta { width: 100%; justify-content: center; }
}

/* ── Editorial variant — pull quote + attribution + CTA ─────────────────── */
.sponsor-banner--editorial {
    padding: 36px 40px;
}
.sponsor-banner--editorial .sponsor-banner__eyebrow { margin-bottom: 14px; }
.sponsor-banner--editorial .sponsor-banner__quote {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.5;
    color: #fff;
    margin: 0 0 18px;
    /* Crimson Pro — the same serif used for English essay pull-quotes.
       Documented as a deliberate canon exception (Be Vietnam Pro is the
       primary; Crimson Pro is for moments where a serif voice helps the
       editorial tone read distinct from surrounding UI/copy). */
    font-family: "Crimson Pro", Georgia, serif;
}
.sponsor-banner--editorial .sponsor-banner__quote::before {
    content: "\201C";
    font-size: 1.6em;
    line-height: 0;
    vertical-align: -.3em;
    color: var(--mint);
    margin-right: 4px;
}
.sponsor-banner--editorial .sponsor-banner__quote::after {
    content: "\201D";
    font-size: 1.6em;
    line-height: 0;
    vertical-align: -.3em;
    color: var(--mint);
}
.sponsor-banner--editorial .sponsor-banner__attr {
    font-size: .875rem;
    color: rgba(255,255,255,.7);
    margin: 0 0 20px;
}
.sponsor-banner--editorial .sponsor-banner__attr strong { color: #fff; font-weight: 700; }
@media (max-width: 600px) {
    .sponsor-banner--editorial { padding: 28px 24px; }
    .sponsor-banner--editorial .sponsor-banner__quote { font-size: 1.0625rem; }
}

/* ─── 404 page ─────────────────────────────────────────────────────────── */
.page-404 {
    padding: var(--section-lg) 0;
    background: var(--surface-soft, #F8F9FB);
}
.page-404__inner {
    max-width: 900px;
    text-align: center;
}
.page-404__overline {
    font-size: 1rem;
    letter-spacing: .15em;
    margin: 0 0 12px;
}
.page-404__title {
    margin: 0 0 16px;
}
.page-404__lead {
    font-size: 1.0625rem;
    color: var(--text-muted);
    line-height: 1.6;
    max-width: 560px;
    margin: 0 auto var(--gap-xl);
}
.page-404__cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gap-md);
    text-align: left;
}
@media (max-width: 720px) {
    .page-404__cards { grid-template-columns: 1fr; }
}
.page-404__card {
    background: #fff;
    border: 1px solid var(--border);
    padding: var(--card-pad-md);
    text-decoration: none;
    color: var(--navy);
    transition: transform var(--ease-base), box-shadow var(--ease-base);
}
/* .page-404__card:hover lift+shadow retired 2026-05-16. */
.page-404__card .heading-card {
    margin: 6px 0 8px;
}
.page-404__card-sub {
    font-size: .9375rem;
    color: var(--text-muted);
    line-height: 1.55;
    margin: 0 0 14px;
}

/* ════════════════════════════════════════════════════════════════════════
 * HOMEPAGE — front-page.php
 *
 * Hero, event strip, featured schools wrapper, service tier preview, articles
 * wrapper, trust band, final CTA band. Card components themselves (school-card,
 * hub-featured-card, hub-article-row, stat-callout, btn--primary, etc.) come
 * from their own canon sections above — this block only adds the homepage
 * layout chrome that wraps them.
 * ════════════════════════════════════════════════════════════════════════ */

/* ── Home hero ────────────────────────────────────────────────────────── */
.home-hero {
    position: relative;
    color: #fff;
    overflow: hidden;
    padding: var(--section-lg) 0;
    /* Navy gradient placeholder until the background image lands.
       .home-hero__bg sits on top with the photo. */
    background: linear-gradient(135deg, #0a1f33 0%, var(--navy) 50%, #082238 100%);
}
.home-hero__bg {
    position: absolute; inset: 0;
    background-size: cover;
    background-position: center;
    /* background-image set inline in front-page.php — easier to swap photos
       without editing CSS. */
}
.home-hero__overlay {
    position: absolute; inset: 0;
    background: linear-gradient(180deg, var(--overlay-navy-light) 0%, rgba(13,40,64,.85) 100%);
}
.home-hero__inner { position: relative; z-index: 2; }
.home-hero__split {
    display: grid;
    grid-template-columns: 3fr 2fr;
    gap: var(--gap-md) var(--gap-lg);
    align-items: center;
}
@media (max-width: 720px) {
    /* Mobile hero: tighter padding (less cramped), centered text + buttons,
       photo focal shifted slightly so the figure stays visible without
       crowding the centered title. Lighter overlay than first pass so the
       photo reads as a real image, not a dark texture. */
    .home-hero { padding: var(--section-md) 0 var(--section-sm); }
    .home-hero__split { grid-template-columns: 1fr; gap: var(--gap-md); text-align: center; }
    .home-hero__title,
    .home-hero__lead { margin-left: auto; margin-right: auto; }
    .home-hero__actions { justify-content: center; }
    .home-hero__bg { background-position: 35% center; }
    .home-hero__overlay {
        background: linear-gradient(180deg, var(--overlay-navy-light) 0%, rgba(13,40,64,.88) 100%);
    }
}
.home-hero__overline {
    display: inline-block;
    font-size: .75rem;
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mint);
    margin: 0 0 16px;
}
.home-hero__title {
    font-size: clamp(2.25rem, 5vw, 3.25rem);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: #fff;
    margin: 0 0 16px;
    max-width: 18ch;
}
.home-hero__title-mint { color: var(--mint); }
.home-hero__lead {
    font-size: 1.0625rem;
    color: rgba(255,255,255,.78);
    line-height: 1.55;
    margin: 0 0 28px;
    max-width: 52ch;
}
.home-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 16px;
    align-items: center;
}
.home-hero__actions .btn { white-space: nowrap; }
.home-hero__sub-cta {
    color: rgba(255,255,255,.85);
    text-decoration: none;
    font-size: .9375rem;
    font-weight: 600;
    border-bottom: 1px solid rgba(255,255,255,.3);
    padding-bottom: 2px;
    transition: color .15s, border-color .15s;
}
.home-hero__sub-cta:hover {
    color: var(--mint);
    border-color: var(--mint);
}
.home-hero__card {
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.12);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    padding: 28px 28px 24px;
}
.home-hero__stat-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 22px 28px;
    margin-bottom: 18px;
}
.home-hero__stat-grid .stat-callout {
    align-items: flex-start;
    text-align: left;
}
.home-hero__card-foot {
    border-top: 1px solid rgba(255,255,255,.12);
    padding-top: 16px;
    margin-top: 4px;
    font-size: .8125rem;
    color: rgba(255,255,255,.7);
    line-height: 1.5;
}

/* ── Home event strip ──────────────────────────────────────────────────
 * Slim navy strip below the hero. Centered: badge · title · countdown
 * pill · 3 city chips · mint "Đăng ký →" CTA. Renders only when at
 * least one open future event instance exists. */
.home-event-strip {
    background: var(--navy-deep, #082238);
    color: #fff;
    padding: 16px 0;
    border-top: 1px solid rgba(255,255,255,.08);
    border-bottom: 1px solid rgba(255,255,255,.08);
}
.home-event-strip__inner {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: 18px;
}
.home-event-strip__badge {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--mint);
    font-weight: 800;
    font-size: .75rem;
    letter-spacing: .1em;
    text-transform: uppercase;
}
.home-event-strip__badge::before {
    content: '';
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--mint);
    animation: home-event-pulse 2.2s ease-in-out infinite;
}
@keyframes home-event-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: .55; transform: scale(.75); }
}
.home-event-strip__title {
    color: #fff;
    font-weight: 700;
    font-size: 1rem;
    margin: 0;
}
.home-event-strip__countdown {
    /* Static label (non-interactive) — squared like canonical .badge.
       Rounded shapes reserved for interactive elements. */
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    background: rgba(79,217,164,.15);
    color: var(--mint);
    font-weight: 800;
    font-size: .8125rem;
    letter-spacing: .02em;
    white-space: nowrap;
}
.home-event-strip__countdown strong { color: #fff; font-weight: 800; }
.home-event-strip__cities {
    display: flex;
    gap: 14px;
    align-items: center;
    color: rgba(255,255,255,.8);
    font-size: .875rem;
}
.home-event-strip__city { display: inline-flex; align-items: center; gap: 6px; }
.home-event-strip__city strong { color: #fff; font-weight: 700; }
.home-event-strip__cta {
    color: var(--mint);
    text-decoration: none;
    font-weight: 800;
    font-size: .9375rem;
    white-space: nowrap;
}
.home-event-strip__cta:hover { color: #fff; }
@media (max-width: 720px) {
    /* Mobile event strip: center stack, hide city chips (too cramped on
       narrow screens — long city names like "Thành phố Hồ Chí Minh"
       wrap weirdly). Badge + title + countdown + CTA is enough; cities
       live on the campaign page one tap away. */
    .home-event-strip__inner {
        flex-direction: column;
        align-items: center;
        text-align: center;
        gap: 8px;
    }
    .home-event-strip__cities { display: none; }
}

/* ── Featured-schools section (wrapper only — uses canonical .school-card-image) */
.fs-section { padding: var(--section-md) 0; background: #fff; }
.fs-section__header { text-align: center; margin: 0 0 var(--gap-lg); }
.fs-section__overline {
    display: inline-block;
    font-size: .75rem;
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mint-dark);
    margin: 0 0 8px;
}
.fs-section__title {
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 800;
    color: var(--navy);
    margin: 0;
}
.fs-section__cta-row { text-align: center; margin-top: var(--gap-md); }
.fs-section__see-all {
    color: var(--mint-dark);
    text-decoration: none;
    font-weight: 700;
    border-bottom: 2px solid var(--mint);
    padding-bottom: 2px;
}
.fs-section__see-all:hover { color: var(--navy); }
.fs-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-md);
}
@media (max-width: 900px) { .fs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .fs-grid { grid-template-columns: 1fr; } }
/* Level-toggle: simple visibility swap */
[data-level-pane] { display: none; }
[data-level-pane].is-active { display: grid; }

/* ── Service tier preview ─────────────────────────────────────────────── */
.tier-preview-section {
    padding: var(--section-md) 0;
    background: var(--surface-soft, #F0F5FA);
}
.tier-preview-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-md);
}
@media (max-width: 900px) { .tier-preview-grid { grid-template-columns: 1fr; } }
.tier-preview-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 28px 24px 24px;
    text-decoration: none;
    color: inherit;
    transition: transform .15s ease, box-shadow .15s ease;
}
/* .tier-preview-card:hover lift+shadow retired 2026-05-16. */
.tier-preview-card__level { align-self: flex-start; margin-bottom: 14px; }
.tier-preview-card__name {
    font-size: 1.25rem;
    font-weight: 800;
    color: var(--navy);
    margin: 0 0 6px;
}
.tier-preview-card__tagline {
    font-size: .9375rem;
    color: var(--text-muted);
    line-height: 1.5;
    margin: 0 0 18px;
    min-height: 4.2em;
}
.tier-preview-card__price {
    margin: 0 0 4px;
    display: flex;
    align-items: baseline;
    gap: 4px;
}
.tier-preview-card__price-amount {
    font-size: 1.625rem;
    font-weight: 800;
    color: var(--navy);
}
.tier-preview-card__price-unit {
    font-size: .875rem;
    color: var(--text-muted);
}
.tier-preview-card__price-note {
    font-size: .75rem;
    color: var(--text-muted);
    margin: 0 0 18px;
}
.tier-preview-card__cta {
    margin-top: auto;
    color: var(--mint-dark);
    text-decoration: none;
    font-weight: 700;
    font-size: .9375rem;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}
.tier-preview-card:hover .tier-preview-card__cta { color: var(--navy); }
/* Trust card variant — navy bg, white text, scholarship/budget CTA */
.tier-preview-card--trust {
    background: var(--navy);
    border-color: var(--navy);
    color: #fff;
}
/* .tier-preview-card--trust:hover shadow retired 2026-05-16. */
.tier-preview-card--trust .tier-preview-card__name {
    color: #fff;
    font-size: 1.375rem;
    line-height: 1.25;
    margin-bottom: 12px;
}
.tier-preview-card--trust .tier-preview-card__tagline {
    color: rgba(255,255,255,.8);
    margin-bottom: 0;
    min-height: 0;
}
.tier-preview-card--trust .tier-preview-card__cta {
    color: var(--mint);
    border-top-color: rgba(255,255,255,.15);
}
.tier-preview-card--trust:hover .tier-preview-card__cta { color: #fff; }
/* Trust card bullet checklist — mint Unicode checkmark */
.tier-preview-card__bullets {
    list-style: none;
    padding: 0;
    margin: 14px 0 0;
}
.tier-preview-card__bullets li {
    color: rgba(255,255,255,.88);
    font-size: .9375rem;
}

/* ── Articles section (wrapper only — uses canonical hub-featured-card, hub-article-row) */
.articles-home { padding: var(--section-md) 0; background: #fff; }
.articles-home__two-up {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--gap-md);
    margin-bottom: var(--gap-lg);
}
@media (max-width: 720px) { .articles-home__two-up { grid-template-columns: 1fr; } }

/* ── Final CTA band · mint flat end-of-homepage CTA ──────────────────────
   Paired with .cta-banner (see ~line 3670) as the two canonical full-bleed
   CTA bands. Flat mint = "warm, light, inviting" — the homepage closer.
   The navy gradient variant lives on detail pages as a more formal CTA.
   Different on purpose; not drift. */
.home-cta-band {
    padding: var(--section-lg) 0;
    background: var(--mint);
    text-align: center;
}
.home-cta-band__inner {
    max-width: 640px;
    margin: 0 auto;
    padding: 0 24px;
}
.home-cta-band__heading { margin: 0 0 16px; }
.home-cta-band__sub {
    font-size: 1.125rem;
    color: rgba(13,40,64,.78);
    line-height: 1.5;
    margin: 0 0 28px;
}

/* ── Homepage chevron link animation ──────────────────────────────────
 * Wrap each "→" in <span class="link-action__arrow"> inside a chevron link.
 * Parent :hover slides the arrow 3px right. Matches canonical .link-action
 * arrow-slide pattern. Hero button is excluded by convention. */
.home-event-strip__cta .link-action__arrow,
.fs-section__see-all .link-action__arrow,
.tier-preview-card__cta .link-action__arrow {
    display: inline-block;
    transition: transform var(--ease-base);
    margin-left: 2px;
}
.home-event-strip__cta:hover .link-action__arrow,
.fs-section__see-all:hover .link-action__arrow,
.tier-preview-card:hover .link-action__arrow { transform: translateX(3px); }


/* ──────────────────────────────────────────────────────────────────
   IMAGE-ZOOM HOVER  (Replaces lift effects retired 2026-05-16.)

   For cards that contain a real image (not initials/placeholder), the
   image gently scales up on card hover. The card itself does not move
   — keeps the layout calm. Image overflow is clipped at the card edge.

   Applies to: photo-forward school cards (.sc-img), homepage article
   featured cards (.hub-featured-card), homepage article rows
   (.hub-article-row), school-profile gallery thumbs, and image-bearing
   widget cards (.school-card-image which is an alias of sc-img).
   ────────────────────────────────────────────────────────────────── */

/* Excludes .hub-article-row — those thumbnails are too small for hover zoom
   to read well (per Brett's note 2026-05-16). Only the larger card formats
   get the effect: full school cards + the home page's two-up featured
   article cards. */
.sc-img,
.hub-featured-card,
.school-card-image {
    overflow: hidden;
}
.sc-img__photo,
.hub-featured-card__img {
    overflow: hidden;
}
.sc-img img,
.hub-featured-card img,
.school-card-image img {
    transition: transform .4s cubic-bezier(.22, .61, .36, 1);
    will-change: transform;
}
.sc-img:hover img,
.hub-featured-card:hover img,
.school-card-image:hover img {
    transform: scale(1.05);
}
/* Event hub cards on /su-kien/ — same effect, but applied to the
   .event-archive-card__media background-image div since these cards
   use a div+background, not an <img>. */
.event-archive-card { overflow: hidden; }
.event-archive-card__media {
    transition: transform .4s cubic-bezier(.22, .61, .36, 1);
    will-change: transform;
}
.event-archive-card:hover .event-archive-card__media {
    transform: scale(1.05);
}

@media (prefers-reduced-motion: reduce) {
    .sc-img img,
    .hub-featured-card img,
    .school-card-image img,
    .event-archive-card__media {
        transition: none;
    }
    .sc-img:hover img,
    .hub-featured-card:hover img,
    .school-card-image:hover img,
    .event-archive-card:hover .event-archive-card__media {
        transform: none;
    }
}

/* ──────────────────────────────────────────────────────────────────
   IMAGE-ZOOM ALTERNATIVES  (uncomment ONE block at a time to test)

   Three options Brett asked to consider — variations of the photo
   treatment without relying on hover. Default (active above) is the
   hover-only zoom. To try an alternative: COMMENT OUT the hover rules
   above and UNCOMMENT one of the blocks below.
   ────────────────────────────────────────────────────────────────── */

/* — Option A — slow Ken Burns on featured cards only.
     Constant gentle pan+zoom on the home page's two big article cards.
     Calmer than hover-zoom on listings; doesn't tire eyes because only
     two images animate.

@keyframes dhtc-ken-burns {
    0%   { transform: scale(1.0) translate(0, 0); }
    100% { transform: scale(1.06) translate(-1.5%, -1%); }
}
.hub-featured-card img {
    transform-origin: center;
    animation: dhtc-ken-burns 18s ease-in-out infinite alternate;
}
@media (prefers-reduced-motion: reduce) {
    .hub-featured-card img { animation: none; }
}
*/

/* — Option B — initial settle. Image starts at scale(1.06) and settles
     to 1.0 over 1.2s when it enters viewport. One-time animation per
     pageview. Gentle "arrival" feel.

@keyframes dhtc-img-settle {
    from { transform: scale(1.06); }
    to   { transform: scale(1.0); }
}
.sc-img img,
.hub-featured-card img,
.school-card-image img {
    animation: dhtc-img-settle 1.2s cubic-bezier(.22,.61,.36,1) both;
}
@media (prefers-reduced-motion: reduce) {
    .sc-img img,
    .hub-featured-card img,
    .school-card-image img { animation: none; }
}
*/

/* — Option C — no effect at all (kill the hover-zoom completely).
     Just delete the active rules above. Cards stay still. Cleanest +
     most performant if Brett decides the hover-zoom doesn't earn its
     keep. */


/* ──────────────────────────────────────────────────────────────────
   NAV SEARCH SPYGLASS  (Task 8 — added 2026-05-16)

   Desktop: a circular spyglass icon sits to the LEFT of the
   "Xem gói dịch vụ" CTA. Click expands a search panel LEFT (toward
   the menu items) up to ~360px wide, sliding over them. The
   "Du Học Thành Công" wordmark stays visible. ESC or outside click
   closes.

   Mobile: a search bar is rendered at the top of the nav drawer
   (between the drawer header and the section links). Same REST
   endpoint, same result rendering — different layout container.
   ────────────────────────────────────────────────────────────────── */

/* ── Desktop spyglass + expanding panel ──────────────────────────── */
/* Now lives as the LAST <li> inside .site-nav__links (browse group),
   not as a separate item in .site-nav__actions next to the CTA. Same
   panel-expansion behavior; the new anchor position means the panel
   grows leftward over the menu items it sits among. */
.nav-search { position: relative; display: flex; align-items: center; list-style: none; }

.nav-search__toggle {
    /* Iconic — no border, no fill. Sits in the menu like another nav item:
       thick stroke, matches the weight of the bold .site-nav__links text. */
    padding: 6px 4px;
    background: transparent;
    color: #fff;
    border: 0;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: color var(--ease-base);
}
.nav-search__toggle:hover,
.nav-search__toggle:focus-visible {
    color: var(--mint);
    outline: none;
}

.nav-search__panel {
    position: absolute;
    top: 50%;
    right: 0;       /* anchored to the spyglass position, grows leftward */
    transform: translateY(-50%) scaleX(0);
    transform-origin: right center;
    /* Spyglass now sits at the end of the browse links (further left in
       the header). Panel grows LEFT from that anchor, covering all menu
       items back to the wordmark. The 480px subtraction reserves the
       wordmark + the breathing space needed before the wordmark edge. */
    width: min(560px, calc(100vw - 480px));
    height: 40px;
    background: #fff;
    border: 1px solid var(--border);
    border-radius: 20px;
    box-shadow: 0 6px 18px rgba(13, 40, 64, .10);
    display: flex; align-items: center;
    transition: transform .25s cubic-bezier(.22, .61, .36, 1), opacity .15s ease, border-color .15s;
    opacity: 0;
    pointer-events: none;
    z-index: 110;   /* above the nav links */
}
.nav-search.is-open .nav-search__panel {
    transform: translateY(-50%) scaleX(1);
    opacity: 1;
    pointer-events: auto;
    border-color: var(--mint);  /* focus cue — matches .form-input:focus pattern */
}
/* When results are visible, merge input + dropdown into one stacked card.
   Bottom corners flatten, the seam between input bottom edge and results top
   edge collapses (transparent border + zero-gap top:100% on results).
   .has-results class is toggled by the search-builder JS in footer.php —
   more reliable than :has() across browser :has-invalidation quirks. */
.nav-search.is-open .nav-search__panel.has-results {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: transparent;
}
.nav-search.is-open .nav-search__toggle {
    /* Hide the toggle while the panel is open — the close button inside takes over */
    visibility: hidden;
}

.nav-search__input {
    flex: 1; min-width: 0;
    padding: 0 8px 0 18px;
    border: none; outline: none; background: transparent;
    font: 15px/1 var(--font-body);
    color: var(--navy);
}
.nav-search__input::placeholder { color: var(--text-muted); }
/* Suppress browser-native clear button on type=search — we have our own .nav-search__close */
.nav-search__input::-webkit-search-cancel-button,
.nav-drawer__search-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.nav-search__close {
    width: 32px; height: 32px; margin-right: 4px;
    padding: 0; background: transparent; color: var(--text-muted);
    border: none; cursor: pointer;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    transition: background var(--ease-base), color var(--ease-base);
}
.nav-search__close:hover { background: var(--surface); color: var(--navy); }

/* Results dropdown — sits flush against the bottom of the input panel,
   inheriting the panel's mint focus border so the two read as one
   floating card (Algolia/Spotify command-palette pattern).
   left/right -1px (not 0): results is positioned inside the panel, so
   right:0 would anchor it to the panel's PADDING edge (1px inside the
   panel's 1px border). Negative offsets pull it back out so the results'
   side borders sit on the same pixel column as the panel's side borders
   — perfectly aligned outer edges, single visible mint line per side. */
.nav-search__results {
    position: absolute;
    top: 100%;
    left: -1px;
    right: -1px;
    list-style: none; margin: 0; padding: 6px 0;
    background: #fff;
    border: 1px solid var(--mint);
    border-top: none;       /* seam with input panel bottom */
    border-bottom-left-radius: 20px;
    border-bottom-right-radius: 20px;
    box-shadow: 0 10px 30px rgba(13, 40, 64, .15);
    max-height: 60vh;
    overflow-y: auto;
    z-index: 110;
}
.nav-search__results[hidden] { display: none; }
.nav-search__results li { padding: 0; margin: 0; }
.nav-search__results a {
    display: block; padding: 8px 16px;
    color: var(--navy); text-decoration: none;
    line-height: 1.3;
}
.nav-search__results a:hover,
.nav-search__results a:focus-visible,
.nav-search__results .is-active a {
    background: var(--surface);
    outline: none;
}
.nav-search__result-title {
    display: block; font-weight: 600; font-size: 14px;
}
.nav-search__result-loc {
    display: block; font-size: 12px; color: var(--text-muted); margin-top: 1px;
}
/* Selectors scoped under .nav-search__results so they out-specify the
   .nav-search__results li { padding: 0 } rule above (otherwise the LI
   reset wins and the loading/empty message loses its left padding). */
.nav-search__results .nav-search__empty,
.nav-search__results .nav-search__loading {
    padding: 12px 16px;  /* horizontal matches result rows (8px 16px) */
    color: var(--text-muted); font-size: 13px;
    font-style: italic;
}

/* Hide on mobile — drawer search takes over */
@media (max-width: 768px) { .nav-search { display: none; } }

/* ── Mobile drawer search ────────────────────────────────────────── */
.nav-drawer__search {
    position: relative;
    margin: 22px 20px 18px;  /* breathing room from the drawer header rule above */
    display: flex; align-items: center;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .15);
    border-radius: 22px;
    padding: 2px 4px 2px 14px;
    color: var(--mint);
}
.nav-drawer__search-icon { color: var(--mint); flex: 0 0 auto; opacity: .85; }
.nav-drawer__search-input {
    flex: 1; min-width: 0;
    padding: 10px 12px;
    background: transparent; border: none; outline: none;
    color: #fff; font: 15px/1 var(--font-body);
}
.nav-drawer__search-input::placeholder { color: rgba(255, 255, 255, .55); }
.nav-drawer__search-results {
    position: absolute;
    top: calc(100% + 4px); left: 0; right: 0;
    list-style: none; margin: 0; padding: 4px 0;
    background: #fff;
    border-radius: 8px;
    max-height: 50vh; overflow-y: auto;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .25);
    z-index: 50;
}
.nav-drawer__search-results[hidden] { display: none; }
.nav-drawer__search-results li { margin: 0; }
.nav-drawer__search-results a {
    display: block; padding: 10px 14px;
    color: var(--navy); text-decoration: none;
    line-height: 1.3;
    border-left: 3px solid transparent;
}
.nav-drawer__search-results a:hover,
.nav-drawer__search-results .is-active a {
    background: var(--surface);
    border-left-color: var(--mint);
}
.nav-drawer__search-results .nav-search__result-title { font-weight: 600; font-size: 14px; }
.nav-drawer__search-results .nav-search__result-loc   { font-size: 12px; color: var(--text-muted); }
.nav-drawer__search-results .nav-search__empty,
.nav-drawer__search-results .nav-search__loading { color: var(--text-muted); padding: 12px 14px; font-size: 13px; font-style: italic; }
