/* ============================================================
   Bellmeir — Candy-Bright Design System
   Implements SMS_UIUX_DESIGN_STUDY_v2.md tokens (Section 3 + 12.1)
   Single source of truth: never hardcode a hex in markup.
   ============================================================ */

/* ---------- 1. Tokens ---------- */
:root {
  /* Candy palette (brand) */
  --teal: #2BB39A;        --teal-deep: #1E967F;
  --coral: #F4756B;       --coral-deep: #E25B50;
  --sunny: #FFC93C;       --sunny-deep: #C28A00;
  --sky: #3BA3F0;         --sky-deep: #2589D6;
  --grape: #8B5CF6;       --grape-deep: #7445E0;
  --blossom: #F49AC1;     --blossom-deep: #E5739F;
  --tangerine: #F79420;   --tangerine-deep: #E07F0E;

  /* Runtime brand (multi-tenant theming hook) */
  --brand: var(--teal);
  --brand-deep: var(--teal-deep);

  /* Ink & surfaces */
  --ink-900: #1F2B4D;
  --ink-700: #3D4A6B;
  --ink-500: #6B7693;
  --ink-400: #98A1B5;
  --ink-200: #E3E7EF;
  --canvas: #ECECEA;
  --panel: #FFFFFF;
  --card: #FFFFFF;
  --inset: #F6F6F4;
  --cream: #F9EFE7;
  --scrim: rgba(31, 43, 77, 0.40);

  /* Pastel fills */
  --mint: #DFF4EE;
  --peach: #FEE9E7;
  --butter: #FFF3D6;
  --skylight: #E3F2FD;
  --lavender: #EDE7FB;
  --blush: #FDE8F1;
  --creamfill: #FFF1DF;

  /* Semantic. These five are the AA-corrected darks, kept BYTE-IDENTICAL to
     web/tailwind.config.ts. The lighter originals (#1E967F / #C28A00 / #E0453A
     / #2589D6 / #E07F0E) sat at 2.62-3.55:1 on their own pastel fills, so every
     status pill on this site failed AA while the portal's passed. One design
     system means one set of hexes: change these only alongside the portal.
     Ratios on their -bg: 5.62 / 4.98 / 5.59 / 5.92 / 5.19. */
  --success: #0F6B57;  --success-bg: #DFF4EE;
  --warning: #8A6200;  --warning-bg: #FFF3D6;
  --error: #B3271A;    --error-bg: #FEE9E7;
  --info: #125E9C;     --info-bg: #E3F2FD;
  --money: #9A5400;    --money-bg: #FFF1DF;

  /* Access marks in the permissions matrix. Their meaning is carried by the
     icon alone, so they are held to text contrast (4.5+) not the 3:1 icon
     floor: 6.44 / 5.49 / 4.53 on white. */
  --access-yes: #0F6B57;
  --access-partial: #8A6200;
  --access-no: #6B7693;

  /* Ink that stays legible ON a saturated candy fill. White is 2.28-2.76:1 on
     teal, coral, sky and tangerine, which fails AA on every pill button and
     stat block; navy on the SAME unchanged fills is 5.03-6.10:1. The palette
     does not move, only what sits on top of it. Grape is the one fill dark
     enough for white (4.23), so it keeps it. */
  --on-candy: #1F2B4D;

  /* Hero headline rainbow. Same four hues as the original sweep, with the
     saturation pulled back to ~55% so it reads rich rather than neon, then
     darkened only as far as AA needs. Worst point of the animation is 4.61:1;
     the original bottomed out at 2.73:1 and the first correction overshot into
     vivid territory. Ratios: 4.75 / 4.62 / 4.61 / 4.62. */
  --shine-1: #357F71;   /* teal  */
  --shine-2: #357AAE;   /* sky   */
  --shine-3: #8360D1;   /* grape */
  --shine-4: #C64D44;   /* coral */
  /* The static colour used where the animation cannot run (reduced motion, no JS). */
  --shine-rest: #0F6B57;

  /* Radius */
  --r-chip: 10px;
  --r-input: 14px;
  --r-card: 20px;
  --r-lg: 24px;
  --r-hero: 28px;
  --r-shell: 32px;
  --r-pill: 999px;

  /* Soft navy elevation */
  --sh-1: 0 4px 16px rgba(31, 43, 77, .06);
  --sh-2: 0 8px 24px rgba(31, 43, 77, .10);
  --sh-3: 0 12px 32px rgba(31, 43, 77, .14);
  --sh-4: 0 20px 48px rgba(31, 43, 77, .18);

  /* Type */
  --font-sans: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  --font-data: 'Inter', system-ui, sans-serif;

  /* Motion */
  --ease-candy: cubic-bezier(0.34, 1.2, 0.4, 1);

  /* Layout */
  --maxw: 1200px;
  --maxw-wide: 1320px;
  --nav-h: 76px;
}

/* ---------- 2. Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-data);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-700);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: none; background: none; }
ul { list-style: none; padding: 0; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 6px; }

h1, h2, h3, h4, h5 {
  font-family: var(--font-sans);
  color: var(--ink-900);
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 800;
}

/* ---------- 3. Typography helpers ---------- */
.display { font-family: var(--font-sans); font-weight: 800; font-size: clamp(2.4rem, 5.2vw, 4rem); line-height: 1.05; letter-spacing: -0.03em; color: var(--ink-900); }
.h1 { font-size: clamp(2rem, 3.6vw, 2.9rem); font-weight: 800; }
.h2 { font-size: clamp(1.5rem, 2.4vw, 2.1rem); font-weight: 800; }
.h3 { font-size: 1.18rem; font-weight: 700; }
.eyebrow {
  font-family: var(--font-sans);
  font-weight: 700; font-size: 0.8rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--brand-deep);
}
.lead { font-size: clamp(1.05rem, 1.5vw, 1.25rem); color: var(--ink-500); line-height: 1.65; }
.muted { color: var(--ink-500); }
.ink { color: var(--ink-900); }
.center { text-align: center; }
.balance { text-wrap: balance; }
.nowrap { white-space: nowrap; }

/* ---------- 4. Layout ---------- */
.container { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: 24px; }
.container-wide { max-width: var(--maxw-wide); }
.container-narrow { max-width: 860px; }

.section { padding-block: clamp(56px, 8vw, 104px); }
.section-tight { padding-block: clamp(40px, 5vw, 64px); }

.section-head { max-width: 720px; margin-inline: auto; margin-bottom: 48px; }
.section-head.left { margin-inline: 0; }
.section-head .eyebrow { margin-bottom: 14px; display: inline-block; }
.section-head h2 { margin-bottom: 16px; }

.grid { display: grid; gap: 24px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.wrap { flex-wrap: wrap; }
.gap-8 { gap: 8px; } .gap-12 { gap: 12px; } .gap-16 { gap: 16px; } .gap-24 { gap: 24px; } .gap-32 { gap: 32px; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mt-24 { margin-top: 24px; } .mt-32 { margin-top: 32px; } .mt-48 { margin-top: 48px; }
.mb-0 { margin-bottom: 0; }

/* ---------- 5. Buttons (pills only) ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font-family: var(--font-sans); font-weight: 700; font-size: 0.97rem;
  border-radius: var(--r-pill);
  padding: 13px 26px; min-height: 48px;
  transition: transform .18s var(--ease-candy), box-shadow .18s var(--ease-candy), background .18s ease, color .18s ease;
  white-space: nowrap; cursor: pointer;
}
.btn svg { width: 18px; height: 18px; }
/* Candy fill + navy ink (see --on-candy). White on these fills was 2.28-2.76:1;
   the label of the site's primary button did not meet AA on any page. The fill
   is unchanged, so the brand reads exactly as before. */
.btn-primary { background: var(--brand); color: var(--on-candy); box-shadow: var(--sh-1); }
.btn-primary:hover { background: var(--brand-deep); box-shadow: var(--sh-2); transform: translateY(-1px); }
.btn-coral { background: var(--coral); color: var(--on-candy); box-shadow: var(--sh-1); }
.btn-coral:hover { background: var(--coral-deep); box-shadow: var(--sh-2); transform: translateY(-1px); }
.btn-tangerine { background: var(--tangerine); color: var(--on-candy); box-shadow: var(--sh-1); }
.btn-tangerine:hover { background: var(--tangerine-deep); box-shadow: var(--sh-2); transform: translateY(-1px); }
.btn-secondary { background: #fff; color: var(--ink-900); border: 1.5px solid var(--ink-200); }
.btn-secondary:hover { border-color: var(--brand); color: var(--success); transform: translateY(-1px); box-shadow: var(--sh-1); }
/* Soft pill: teal-deep on mint was 2.40:1. --success is the same hue, 4.9:1 here. */
.btn-soft { background: var(--mint); color: var(--success); }
.btn-soft:hover { transform: translateY(-1px); box-shadow: var(--sh-1); }
/* brand-deep as link text is 3.67:1 on white; --success is the same family at 6.44. */
.btn-ghost { background: transparent; color: var(--success); padding-inline: 14px; }
.btn-ghost:hover { background: rgba(43, 179, 154, 0.10); }
.btn-white { background: #fff; color: var(--ink-900); box-shadow: var(--sh-1); }
.btn-white:hover { transform: translateY(-1px); box-shadow: var(--sh-2); }
.btn-lg { font-size: 1.05rem; padding: 16px 32px; min-height: 56px; }
.btn-block { width: 100%; }
.btn:active { transform: scale(0.97); }

/* ---------- 6. Cards ---------- */
.card {
  background: var(--card); border-radius: var(--r-card);
  box-shadow: var(--sh-1); padding: 24px;
}
.card-lg { border-radius: var(--r-lg); padding: 28px; }
.card-hover { transition: transform .2s var(--ease-candy), box-shadow .2s var(--ease-candy); }
.card-hover:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }

/* Icon chip — pastel rounded square + deep icon (every list/feature row) */
.icon-chip {
  width: 52px; height: 52px; flex: none;
  border-radius: 14px;
  display: grid; place-items: center;
}
.icon-chip svg { width: 26px; height: 26px; }
.icon-chip.sm { width: 42px; height: 42px; border-radius: 12px; }
.icon-chip.sm svg { width: 21px; height: 21px; }
.icon-chip.lg { width: 64px; height: 64px; border-radius: 18px; }
.icon-chip.lg svg { width: 32px; height: 32px; }

/* Pastel chip tints */
.chip-mint { background: var(--mint); color: var(--teal-deep); }
.chip-peach { background: var(--peach); color: var(--coral-deep); }
.chip-butter { background: var(--butter); color: var(--sunny-deep); }
.chip-sky { background: var(--skylight); color: var(--sky-deep); }
.chip-lavender { background: var(--lavender); color: var(--grape-deep); }
.chip-blush { background: var(--blush); color: var(--blossom-deep); }
.chip-cream { background: var(--creamfill); color: var(--tangerine-deep); }

/* Solid candy fills (stat blocks etc.) */
/* Navy ink on every candy fill, not just yellow. The "ink on yellow" rule
   below was right and simply did not go far enough: white measured 2.28-2.76:1
   on teal, coral, sky and tangerine too. Navy on the same unchanged fills is
   5.03-6.10:1. Grape is dark enough to keep white (4.23 vs 3.28 for navy). */
.fill-teal { background: var(--teal); color: var(--on-candy); }
.fill-coral { background: var(--coral); color: var(--on-candy); }
.fill-sky { background: var(--sky); color: var(--on-candy); }
.fill-grape { background: var(--grape); color: #fff; }
.fill-tangerine { background: var(--tangerine); color: var(--on-candy); }
.fill-sunny { background: var(--sunny); color: var(--on-candy); }
.fill-brand { background: var(--brand); color: #fff; }

/* Feature card */
.feature-card { background: #fff; border-radius: var(--r-lg); padding: 28px; box-shadow: var(--sh-1); }
.feature-card .icon-chip { margin-bottom: 18px; }
.feature-card h3 { margin-bottom: 8px; }
.feature-card p { color: var(--ink-500); font-size: 0.96rem; }

/* Stat block — solid color owns the card; big count-up number */
.stat-block {
  border-radius: var(--r-lg); padding: 26px 24px; box-shadow: var(--sh-1);
  position: relative; overflow: hidden;
}
.stat-block .stat-num { font-family: var(--font-sans); font-weight: 800; font-size: clamp(2.2rem, 4vw, 3rem); line-height: 1; letter-spacing: -0.03em; }
.stat-block .stat-label { font-weight: 600; opacity: .92; margin-top: 8px; font-size: 0.95rem; }
.stat-block .stat-deco { position: absolute; right: -10px; bottom: -10px; opacity: .22; }
.stat-block .stat-deco svg { width: 96px; height: 96px; }

/* List row card (entity rows) */
.row-card { display: flex; align-items: center; gap: 16px; background: #fff; border-radius: var(--r-card); padding: 16px 18px; box-shadow: var(--sh-1); }
.row-card .row-body { flex: 1; min-width: 0; }
.row-card .row-body .h3 { color: var(--ink-900); }
.row-card .row-meta { color: var(--ink-500); font-size: 0.88rem; }

/* ---------- 7. Badges / pills / tags ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: var(--r-pill); padding: 6px 13px;
  font-family: var(--font-sans); font-weight: 700; font-size: 0.78rem;
  letter-spacing: 0.02em;
}
.pill svg { width: 14px; height: 14px; }
.pill-mint { background: var(--mint); color: var(--teal-deep); }
.pill-peach { background: var(--peach); color: var(--coral-deep); }
.pill-butter { background: var(--butter); color: var(--sunny-deep); }
.pill-sky { background: var(--skylight); color: var(--sky-deep); }
.pill-lavender { background: var(--lavender); color: var(--grape-deep); }
.pill-blush { background: var(--blush); color: var(--blossom-deep); }
.pill-cream { background: var(--creamfill); color: var(--tangerine-deep); }
.pill-ink { background: var(--ink-900); color: #fff; }
.pill-glass { background: rgba(255,255,255,0.18); color: #fff; backdrop-filter: blur(4px); }

.tag { display: inline-flex; align-items: center; gap: 6px; background: var(--inset); color: var(--ink-700); border-radius: var(--r-chip); padding: 5px 12px; font-size: 0.82rem; font-weight: 600; }

/* ---------- 8. Header / nav ---------- */
/* Holds the header's 76px open from first paint. site.js builds the header at
   runtime and inserts it as body's first child, which pushed the whole page
   down 76px the moment it ran. The placeholder occupies exactly that height
   until the real header exists, then stands down, so the total never changes. */
body::before { content: ""; display: block; height: var(--nav-h); }
body.has-header::before { display: none; }

.site-header {
  position: sticky; top: 0; z-index: 100;
  height: var(--nav-h);
  display: flex; align-items: center;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.site-header.scrolled { border-bottom-color: var(--ink-200); box-shadow: var(--sh-1); }
.nav { display: flex; align-items: center; justify-content: space-between; width: 100%; max-width: var(--maxw-wide); margin-inline: auto; padding-inline: 24px; gap: 24px; }
.brand { display: flex; align-items: center; gap: 11px; font-family: var(--font-sans); font-weight: 800; font-size: 1.28rem; color: var(--ink-900); letter-spacing: -0.02em; }
.brand .logo-mark { width: 26px; height: 26px; flex: none; display: block; }

.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-links a { font-family: var(--font-sans); font-weight: 600; font-size: 0.95rem; color: var(--ink-700); padding: 9px 14px; border-radius: var(--r-pill); transition: background .15s ease, color .15s ease; }
.nav-links a:hover { background: var(--inset); color: var(--ink-900); }
.nav-links a.active { color: var(--brand-deep); }
.nav-cta { display: flex; align-items: center; gap: 10px; }

/* dropdown */
.nav-item { position: relative; }
.nav-menu {
  position: absolute; top: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(8px);
  background: #fff; border-radius: var(--r-lg); box-shadow: var(--sh-3); padding: 12px;
  width: 300px; opacity: 0; visibility: hidden; transition: all .2s var(--ease-candy);
}
/* Three ways in, not one. `:hover` alone meant the submenu was unreachable by
   keyboard (a hidden menu is out of the tab order) and by touch (no hover
   exists), so nine destinations could only be found in the footer.
   `:focus-within` covers Tab, `.open` covers the chevron button tap. */
.nav-item:hover .nav-menu,
.nav-item:focus-within .nav-menu,
.nav-item.open .nav-menu { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
/* The chevron is a real button so it can be tapped and announced. */
.nav-disc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; margin-left: 2px; padding: 0;
  border: 0; background: transparent; color: inherit; cursor: pointer;
  border-radius: 50%;
}
.nav-disc svg { width: 15px; height: 15px; transition: transform .18s var(--ease-candy); }
.nav-item.open .nav-disc svg { transform: rotate(180deg); }
/* Bridges the 10px gap between the trigger and the panel so the pointer can
   travel down without the menu closing underneath it. */
.nav-menu::before { content: ""; position: absolute; left: 0; right: 0; top: -12px; height: 12px; }
.nav-menu a { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 14px; }
.nav-menu a:hover { background: var(--inset); }
.nav-menu .mi-title { font-family: var(--font-sans); font-weight: 700; font-size: 0.92rem; color: var(--ink-900); }
.nav-menu .mi-sub { font-size: 0.8rem; color: var(--ink-500); }

.nav-toggle { display: none; width: 44px; height: 44px; border-radius: 50%; background: var(--inset); place-items: center; }
.nav-toggle svg { width: 22px; height: 22px; color: var(--ink-900); }

/* mobile drawer */
.mobile-nav { position: fixed; inset: 0; z-index: 200; visibility: hidden; }
.mobile-nav.open { visibility: visible; }
.mobile-nav .mscrim { position: absolute; inset: 0; background: var(--scrim); opacity: 0; transition: opacity .25s ease; }
.mobile-nav.open .mscrim { opacity: 1; }
.mobile-nav .msheet { position: absolute; top: 0; right: 0; height: 100%; width: min(86vw, 360px); background: #fff; padding: 24px; transform: translateX(100%); transition: transform .28s var(--ease-candy); overflow-y: auto; }
.mobile-nav.open .msheet { transform: translateX(0); }
/* Scoped to `.mlinks`, not to every `a` in the sheet. As `.msheet a` it also
   caught the brand lockup (stacking the mark above the word) and the two CTA
   buttons (forcing display:block, which left-aligned their labels). */
.mobile-nav .mlinks a { display: block; padding: 14px 16px; border-radius: 14px; font-family: var(--font-sans); font-weight: 600; color: var(--ink-900); }
.mobile-nav .mlinks a:hover { background: var(--inset); }
.mobile-nav .mclose { margin-left: auto; flex: none; }
/* The drawer header. The lockup used to wrap onto two lines here: at 1.28rem
   the brand is 287px wide and the sheet only has 312px of inner width, so the
   44px close button tipped it over. A wrapped 87px lockup then pushed both
   CTAs below the fold on a 844px screen. */
.mobile-nav .mhead {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
/* `display:flex` is restated because the generic `.msheet a` rule sets
   `display:block` + 14px padding on every link in the sheet, which caught the
   brand too and stacked the mark above the word. */
.mobile-nav .mhead .brand {
  display: flex; align-items: center; gap: 9px;
  font-size: 1.1rem; white-space: nowrap; min-width: 0; padding: 0;
}
.mobile-nav .mhead .brand:hover { background: none; }

/* The sheet is a column: links scroll, the two CTAs stay pinned to the bottom.
   Sixteen links plus two buttons genuinely do not fit a 844px phone, and the
   honest fix is to keep the actions reachable rather than to shrink 52px touch
   targets until they do. */
.mobile-nav .msheet { display: flex; flex-direction: column; }
.mobile-nav .mlinks { flex: 1 1 auto; overflow-y: auto; margin-inline: -8px; padding-inline: 8px; }
.mobile-nav .mcta {
  flex: none; display: grid; gap: 10px;
  padding-top: 14px; margin-top: 10px;
  border-top: 1px solid var(--ink-200); background: #fff;
}
/* Marks the page you are on, which the drawer never did. */
.mobile-nav .mlinks a[aria-current="page"] {
  background: var(--mint); color: var(--success);
}

/* Soft-navigation swap. The guide fades in from a few pixels down so the
   change registers without the white flash of a full document load. */
.docs-content { transition: opacity .16s ease, transform .16s ease; }
.docs-content.docs-swapped { opacity: 0; transform: translateY(6px); }
.docs-shell[aria-busy="true"] { cursor: progress; }
@media (prefers-reduced-motion: reduce) {
  .docs-content { transition: none; }
  .docs-content.docs-swapped { opacity: 1; transform: none; }
}

/* ---------- 8b. Help Center search (sidebar, every guide) ---------- */
.ds-search { position: relative; margin-bottom: 18px; }
.dsq-wrap { position: relative; }
.dsq-ic {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--ink-500); display: inline-flex; pointer-events: none;
}
.dsq-ic svg { width: 16px; height: 16px; }
.dsq {
  width: 100%; height: 42px; padding: 0 14px 0 38px;
  border: 1.5px solid var(--ink-200); border-radius: var(--r-pill);
  background: #fff; font-family: var(--font-sans); font-size: .9rem; color: var(--ink-900);
}
.dsq::placeholder { color: var(--ink-500); }
.dsq:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 4px rgba(43,179,154,.12); }
.dsq::-webkit-search-cancel-button { cursor: pointer; }

/* Wider than the 250px sidebar it hangs off, because a result needs room for
   a heading, its guide and a line of context. */
/* Above the sticky header (z-index 100). A search panel that opens upward on a
   short screen must sit over the header, never behind it. */
.dsr {
  position: absolute; z-index: 150; left: 0; top: calc(100% + 8px);
  width: max(100%, 380px);
  max-height: min(60vh, 440px); overflow-y: auto;
  background: #fff; border-radius: var(--r-lg); box-shadow: var(--sh-3);
  padding: 6px; border: 1px solid var(--ink-200);
}
/* On the hub the box sits inside `.hero`, which is `overflow: hidden` so it can
   contain its decorative blobs. That clipped the results panel off mid-result.
   `position: fixed` takes it out of every ancestor's clip; site.js keeps its
   top/left/width pinned to the input while it is open. */
.docs-hero-search .dsr {
  position: fixed; left: auto; right: auto; width: auto;
  max-height: min(58vh, 460px);
}
@media (max-width: 1024px) { .dsr { width: 100%; } }
/* `.docs-sidebar a` sets display:flex on every link in the sidebar, which
   caught the result rows and laid their three lines out as columns. Stated
   with matching specificity so a result stacks the way it is written. */
/* `text-align: left` is explicit because the hub's hero is `.center`, which
   centred every result line and made the list unscannable. */
.dsr, .dsr-empty { text-align: left; }
.dsr-item, .docs-sidebar .dsr-item {
  display: block; padding: 10px 12px; border-radius: 12px;
  text-decoration: none; font-weight: 400; color: inherit; text-align: left;
}
.dsr-item:hover, .dsr-item.on,
.docs-sidebar .dsr-item:hover, .docs-sidebar .dsr-item.on { background: var(--inset); }
.dsr-item .dsr-h { display: block; font-family: var(--font-sans); font-weight: 700; font-size: .88rem; color: var(--ink-900); }
.dsr-item .dsr-p { display: block; font-size: .72rem; font-weight: 600; color: var(--success); margin-top: 1px; }
.dsr-item .dsr-t { display: block; font-size: .8rem; color: var(--ink-500); margin-top: 3px; line-height: 1.5; }
.dsr-item mark { background: var(--butter); color: var(--ink-900); border-radius: 3px; padding: 0 2px; }
.dsr-empty { padding: 14px 12px; font-size: .86rem; color: var(--ink-500); line-height: 1.6; }
.dsr-empty a { color: var(--success); font-weight: 600; }

/* On the hub the sidebar does not exist, so the box sits in the hero instead. */
.docs-hero-search { max-width: 560px; margin: 22px auto 0; }
.docs-hero-search .dsq { height: 52px; font-size: 1rem; box-shadow: var(--sh-1); border-color: transparent; }
.docs-hero-search .dsq-ic { left: 18px; width: 18px; height: 18px; }
.docs-hero-search .dsq { padding-left: 46px; }

/* ---------- 9. Hero ---------- */
.hero { position: relative; padding-top: clamp(40px, 6vw, 72px); padding-bottom: clamp(40px, 6vw, 80px); overflow: hidden; }
.hero-grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 48px; align-items: center; }
.hero-copy .display { margin-bottom: 22px; }
.hero-copy .lead { margin-bottom: 30px; max-width: 540px; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
.hero-trust { margin-top: 34px; display: flex; align-items: center; gap: 18px; flex-wrap: wrap; color: var(--ink-500); font-size: 0.9rem; }
.hero-trust .avatars { display: flex; }
.hero-trust .avatars span { width: 34px; height: 34px; border-radius: 50%; border: 2px solid #fff; margin-left: -10px; display: grid; place-items: center; font-family: var(--font-sans); font-weight: 700; font-size: 0.8rem; color: #fff; }
.hero-trust .avatars span:first-child { margin-left: 0; }

/* hero banner (teal block, Reference A) */
.hero-banner {
  background: linear-gradient(135deg, var(--brand) 0%, #35C2A8 100%);
  border-radius: var(--r-hero); padding: 36px; color: #fff;
  box-shadow: var(--sh-3); position: relative; overflow: hidden;
}

/* ---------- 10. Showcase / mock device frames ---------- */
.browser-mock { background: #fff; border-radius: var(--r-lg); box-shadow: var(--sh-4); overflow: hidden; }
.browser-bar { display: flex; align-items: center; gap: 7px; padding: 13px 16px; background: var(--inset); border-bottom: 1px solid var(--ink-200); }
.browser-bar .dot { width: 11px; height: 11px; border-radius: 50%; }
.browser-bar .url { margin-left: 12px; background: #fff; border-radius: var(--r-pill); padding: 5px 14px; font-size: 0.78rem; color: var(--ink-500); flex: 1; max-width: 320px; }

.phone-mock { width: 250px; background: var(--ink-900); border-radius: 38px; padding: 11px; box-shadow: var(--sh-4); }
.phone-screen { background: var(--cream); border-radius: 28px; overflow: hidden; aspect-ratio: 9 / 19.2; position: relative; padding: 18px 14px; }
.phone-notch { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); width: 90px; height: 20px; background: var(--ink-900); border-radius: var(--r-pill); z-index: 5; }

/* Real product screens in the frames. The frames stay CSS so they are crisp at
   any size; only the screen is a picture, captured from the real apps by
   scripts/capture-mockups.js (assets/mockups/README.md). */
.browser-mock.shot > img { display: block; width: 100%; height: auto; background: var(--canvas); }
.phone-mock.shot .phone-screen { padding: 0; aspect-ratio: 9 / 20; background: #fff; }
.phone-mock.shot .phone-screen > img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.phone-mock.shot .phone-notch { top: 6px; width: 11px; height: 11px; }   /* a punch-hole camera, clear of the clock and icons */
.shot-crop { margin: 0; background: #fff; border-radius: var(--r-card); overflow: hidden; box-shadow: var(--sh-2); outline: 1px solid var(--ink-200); outline-offset: -1px; }
.shot-crop > img { display: block; width: 100%; height: auto; }
.shot-caption { margin-top: 12px; text-align: center; font-size: .84rem; color: var(--ink-500); }

/* A coloured stage a phone rises out of: the stage's bottom edge cuts the
   phone, so a panel shows the top of the screen without a 540px-tall device. */
.shot-stage { position: relative; display: flex; justify-content: center; align-items: flex-start; gap: 22px; padding: 36px 24px 0; border-radius: var(--r-lg); overflow: hidden; height: 440px; }
.shot-stage .phone-mock { flex: none; }
.shot-stage.pair .phone-mock + .phone-mock { margin-top: 56px; }   /* a pair: the second sits lower */
.shot-stage.tall { height: 500px; }

/* A phone laid over a corner of a browser frame: the office and the family,
   the same moment from both ends. The parent needs position: relative. */
.overlap-phone { position: absolute; right: -26px; bottom: -58px; width: 152px; padding: 7px; border-radius: 27px; z-index: 2; }
.overlap-phone .phone-screen { border-radius: 21px; }
.phone-mock.shot.overlap-phone .phone-notch { top: 4px; width: 7px; height: 7px; }
@media (max-width: 640px) {
  .overlap-phone { width: 104px; right: -8px; bottom: -34px; padding: 5px; border-radius: 19px; }
  .overlap-phone .phone-screen { border-radius: 15px; }
  .shot-stage, .shot-stage.tall { height: 380px; }
  .shot-stage .phone-mock { width: 200px; }
  /* a pair stays a pair: two smaller phones still fit a 390px screen */
  .shot-stage.pair { gap: 12px; padding: 28px 12px 0; height: 340px; }
  .shot-stage.pair .phone-mock { width: 146px; padding: 7px; border-radius: 26px; }
  .shot-stage.pair .phone-mock .phone-screen { border-radius: 20px; }
  .shot-stage.pair .phone-mock .phone-notch { top: 4px; width: 7px; height: 7px; }
  .shot-stage.pair .phone-mock + .phone-mock { margin-top: 34px; }
}

/* ---------- 11. Role / persona cards ---------- */
.persona-tabs { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-bottom: 36px; }
.persona-tab { display: inline-flex; align-items: center; gap: 9px; padding: 11px 20px; border-radius: var(--r-pill); background: #fff; box-shadow: var(--sh-1); font-family: var(--font-sans); font-weight: 700; color: var(--ink-500); transition: all .18s var(--ease-candy); }
.persona-tab svg { width: 18px; height: 18px; }
.persona-tab.active { color: #fff; transform: translateY(-1px); box-shadow: var(--sh-2); }
.persona-tab[data-persona="admin"].active { background: var(--sky); }
.persona-tab[data-persona="teacher"].active { background: var(--sunny-deep); }
.persona-tab[data-persona="parent"].active { background: var(--blossom-deep); }
.persona-tab[data-persona="driver"].active { background: var(--coral); }
.persona-panel { display: none; }
.persona-panel.active { display: block; animation: fadeUp .4s var(--ease-candy); }

/* ---------- 12. Steps / how it works ---------- */
.steps { counter-reset: step; }
.step { display: flex; gap: 20px; align-items: flex-start; }
.step .step-num { flex: none; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-sans); font-weight: 800; font-size: 1.1rem; }
.step h3 { margin-bottom: 6px; }
.step p { color: var(--ink-500); }

/* connector for vertical steps */
.steps-vertical .step { position: relative; padding-bottom: 36px; }
.steps-vertical .step:not(:last-child)::after { content: ""; position: absolute; left: 22px; top: 50px; bottom: 0; width: 2px; background: var(--ink-200); }

/* ---------- 13. Testimonials ---------- */
.quote-card { background: #fff; border-radius: var(--r-lg); padding: 30px; box-shadow: var(--sh-1); display: flex; flex-direction: column; gap: 18px; }
.quote-card .qmark { font-family: var(--font-sans); font-size: 3rem; line-height: 0.6; color: var(--brand); font-weight: 800; }
.quote-card blockquote { font-size: 1.06rem; color: var(--ink-700); line-height: 1.6; }
.quote-card .qwho { display: flex; align-items: center; gap: 12px; margin-top: auto; }
.quote-card .qwho .av { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-sans); font-weight: 700; color: #fff; }
.quote-card .qwho .qname { font-family: var(--font-sans); font-weight: 700; color: var(--ink-900); font-size: 0.95rem; }
.quote-card .qwho .qrole { color: var(--ink-500); font-size: 0.85rem; }

/* logo cloud */
.logo-cloud { display: flex; flex-wrap: wrap; gap: 14px 40px; align-items: center; justify-content: center; opacity: .9; }
.logo-cloud .lc-item { display: flex; align-items: center; gap: 9px; font-family: var(--font-sans); font-weight: 800; font-size: 1.1rem; color: var(--ink-500); letter-spacing: -0.01em; }
.logo-cloud .lc-item svg { width: 22px; height: 22px; }

/* ---------- 14. CTA band ---------- */
.cta-band { border-radius: var(--r-hero); padding: clamp(40px, 6vw, 72px); text-align: center; position: relative; overflow: hidden; box-shadow: var(--sh-3); }
.cta-band h2 { color: #fff; margin-bottom: 14px; }
.cta-band p { color: rgba(255,255,255,0.92); max-width: 560px; margin: 0 auto 28px; font-size: 1.1rem; }

/* ---------- 15. Forms ---------- */
.field { margin-bottom: 18px; }
.field label { display: block; font-family: var(--font-sans); font-weight: 600; font-size: 0.88rem; color: var(--ink-700); margin-bottom: 7px; }
.field input, .field select, .field textarea {
  width: 100%; background: #fff; border: 1.5px solid var(--ink-200);
  border-radius: var(--r-input); padding: 13px 15px; font-family: var(--font-data); font-size: 0.97rem; color: var(--ink-900);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input::placeholder, .field textarea::placeholder { color: var(--ink-500); }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 4px rgba(43,179,154,0.12); }
.field textarea { resize: vertical; min-height: 120px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* Demo form v2 — calm inset fields, icons, chip pickers */
.form-card { background: #fff; border-radius: var(--r-shell); box-shadow: var(--sh-2); overflow: hidden; }
.form-card-head {
  display: flex; align-items: center; gap: 16px;
  padding: 26px 32px;
  background: linear-gradient(115deg, var(--mint), var(--skylight) 58%, var(--lavender));
}
.form-card-head h2 { margin: 0 0 2px; font-size: 1.35rem; }
.form-card-head p { margin: 0; color: var(--ink-500); font-size: .9rem; }
.form-card-body { padding: 28px 32px 32px; }
.form-card .field input, .form-card .field select, .form-card .field textarea {
  background: var(--inset); border-color: transparent;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.form-card .field input:hover, .form-card .field select:hover, .form-card .field textarea:hover { border-color: var(--ink-200); }
.form-card .field input:focus, .form-card .field select:focus, .form-card .field textarea:focus {
  background: #fff; border-color: var(--brand); box-shadow: 0 0 0 4px rgba(43,179,154,0.12);
}
.input-wrap { position: relative; }
.input-wrap > .fi {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--ink-500); display: inline-flex; pointer-events: none;
}
.input-wrap > .fi svg { width: 17px; height: 17px; }
.input-wrap input, .input-wrap select { padding-left: 41px; }
.input-wrap input:focus ~ .fi, .input-wrap select:focus ~ .fi { color: var(--brand-deep); }
.field select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7693' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 16px;
}
.chip-group { display: flex; flex-wrap: wrap; gap: 8px; }
.chip-opt { position: relative; }
.chip-opt input { position: absolute; opacity: 0; pointer-events: none; }
.chip-opt .c {
  display: inline-flex; align-items: center; gap: 7px; padding: 9px 16px;
  border-radius: var(--r-pill); background: var(--inset); border: 1.5px solid transparent;
  font-family: var(--font-sans); font-weight: 600; font-size: .87rem; color: var(--ink-500);
  cursor: pointer; transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.chip-opt:hover .c { border-color: var(--ink-200); color: var(--ink-700); }
.chip-opt input:checked + .c { background: var(--mint); border-color: var(--brand); color: var(--teal-deep); }
.chip-opt input:focus-visible + .c { box-shadow: 0 0 0 4px rgba(43,179,154,0.12); }
/* ink-400 is 2.59:1; this is real instructional copy, so it takes ink-500. */
.form-note { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: 14px; color: var(--ink-500); font-size: .8rem; }
.form-note svg { width: 13px; height: 13px; }
.form-note:first-of-type { justify-content: flex-start; margin-top: 0; margin-bottom: 16px; }

/* Required marker and the phone-or-email hint. Requirements used to be
   discoverable only by submitting and failing. */
.req { color: var(--error); font-weight: 700; margin-left: 1px; }
/* One hint under the phone/email pair. These two used to carry "or email" and
   "or phone" inside their own labels, so each field appeared to be describing
   the other one and the rule was stated twice. It belongs once, under the pair
   it applies to. */
.row-hint {
  margin: -8px 0 18px; font-size: .82rem; color: var(--ink-500);
  display: flex; align-items: center; gap: 6px;
}
.field-err {
  display: flex; align-items: flex-start; gap: 5px;
  margin: 6px 0 0; font-size: .8rem; font-weight: 500; color: var(--error);
}
.field [aria-invalid="true"] { border-color: var(--error); }
.field [aria-invalid="true"]:focus { box-shadow: 0 0 0 4px rgba(179, 39, 26, 0.12); }

/* Contact page: side rail slightly narrower than the form */
.contact-grid { grid-template-columns: 0.9fr 1.1fr; }
@media (max-width: 960px) { .contact-grid { grid-template-columns: 1fr; } }

/* Contact page: what-happens-next timeline (compact, fits above the fold) */
.step-list { display: grid; }
.step { display: flex; gap: 14px; position: relative; padding-bottom: 16px; }
.step:last-child { padding-bottom: 0; }
.step::before { content: ""; position: absolute; left: 17px; top: 40px; bottom: 4px; width: 2px; border-radius: 2px; background: var(--ink-200); }
.step:last-child::before { display: none; }
.step .sn {
  width: 36px; height: 36px; flex: none; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--font-sans); font-weight: 800; font-size: .95rem;
}
.step h3 { margin-bottom: 2px; font-size: .98rem; }
.step p { color: var(--ink-500); font-size: .88rem; }
.step .st-tag { display: inline-block; margin-left: 8px; font-size: .72rem; font-weight: 700; color: var(--ink-500); vertical-align: 1px; }

/* Contact page: call / email channel cards */
.contact-channel-row { display: grid; grid-template-columns: auto auto; justify-content: start; gap: 12px; }
@media (max-width: 1200px) { .contact-channel-row { grid-template-columns: 1fr; } }
.contact-channel {
  display: flex; align-items: center; gap: 12px; background: #fff;
  border-radius: var(--r-card); padding: 12px 18px 12px 12px; box-shadow: var(--sh-1);
  transition: transform .2s var(--ease-candy), box-shadow .2s var(--ease-candy);
}
.contact-channel:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
.contact-channel .icon-chip { width: 42px; height: 42px; }
.contact-channel .cc-label { font-size: .74rem; color: var(--ink-500); }
.contact-channel .cc-value { font-family: var(--font-sans); font-weight: 700; font-size: .92rem; color: var(--ink-900); word-break: break-all; }
.contact-channel .cc-arrow { margin-left: auto; color: var(--ink-500); display: inline-flex; width: 18px; flex: none; }

/* Compact form so the page fits a laptop viewport without scrolling */
.form-card .field { margin-bottom: 13px; }
.form-card .field label { margin-bottom: 5px; font-size: .84rem; }
.form-card .field input, .form-card .field select { padding-top: 11px; padding-bottom: 11px; }
.form-card .field textarea { min-height: 76px; }
.form-card-head { padding: 18px 28px; }
.form-card-body { padding: 22px 28px 24px; }
.form-card .chip-opt .c { padding: 7px 13px; font-size: .84rem; }

/* ---------- 16. FAQ accordion ---------- */
.faq-item { background: #fff; border-radius: var(--r-card); box-shadow: var(--sh-1); margin-bottom: 14px; overflow: hidden; }
.faq-q { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 24px; text-align: left; font-family: var(--font-sans); font-weight: 700; font-size: 1.02rem; color: var(--ink-900); }
.faq-q .faq-ico { flex: none; width: 30px; height: 30px; border-radius: 50%; background: var(--mint); color: var(--teal-deep); display: grid; place-items: center; transition: transform .25s var(--ease-candy), background .2s ease; }
.faq-q .faq-ico svg { width: 18px; height: 18px; }
.faq-item.open .faq-q .faq-ico { transform: rotate(45deg); background: var(--brand); color: #fff; }
.faq-a { max-height: 0; overflow: hidden; transition: max-height .3s ease; }
.faq-a .faq-a-inner { padding: 0 24px 22px; color: var(--ink-500); line-height: 1.65; }

/* ---------- 17. Footer ---------- */
.site-footer { background: var(--ink-900); color: #fff; padding-block: 64px 32px; margin-top: 40px; }
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; }
.footer-brand .brand { color: #fff; margin-bottom: 16px; }
.footer-brand p { color: rgba(255,255,255,0.6); font-size: 0.92rem; max-width: 280px; }
.footer-col h4 { color: #fff; font-size: 0.82rem; letter-spacing: 0.1em; text-transform: uppercase; margin: 0 0 16px; font-weight: 700; }
.footer-col a { display: block; color: rgba(255,255,255,0.62); font-size: 0.92rem; padding: 6px 0; transition: color .15s ease; }
.footer-col a:hover { color: #fff; }
/* Native <details>, so it needs no JS and is keyboard-operable for free.
   Forced open on desktop; only a phone gets the collapsed version, where 21
   stacked links were about 40% of the height of a short page. */
.footer-col > summary { list-style: none; cursor: default; }
.footer-col > summary::-webkit-details-marker { display: none; }
.footer-col > summary::marker { content: ''; }
.footer-col > summary > h4 { display: inline-block; }
.footer-col .fc-links { display: block; }
/* 0.5 alpha on navy is 4.3:1; 0.62 clears AA at this size. */
.footer-bottom { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; margin-top: 48px; padding-top: 24px; border-top: 1px solid rgba(255,255,255,0.12); color: rgba(255,255,255,0.62); font-size: 0.86rem; }
.footer-social { display: flex; gap: 10px; }
.footer-social a { width: 38px; height: 38px; border-radius: 50%; background: rgba(255,255,255,0.08); display: grid; place-items: center; }
.footer-social a:hover { background: rgba(255,255,255,0.16); }
.footer-social svg { width: 18px; height: 18px; }

/* ---------- 18. Docs layout ---------- */
.docs-shell { display: grid; grid-template-columns: 268px 1fr; gap: 48px; align-items: start; padding-block: 48px; }
.docs-sidebar { position: sticky; top: calc(var(--nav-h) + 24px); }
.docs-sidebar .ds-group { margin-bottom: 26px; }
.docs-sidebar .ds-label { font-family: var(--font-sans); font-weight: 700; font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-500); padding: 0 14px; margin-bottom: 8px; }
.docs-sidebar a { display: flex; align-items: center; gap: 10px; padding: 9px 14px; border-radius: 14px; font-size: 0.92rem; font-weight: 600; color: var(--ink-500); transition: all .15s ease; }
.docs-sidebar a svg { width: 17px; height: 17px; }
.docs-sidebar a:hover { background: var(--inset); color: var(--ink-900); }
.docs-sidebar a.active { background: #fff; color: var(--ink-900); box-shadow: var(--sh-2); }
.docs-sidebar a.active svg { color: var(--brand-deep); }

.docs-shell.with-toc { grid-template-columns: 250px 1fr 196px; gap: 40px; }
@media (max-width: 1180px) { .docs-shell.with-toc { grid-template-columns: 250px 1fr; } .docs-shell.with-toc .toc { display: none; } }
@media (max-width: 1024px) { .docs-shell.with-toc { grid-template-columns: 1fr; } }

.docs-breadcrumb { display: flex; align-items: center; gap: 8px; font-size: 0.84rem; color: var(--ink-500); margin-bottom: 20px; flex-wrap: wrap; }
.docs-breadcrumb a { color: var(--ink-500); font-weight: 600; }
.docs-breadcrumb a:hover { color: var(--brand-deep); }
.docs-breadcrumb svg { width: 14px; height: 14px; }

.docs-toggle-btn { display: none; margin-bottom: 20px; }
@media (max-width: 1024px) { .docs-toggle-btn { display: inline-flex; } }

.docs-prevnext { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 48px; }
.docs-prevnext a { display: block; background: #fff; border-radius: var(--r-card); padding: 18px 20px; box-shadow: var(--sh-1); transition: transform .18s var(--ease-candy), box-shadow .18s var(--ease-candy); }
.docs-prevnext a:hover { transform: translateY(-3px); box-shadow: var(--sh-2); }
.docs-prevnext .pn-label { font-size: 0.74rem; color: var(--ink-500); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; }
.docs-prevnext .pn-title { font-family: var(--font-sans); font-weight: 700; color: var(--ink-900); margin-top: 4px; }
.docs-prevnext a.next { text-align: right; }
@media (max-width: 560px) { .docs-prevnext { grid-template-columns: 1fr; } }

.docs-content { min-width: 0; max-width: 820px; }
.docs-content h1 { font-size: clamp(2rem, 3.4vw, 2.6rem); margin-bottom: 14px; }
.docs-content h2 { font-size: 1.5rem; margin-top: 44px; margin-bottom: 14px; scroll-margin-top: calc(var(--nav-h) + 20px); }
.docs-content h3 { font-size: 1.15rem; margin-top: 28px; margin-bottom: 10px; }
.docs-content p { margin-bottom: 16px; color: var(--ink-700); }
.docs-content ul.bullets { margin: 0 0 18px; padding-left: 0; }
.docs-content ul.bullets li { position: relative; padding-left: 28px; margin-bottom: 10px; color: var(--ink-700); }
.docs-content ul.bullets li::before { content: ""; position: absolute; left: 4px; top: 9px; width: 8px; height: 8px; border-radius: 50%; background: var(--brand); }
.docs-content .lead { margin-bottom: 28px; }
.docs-content code { font-family: 'Inter', monospace; background: var(--inset); border: 1px solid var(--ink-200); border-radius: 8px; padding: 2px 7px; font-size: 0.86em; color: var(--coral-deep); }
.docs-content a.inline-link { color: var(--brand-deep); font-weight: 600; border-bottom: 1.5px solid rgba(43,179,154,0.3); }
.docs-content a.inline-link:hover { border-bottom-color: var(--brand); }

.callout { display: flex; gap: 14px; border-radius: var(--r-card); padding: 18px 20px; margin: 22px 0; }
.callout .icon-chip { width: 38px; height: 38px; border-radius: 11px; }
.callout .icon-chip svg { width: 20px; height: 20px; }
.callout-body { font-size: 0.94rem; }
.callout-body strong { color: var(--ink-900); font-family: var(--font-sans); }
.callout-tip { background: var(--mint); }
.callout-tip .callout-body { color: var(--teal-deep); }
.callout-info { background: var(--skylight); }
.callout-info .callout-body { color: var(--sky-deep); }
.callout-warn { background: var(--butter); }
.callout-warn .callout-body { color: var(--sunny-deep); }

/* numbered guide steps */
.guide-steps { counter-reset: gstep; margin: 24px 0; }
.guide-step { display: flex; gap: 18px; padding: 20px 0; border-bottom: 1px solid var(--ink-200); }
.guide-step:last-child { border-bottom: none; }
.guide-step::before { counter-increment: gstep; content: counter(gstep); flex: none; width: 38px; height: 38px; border-radius: 50%; background: var(--brand); color: #fff; font-family: var(--font-sans); font-weight: 800; display: grid; place-items: center; }
.guide-step .gs-body h3 { margin-top: 0; margin-bottom: 6px; }
.guide-step .gs-body p { margin-bottom: 0; color: var(--ink-500); }

/* docs cards grid (hub) */
.doc-card { display: block; background: #fff; border-radius: var(--r-lg); padding: 26px; box-shadow: var(--sh-1); transition: transform .2s var(--ease-candy), box-shadow .2s var(--ease-candy); }
.doc-card:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
.doc-card .icon-chip { margin-bottom: 16px; }
.doc-card h3 { margin-bottom: 6px; }
.doc-card p { color: var(--ink-500); font-size: 0.92rem; margin-bottom: 14px; }
.doc-card .dc-link { font-family: var(--font-sans); font-weight: 700; font-size: 0.9rem; color: var(--brand-deep); display: inline-flex; align-items: center; gap: 6px; }

/* on this page (toc) */
.toc { position: sticky; top: calc(var(--nav-h) + 24px); }
.toc .toc-label { font-family: var(--font-sans); font-weight: 700; font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-500); margin-bottom: 12px; }
.toc a { display: block; padding: 5px 0 5px 14px; border-left: 2px solid var(--ink-200); font-size: 0.86rem; color: var(--ink-500); }
.toc a:hover, .toc a.active { color: var(--brand-deep); border-left-color: var(--brand); }

/* ---------- 19. Decorative blobs ---------- */
.blob { position: absolute; border-radius: 50%; filter: blur(50px); opacity: 0.5; z-index: -1; pointer-events: none; }
.blob-teal { background: var(--mint); }
.blob-coral { background: var(--peach); }
.blob-sunny { background: var(--butter); }
.blob-sky { background: var(--skylight); }
.blob-grape { background: var(--lavender); }

/* dotted grid bg accent */
.dots-bg { background-image: radial-gradient(var(--ink-200) 1.4px, transparent 1.4px); background-size: 22px 22px; }

/* ---------- 20. Animations ---------- */
@keyframes fadeUp { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
@keyframes floaty { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
@keyframes pulseRing { 0% { box-shadow: 0 0 0 0 rgba(43,179,154,0.35); } 70% { box-shadow: 0 0 0 16px rgba(43,179,154,0); } 100% { box-shadow: 0 0 0 0 rgba(43,179,154,0); } }
@keyframes spinSlow { to { transform: rotate(360deg); } }

.float { animation: floaty 6s ease-in-out infinite; }
.float-slow { animation: floaty 9s ease-in-out infinite; }
.pulse-ring { animation: pulseRing 2.2s var(--ease-candy) infinite; }

/* scroll reveal */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity .6s var(--ease-candy), transform .6s var(--ease-candy); }
.reveal.in { opacity: 1; transform: none; }
.reveal-delay-1 { transition-delay: .08s; }
.reveal-delay-2 { transition-delay: .16s; }
.reveal-delay-3 { transition-delay: .24s; }
.reveal-delay-4 { transition-delay: .32s; }

/* ---------- 21. Responsive ---------- */
@media (max-width: 1024px) {
  .hero-grid { grid-template-columns: 1fr; gap: 36px; }
  .hero-visual { order: -1; }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1.4fr 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }
  .docs-shell { grid-template-columns: 1fr; }
  .docs-sidebar { position: static; display: none; }
  .docs-sidebar.mobile-show { display: block; }
}

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-toggle { display: grid; }
  /* "Sign in" used to be display:none here, so a returning customer on a phone
     had to open the hamburger to find the one thing they came for. It stays,
     as a compact text link rather than a second competing pill. */
  .nav-cta .btn-secondary {
    background: transparent; border: 0; box-shadow: none;
    padding: 10px 6px; min-height: 40px; font-size: .9rem; color: var(--ink-700);
  }
  .nav-cta .btn-secondary:hover { background: transparent; color: var(--success); transform: none; }
  .grid-3 { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
  .field-row { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .section { padding-block: 56px; }
}

/* Footer accordions: collapsed only below 720px. Above that the <details>
   panels are forced open so the footer stays a normal three-column sitemap. */
@media (min-width: 721px) {
  .footer-col .fc-links { display: block !important; }
}
@media (max-width: 720px) {
  .footer-grid { grid-template-columns: 1fr; gap: 4px; }
  .footer-brand { margin-bottom: 18px; }
  .footer-col { border-top: 1px solid rgba(255,255,255,0.12); }
  .footer-col > summary {
    display: flex; align-items: center; justify-content: space-between;
    cursor: pointer; padding: 15px 0; min-height: 48px;
  }
  .footer-col > summary > h4 { margin: 0; }
  .footer-col > summary::after {
    content: ''; width: 9px; height: 9px; flex: none; margin-right: 4px;
    border-right: 2px solid rgba(255,255,255,0.55);
    border-bottom: 2px solid rgba(255,255,255,0.55);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s var(--ease-candy);
  }
  .footer-col[open] > summary::after { transform: rotate(-135deg) translate(-3px, -3px); }
  .footer-col .fc-links { padding-bottom: 10px; }
  .site-footer { padding-block: 40px 28px; }
}

@media (max-width: 560px) {
  .grid-4 { grid-template-columns: 1fr 1fr; }
  .container { padding-inline: 18px; }
  .hero-actions .btn { width: 100%; }
  .cta-band .btn { width: 100%; }
  .footer-grid { grid-template-columns: 1fr; }
  /* keep brand + CTA + toggle inside a ~390px viewport */
  .nav { gap: 8px; }
  .nav-cta { gap: 8px; }
  .nav-cta .btn { padding: 10px 14px; min-height: 40px; font-size: .85rem; }
  .nav-toggle { width: 40px; height: 40px; }
}

/* reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- 22. Product mockups (marketing visuals) ---------- */
/* The product mockups mirror the real console, so they take navy on the brand
   fill for the same reason the console does. Leaving them white-on-teal would
   advertise a screen that no longer exists. */
.mock-hero {
  background: linear-gradient(135deg, var(--brand) 0%, #35C2A8 100%);
  border-radius: 18px; padding: 18px 20px; color: var(--on-candy); position: relative; overflow: hidden;
}
.mock-hero h4 { color: var(--on-candy); font-size: 1.05rem; margin-bottom: 4px; }
.mock-hero p { font-size: 0.78rem; color: rgba(31,43,77,0.78); margin-bottom: 12px; }
.mock-chip-stats { display: flex; gap: 10px; }
.mock-chip-stat { display: flex; align-items: center; gap: 8px; background: rgba(255,255,255,0.42); border-radius: var(--r-pill); padding: 6px 12px; font-size: 0.75rem; font-weight: 700; color: var(--on-candy); }
.mock-chip-stat span.dot { width: 22px; height: 22px; border-radius: 50%; background: rgba(255,255,255,0.55); display: grid; place-items: center; }
.mock-chip-stat svg { width: 13px; height: 13px; }

.mini-stat { border-radius: 16px; padding: 14px 16px; box-shadow: var(--sh-1); }
.mini-stat .ms-num { font-family: var(--font-sans); font-weight: 800; font-size: 1.6rem; line-height: 1; }
.mini-stat .ms-label { font-size: 0.72rem; font-weight: 600; opacity: 0.9; margin-top: 4px; }

.mock-card { background: #fff; border-radius: 16px; padding: 14px; box-shadow: var(--sh-1); }
/* The search pill above a person card — mirrors the portal's own /search box. */
.mock-search { display: flex; align-items: center; gap: 10px; background: var(--inset); border-radius: var(--r-pill); padding: 11px 16px; margin-bottom: 16px; font-family: var(--font-sans); font-weight: 600; font-size: .9rem; color: var(--ink-700); }
.mock-search svg { width: 16px; height: 16px; color: var(--ink-400); flex: none; }
.mock-chart { display: flex; align-items: flex-end; gap: 8px; height: 76px; }
.mock-bar { flex: 1; border-radius: 6px 6px 3px 3px; background: var(--brand); opacity: 0.85; }

.mock-row { display: flex; align-items: center; gap: 11px; padding: 9px 0; }
.mock-row + .mock-row { border-top: 1px solid var(--ink-200); }
.mock-row .mr-ic { width: 34px; height: 34px; border-radius: 10px; flex: none; display: grid; place-items: center; }
.mock-row .mr-ic svg { width: 17px; height: 17px; }
.mock-row .mr-body { flex: 1; min-width: 0; }
.mock-row .mr-title { font-family: var(--font-sans); font-weight: 700; font-size: 0.82rem; color: var(--ink-900); }
.mock-row .mr-sub { font-size: 0.72rem; color: var(--ink-500); }
.mock-row .mr-pill { font-size: 0.68rem; font-weight: 700; padding: 4px 10px; border-radius: var(--r-pill); }

/* live dot */
.live-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--teal); position: relative; flex: none; }
.live-dot::after { content: ""; position: absolute; inset: -5px; border-radius: 50%; border: 2px solid var(--teal); opacity: 0; animation: pulseRing 2s var(--ease-candy) infinite; }

/* faux live map */
.map-mock { position: relative; background:
    radial-gradient(circle at 20% 30%, rgba(43,179,154,0.10), transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(244,117,107,0.10), transparent 40%),
    var(--mint);
  overflow: hidden; }
.map-mock .road { position: absolute; background: rgba(255,255,255,0.85); }
.map-mock .route { position: absolute; border: 2.5px dashed var(--brand); border-radius: 40% 60% 50% 50%; opacity: 0.7; }
.map-mock .stop { position: absolute; width: 16px; height: 16px; border-radius: 50%; background: #fff; border: 3px solid var(--ink-400); transform: translate(-50%, -50%); }
.map-mock .stop.done { border-color: var(--teal); }
.map-mock .stop.you { border-color: var(--tangerine); width: 18px; height: 18px; }
.map-mock .van-pin { position: absolute; width: 36px; height: 36px; border-radius: 50%; background: var(--coral); display: grid; place-items: center; box-shadow: var(--sh-3); transform: translate(-50%, -50%); color: #fff; }
.map-mock .van-pin svg { width: 20px; height: 20px; }

/* boarded banner */
.van-banner { display: flex; align-items: center; gap: 10px; background: var(--mint); color: var(--teal-deep); border-radius: 16px; padding: 11px 15px; font-family: var(--font-sans); font-weight: 700; font-size: 0.86rem; box-shadow: var(--sh-2); }
.van-banner .vb-ic { width: 28px; height: 28px; border-radius: 50%; background: var(--teal); color: #fff; display: grid; place-items: center; flex: none; }
.van-banner .vb-ic svg { width: 17px; height: 17px; }

/* floating accent card */
.float-card { position: absolute; background: #fff; border-radius: 16px; box-shadow: var(--sh-3); padding: 12px 14px; }

/* week strip (mobile) */
.week-strip { display: flex; gap: 6px; justify-content: space-between; }
.week-strip .wd { text-align: center; flex: 1; }
.week-strip .wd .wl { font-size: 0.62rem; font-weight: 700; color: var(--ink-400); }
.week-strip .wd .wn { width: 28px; height: 28px; margin: 4px auto 0; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-sans); font-weight: 700; font-size: 0.76rem; color: var(--ink-700); }
.week-strip .wd.sel .wn { background: var(--tangerine); color: #fff; }
.week-strip .wd.done .wn { background: var(--mint); color: var(--teal-deep); }

/* stat strip (mobile, Reference B) */
.stat-strip { display: flex; border-radius: 18px; overflow: hidden; }
.stat-strip .ss-cell { flex: 1; padding: 14px 10px; text-align: center; color: #fff; }
.stat-strip .ss-cell + .ss-cell { border-left: 1px solid rgba(255,255,255,0.25); }
.stat-strip .ss-num { font-family: var(--font-sans); font-weight: 800; font-size: 1.3rem; }
.stat-strip .ss-label { font-size: 0.64rem; opacity: 0.9; margin-top: 2px; }

/* comparison check/cross lists */
.compare-list li { display: flex; align-items: flex-start; gap: 11px; padding: 9px 0; color: var(--ink-700); font-size: 0.96rem; }
.compare-list li .ci { width: 24px; height: 24px; border-radius: 50%; flex: none; display: grid; place-items: center; margin-top: 1px; }
.compare-list li .ci svg { width: 15px; height: 15px; }
.compare-list li .ci.yes { background: var(--mint); color: var(--teal-deep); }
.compare-list li .ci.no { background: var(--peach); color: var(--coral-deep); }

/* mobile bottom-nav mock */
.mock-bnav { display: flex; justify-content: space-between; background: #fff; border-radius: var(--r-pill); padding: 9px 14px; box-shadow: var(--sh-2); }
.mock-bnav .bn { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; color: var(--ink-400); }
.mock-bnav .bn svg { width: 18px; height: 18px; }
.mock-bnav .bn.on { background: var(--mint); color: var(--teal-deep); }

/* section background variants */
.bg-cream { background: var(--cream); }
.bg-inset { background: var(--inset); }
.bg-panel { background: #fff; }
.bg-ink { background: var(--ink-900); }
.bg-ink h2, .bg-ink h3, .bg-ink .display { color: #fff; }
.bg-ink p, .bg-ink .lead { color: rgba(255,255,255,0.7); }

/* rounded panel (Reference A outer shell vibe) */
.shell-panel { background: #fff; border-radius: var(--r-shell); box-shadow: var(--sh-2); padding: clamp(28px, 4vw, 56px); }

/* ---------- 23. Permissions matrix table ---------- */
.perm-wrap { overflow-x: auto; border-radius: var(--r-lg); box-shadow: var(--sh-1); background: #fff; }
.perm-table { width: 100%; border-collapse: collapse; min-width: 720px; }
/* `position: relative` contains the visually-hidden access labels. `.sr-only`
   is absolutely positioned, and without a positioned ancestor its containing
   block is the page, not the cell, so `.perm-wrap`'s overflow could not clip
   it and 200 of them dragged the page out to 999px wide on a phone. */
.perm-table th, .perm-table td { position: relative; padding: 13px 14px; text-align: center; border-bottom: 1px solid var(--ink-200); }
.perm-table thead th { background: var(--inset); font-family: var(--font-sans); font-weight: 700; font-size: 0.8rem; color: var(--ink-700); white-space: nowrap; }
.perm-table thead th:first-child { text-align: left; }
.perm-table tbody th { text-align: left; font-family: var(--font-data); font-weight: 600; color: var(--ink-900); font-size: 0.92rem; white-space: nowrap; }
.perm-table tbody tr:last-child td, .perm-table tbody tr:last-child th { border-bottom: none; }
.perm-table tbody tr:hover { background: rgba(43, 179, 154, 0.045); }
/* Access marks. These are sized OUTSIDE `.perm-table` on purpose: the legend
   above the table uses the same three classes, and while the sizing was scoped
   to the table its SVGs inherited no width at all and rendered at 0x0. The key
   that decodes 160 icon-only cells was invisible. */
.yes { color: var(--access-yes); display: inline-flex; }
.yes svg { width: 19px; height: 19px; }
.no { color: var(--access-no); display: inline-flex; }
.no svg { width: 16px; height: 16px; }
.partial { color: var(--access-partial); display: inline-flex; }
.partial svg { width: 17px; height: 17px; }

/* The first column stays put while the ten role columns scroll under it.
   Without this a phone shows anonymous columns of ticks with no row label. */
.perm-table tbody th, .perm-table thead th:first-child {
  position: sticky; left: 0; z-index: 1;
  box-shadow: 1px 0 0 var(--ink-200);
}
.perm-table tbody th { background: #fff; }
.perm-table tbody tr:hover th { background: #F4FBF9; }

/* role spotlight card */
.role-card { background: #fff; border-radius: var(--r-lg); box-shadow: var(--sh-1); padding: 26px; height: 100%; }
.role-card .role-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.role-card .role-head h3 { margin: 0; }
.role-card .role-head .role-where { font-size: 0.78rem; color: var(--ink-500); font-weight: 600; }
.role-card .can-list li { display: flex; align-items: flex-start; gap: 10px; padding: 6px 0; font-size: 0.92rem; color: var(--ink-700); }
.role-card .can-list li svg { width: 17px; height: 17px; color: var(--teal-deep); flex: none; margin-top: 3px; }

/* outcome / ROI stat */
.outcome { text-align: center; padding: 26px 18px; }
.outcome .o-num { font-family: var(--font-sans); font-weight: 800; font-size: clamp(2.2rem, 4vw, 3rem); line-height: 1; letter-spacing: -0.03em; }
.outcome .o-label { color: var(--ink-700); font-weight: 600; margin-top: 10px; }
.outcome .o-sub { color: var(--ink-500); font-size: 0.86rem; margin-top: 4px; }

/* timeline / process */
.timeline { position: relative; }
.timeline .tl-item { display: flex; gap: 20px; padding-bottom: 30px; position: relative; }
.timeline .tl-item:not(:last-child)::after { content: ""; position: absolute; left: 23px; top: 52px; bottom: 0; width: 2px; background: var(--ink-200); }
.timeline .tl-dot { flex: none; width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-sans); font-weight: 800; color: #fff; z-index: 1; }
.timeline .tl-body h3 { margin-bottom: 6px; }
.timeline .tl-body p { color: var(--ink-500); margin: 0; }

/* big pull quote */
.pullquote { font-family: var(--font-sans); font-weight: 800; font-size: clamp(1.4rem, 2.6vw, 2.1rem); line-height: 1.3; letter-spacing: -0.02em; color: var(--ink-900); }

/* check chip list (2-col friendly) */
.chk-list li { display: flex; align-items: flex-start; gap: 11px; padding: 8px 0; color: var(--ink-700); }
.chk-list li > span.k { width: 24px; height: 24px; border-radius: 50%; background: var(--mint); color: var(--success); flex: none; display: grid; place-items: center; margin-top: 1px; }
/* Two columns, but only where two columns fit. This was an inline
   `columns:2` that never collapsed, so the list ran 51px past the right edge
   of a 390px phone and took the whole page into horizontal scroll with it. */
.cols-2 { columns: 2; column-gap: 28px; }
.cols-2 > li { break-inside: avoid; }
@media (max-width: 620px) { .cols-2 { columns: 1; } }
.chk-list li > span.k svg { width: 14px; height: 14px; }

/* ---------- 25. Guide screenshots ---------- */
/* A screenshot inside a docs article. The main column caps at 820px, so a
   1920px-wide capture lands at roughly 40% scale: readable as a shape, not as
   text. Caption the point rather than expecting anyone to read the pixels. */
.docs-shot { margin: 26px 0 30px; }
.docs-shot img {
  display: block; width: 100%; height: auto;
  border-radius: var(--r-card); box-shadow: var(--sh-2);
  background: var(--inset);
}
.docs-shot figcaption {
  margin-top: 12px; font-size: 0.86rem; line-height: 1.55; color: var(--ink-500);
}
.docs-shot figcaption strong { color: var(--ink-900); font-family: var(--font-sans); }

/* print */
@media print { .site-header, .site-footer, .nav-toggle { display: none; } }

/* ---------- 20. Motion system (anime.js + motion.js) ---------- */

/* Cross-page fade (View Transitions API, progressive enhancement) */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation-duration: .18s; }
::view-transition-new(root) { animation-duration: .26s; }

/* Scroll progress bar */
.mo-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 120;
  background: linear-gradient(90deg, var(--teal), var(--sunny), var(--coral), var(--grape));
  transform-origin: 0 50%; transform: scaleX(0); pointer-events: none;
}

/* Split-word headline (spans injected by motion.js) */
.mo-w { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: .08em; margin-bottom: -.08em; }
.mo-wi { display: inline-block; will-change: transform; }

/* Shimmering gradient text on hero highlights.
   The travelling rainbow is kept, deliberately. What changed is the five stops:
   the originals ran 2.73:1 (sky) to 4.23:1 (grape) against white, so the key
   phrase of every headline was below AA at every point in the sweep. These are
   the SAME five hues deepened until the worst point reads 4.61:1, so the effect
   is unchanged to look at and the words are legible the whole way round. */
.mo-shine {
  background: linear-gradient(100deg,
    var(--shine-1) 0%, var(--shine-2) 28%, var(--shine-3) 52%, var(--shine-4) 74%, var(--shine-1) 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: moShine 7s linear infinite;
}
@keyframes moShine { from { background-position: 0% 50%; } to { background-position: -260% 50%; } }

/* Rotating word */
.mo-rotate {
  display: inline-block; position: relative; overflow: hidden;
  vertical-align: bottom; white-space: nowrap;
  color: var(--brand-deep); font-weight: 700;
  padding-bottom: .06em; margin-bottom: -.06em;
}
.mo-rotate .mo-rw { display: inline-block; will-change: transform; }

/* Morphing background blob (SVG injected into heroes) */
.mo-morph {
  position: absolute; z-index: -1; pointer-events: none;
  width: min(56vw, 720px); height: min(56vw, 720px);
  top: -12%; right: -14%; opacity: .5;
}
.mo-morph.alt { right: auto; left: -16%; top: auto; bottom: -22%; opacity: .34; }

/* Candy sprinkles (generated by motion.js) */
.mo-sprinkles { position: absolute; inset: 0; overflow: hidden; z-index: -1; pointer-events: none; }
.mo-sp { position: absolute; will-change: transform; }
.mo-sp i { display: block; will-change: transform; }
.mo-sp .dot { width: 10px; height: 10px; border-radius: 50%; }
.mo-sp .ring { width: 14px; height: 14px; border-radius: 50%; background: transparent !important; border: 3px solid; }
.mo-sp .sq { width: 10px; height: 10px; border-radius: 3px; transform: rotate(18deg); }
.mo-sp .tri { width: 0; height: 0; background: transparent !important; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 12px solid; border-bottom-color: inherit; }

/* Richer default reveal (staggered per-sibling by motion.js) */
.reveal { opacity: 0; transform: translateY(26px) scale(.985); transition: opacity .7s var(--ease-candy), transform .7s var(--ease-candy); }
.reveal.in { opacity: 1; transform: none; }

/* Reduced motion: everything readable, nothing moves */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .float, .float-slow, .pulse-ring, .mo-shine, .mo-track { animation: none !important; }
  .mo-shine { -webkit-text-fill-color: var(--shine-rest); color: var(--shine-rest); background: none; }
  .mo-progress, .mo-sprinkles, .mo-morph { display: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ---------- 24. Interaction tier (live.js) ----------
   EVERY rule below is scoped under `body.mo-live`, a class live.js adds
   to itself. With JS off, or reduced-motion on (site.js never loads the
   motion layer then), none of this applies and the page renders exactly
   as the sections above describe it. */

/* -- The van's route. The decorative dashed ellipse is hidden by live.js
      once this polyline replaces it, so a map never shows two routes. -- */
/* z-index 1 puts the route above the map's white road bands (which are
   semi-transparent and would otherwise wash a stripe across it) and
   below the stops and the van. */
.mo-vroute { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 1; }
.mo-vroute polyline { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.mo-vroute-base { stroke: var(--brand); stroke-width: 2.5; stroke-dasharray: 6 7; opacity: .38; }
.mo-vroute-run { stroke: var(--brand); stroke-width: 3.5; opacity: .95; }
/* The map's own markers must sit above the line it drives along. */
.mo-live .map-mock .stop, .mo-live .map-mock .van-pin { z-index: 2; }
.mo-live .map-mock .stop { transition: border-color .35s var(--ease-candy), background .35s var(--ease-candy); }
.mo-live .map-mock .stop.done { background: var(--mint); }
.mo-live .map-mock .stop.mo-stop-hit { border-color: var(--teal); background: var(--teal); box-shadow: 0 0 0 6px rgba(43, 179, 154, .22); }
.mo-live .map-mock .van-pin { transition: none; }

/* Boarding alert landing. The chip keeps its authored teal in both
   states: the glyph (pin → tick) and the lift carry the change, and a
   grey chip only muddied the mint banner it sits on. */
.mo-live .van-banner { transition: box-shadow .4s var(--ease-candy); }
.mo-live .van-banner.mo-vb-hot { box-shadow: var(--sh-3); }

/* -- Pointer-reactive cards: a few degrees of turn, plus a soft
      highlight that tracks the cursor. -- */
.mo-live .mo-tilt { position: relative; transform-style: preserve-3d; will-change: transform; }
.mo-live .mo-tilt::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(340px circle at var(--mo-x, 50%) var(--mo-y, 50%), rgba(255, 255, 255, .55), transparent 62%);
  opacity: 0; transition: opacity .28s ease;
}
.mo-live .mo-tilt:hover::after { opacity: 1; }
/* Solid candy blocks are already saturated; a white wash on them muddies
   the fill, so they get a gentle darkening instead. */
.mo-live .stat-block.mo-tilt::after {
  background: radial-gradient(320px circle at var(--mo-x, 50%) var(--mo-y, 50%), rgba(255, 255, 255, .28), transparent 60%);
}

/* -- Magnetic buttons, with a single sheen sweep on hover. -- */
.mo-live .mo-mag { position: relative; overflow: hidden; }
.mo-live .mo-mag::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: -60%; width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .45), transparent);
  transform: skewX(-18deg); pointer-events: none; opacity: 0;
}
.mo-live .mo-mag:hover::after { opacity: 1; animation: moSheen .75s var(--ease-candy); }
@keyframes moSheen { from { left: -60%; } to { left: 130%; } }
/* The secondary button is white; a white sheen is invisible on it. */
.mo-live .btn-secondary.mo-mag::after, .mo-live .btn-white.mo-mag::after {
  background: linear-gradient(100deg, transparent, rgba(43, 179, 154, .20), transparent);
}

/* -- Icon chips answer a hover on the card that owns them. -- */
@keyframes moWobble { 0%, 100% { transform: rotate(0) scale(1); } 30% { transform: rotate(-7deg) scale(1.08); } 65% { transform: rotate(5deg) scale(1.04); } }
.mo-live .feature-card:hover .icon-chip,
.mo-live .card-hover:hover .icon-chip,
.mo-live .doc-card:hover .icon-chip,
.mo-live .contact-channel:hover .icon-chip { animation: moWobble .62s var(--ease-candy); }

/* -- Scroll-linked timeline fill. The grey connector says how far the
      story runs; this says how far the reader has come. -- */
.mo-live .timeline > .mo-tl-fill, .mo-live .steps-vertical > .mo-tl-fill {
  position: absolute; top: 52px; bottom: 30px; width: 2px; z-index: 0;
  background: linear-gradient(180deg, var(--brand), var(--sky));
  transform: scaleY(0); transform-origin: 50% 0; pointer-events: none;
}
.mo-live .timeline > .mo-tl-fill { left: 23px; }
.mo-live .steps-vertical > .mo-tl-fill { left: 22px; top: 50px; bottom: 36px; }

/* -- Drifting gradient panels (background-size is set inline by live.js,
      because several of these carry an inline `background:` shorthand). -- */
@keyframes moDrift { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
.mo-live .mo-drift { animation: moDrift 16s ease-in-out infinite; }

/* -- Module ribbon: a continuously moving band of what a school gets.
      live.js clones the track, so one copy is authored in the HTML. -- */
.mo-marquee { display: flex; overflow: hidden; gap: 14px; user-select: none; }
.mo-marquee-track { display: flex; gap: 14px; flex: none; min-width: 100%; padding-right: 14px; }
.mo-live .mo-marquee { -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.mo-live .mo-marquee .mo-marquee-track { animation: moMarquee 52s linear infinite; }
.mo-live .mo-marquee.rev .mo-marquee-track { animation-direction: reverse; animation-duration: 64s; }
.mo-live .mo-marquee:hover .mo-marquee-track,
.mo-live .mo-marquee.mo-paused .mo-marquee-track { animation-play-state: paused; }
@keyframes moMarquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.mo-chip {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  background: #fff; border-radius: var(--r-pill); padding: 9px 17px;
  box-shadow: var(--sh-1); font-family: var(--font-sans); font-weight: 700;
  font-size: .86rem; color: var(--ink-700); white-space: nowrap;
}
.mo-chip svg { width: 16px; height: 16px; }
.mo-chip .mo-chip-ic { display: inline-flex; color: var(--brand-deep); }
.mo-chip:nth-child(3n+2) .mo-chip-ic { color: var(--coral-deep); }
.mo-chip:nth-child(3n+3) .mo-chip-ic { color: var(--sky-deep); }
.mo-chip:nth-child(5n+4) .mo-chip-ic { color: var(--grape-deep); }
.mo-chip:nth-child(7n+5) .mo-chip-ic { color: var(--sunny-deep); }

/* -- Header condenses as you leave the top of the page. -- */
.mo-live .site-header { transition: border-color .2s ease, box-shadow .2s ease, height .25s var(--ease-candy), background .25s ease; }
.mo-live .site-header.scrolled { height: 64px; }
/* The brand mark's two dots drift apart on hover. */
.mo-live .brand .logo-mark { transition: transform .32s var(--ease-candy); }
.mo-live .brand:hover .logo-mark { transform: translateY(-2px); }

/* -- Footer links get an underline that draws in. The anchor stays block
   (one link per line); fit-content keeps the underline to the text width. -- */
.mo-live .footer-col a { position: relative; display: block; width: fit-content; }
.mo-live .footer-col a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 4px; height: 1.5px;
  background: currentColor; transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .28s var(--ease-candy);
}
.mo-live .footer-col a:hover::after { transform: scaleX(1); }

/* -- Back to top (injected by site.js, so it survives reduced motion). -- */
.to-top {
  position: fixed; right: 22px; bottom: 22px; z-index: 110;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--ink-900); color: #fff; display: grid; place-items: center;
  box-shadow: var(--sh-3); opacity: 0; visibility: hidden; transform: translateY(14px) scale(.9);
  transition: opacity .25s ease, transform .25s var(--ease-candy), visibility .25s;
}
.to-top.show { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { background: var(--brand-deep); }
.to-top svg { width: 20px; height: 20px; }
@media (max-width: 560px) { .to-top { right: 14px; bottom: 14px; width: 42px; height: 42px; } }

/* -- Reduced motion. live.js never runs in that case, so `.mo-live` is
      absent and almost nothing here can apply; these are the belt-and-
      braces for a visitor who flips the setting mid-visit. -- */
@media (prefers-reduced-motion: reduce) {
  .mo-live .mo-drift, .mo-live .mo-marquee .mo-marquee-track,
  .mo-live .mo-mag:hover::after, .mo-live .feature-card:hover .icon-chip,
  .mo-live .card-hover:hover .icon-chip, .mo-live .doc-card:hover .icon-chip { animation: none !important; }
  .mo-live .mo-tilt { transform: none !important; }
  .to-top { transition: none; }
}

/* Accessibility: skip-to-content link (visually hidden until focused) + the no-JS
   navigation fallback (the real header is JS-injected). */
/* Visually hidden, still announced. The permissions matrix carried its whole
   meaning in `aria-hidden` icons, so 160 cells read as nothing at all. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.skip-link{position:absolute;left:-9999px;top:0;z-index:2000;background:#0F6B57;color:#fff;padding:10px 16px;border-radius:0 0 10px 0;font-weight:700;text-decoration:none}
.skip-link:focus{left:0}
.noscript-nav{padding:12px 20px;background:#F6F6F4;border-bottom:1px solid #E3E7EF;font-size:14px;color:#3D4A6B}
.noscript-nav a{color:#1E967F;text-decoration:none;font-weight:600}
.noscript-nav a:hover{text-decoration:underline}
