/* ═══════════════════════════════════════════════════════════════════════════
   SummerScope — the site's stylesheet.
   Extracted from index.html/landing.html, which each carried their own copy
   and drifted apart. One file means a mobile fix or a colour change lands on
   every page at once.

   Two things shape everything below:

   1. DARK IS THE DEFAULT. The tokens on bare :root are the dark palette, and
      :root[data-theme="light"] overrides them. It is deliberately NOT keyed to
      prefers-color-scheme: the site opens dark for everyone, and the nav toggle
      (persisted in localStorage) is the only thing that changes it.

   2. MOBILE IS THE BASE. Every rule outside a media query targets a phone.
      Wider screens add to it in min-width blocks. The old sheet did the
      opposite — desktop first, with a single 680px block undoing it — which is
      why the phone layout kept regressing.
   ═══════════════════════════════════════════════════════════════════════════ */

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

/* ── THE PALETTE ──────────────────────────────────────────────────────────────
   Third pass, and the first two failed for the same underlying reason: the
   GREYSCALE was carrying the brand hue. Navy-tinted greys read as a stock AI
   dashboard; warm-beige greys under a terracotta accent read as somebody
   else's product. Either way the neutrals were doing identity work, which is
   the one job they are bad at.

   So the greys here are genuinely neutral — hue 197°, chroma 0.004, which is
   below the level where a cast is visible on any calibrated screen — and a
   single accent carries the whole identity.

   That accent is deep teal at 197°: far from the navy of the first attempt
   (257°) and far from the terracotta of the second (46°). It also leaves the
   semantic green at 155° free to mean "free / open" without competing with the
   button colour — 42° of separation between "this is interactive" and "this
   program costs nothing".

   Both modes are generated perceptually in OKLCH, then verified as a set: body
   text lands 9–13:1 on dark and 13–17:1 on light (crisp, but short of the
   ~16:1-on-black point where light text starts to halo), secondary text clears
   4.5:1, every accent and status colour clears 4.5:1 on every ground it sits
   on, ink clears 4.5:1 on the accent fill, each of the ten tag chips clears
   4.5:1 against its own label AND stays visible against the card beneath it,
   and every pair of surfaces that share an edge is at least 2.5 ΔL apart.
   Change one value and re-check the whole set — these numbers hold each other
   up.
   ───────────────────────────────────────────────────────────────────────── */
:root{
  color-scheme:dark;

  --bg:#151818;            /* page ground — lifted off black to kill the halo */
  --bg-2:#152324;          /* nav + hero + footer band, the one tinted surface */
  --card:#222525;
  --card-2:#2F3232;        /* raised surface inside a card */
  --text:#D6DADA;          /* deliberately not #fff: 12.7:1 on the page, not 16 */
  --muted:#A3A7A7;
  --faint:#868989;
  --accent:#5CC2C4;        /* teal — the only thing in the file with real chroma */
  --accent-2:#83D5D6;
  --accent-ink:#031A1B;    /* text on an accent fill — 8.5:1 */
  --border:#3B3E3E;
  --border-2:#505353;      /* hover / focus border */
  --tag-bg:#2F3232;
  --green:#76C392;
  --amber:#E5B46E;
  --red:#D8847D;
  --shadow:0 6px 24px rgba(0,0,0,.45);
  --shadow-lg:0 20px 50px rgba(0,0,0,.55);
  --scrim:rgba(8,10,10,.72);

  /* The band: nav, hero and footer. On dark it sits just above the page
     ground; on light it is a soft teal panel rather than a dark slab, so these
     are "ink on the band", not "ink on dark". */
  --band-ink:var(--text);
  --band-muted:#A3A7A7;
  --band-faint:#868989;
  --band-line:rgba(255,255,255,.07);
  --band-fill:rgba(255,255,255,.05);
  --band-fill-2:rgba(255,255,255,.10);

  /* Tag palette. Ten saturated pills on one card is its own kind of noise, so
     each hue keeps its identity at a fraction of the chroma: the chip reads as
     a tinted grey and its label carries the colour. */
  --t-indigo-bg:#33384C;  --t-indigo-fg:#AEBBEF;
  --t-emerald-bg:#2A3F31; --t-emerald-fg:#97CDA9;
  --t-blue-bg:#293B4B;    --t-blue-fg:#95C3EB;
  --t-violet-bg:#3C3549;  --t-violet-fg:#C5B3E8;
  --t-yellow-bg:#403923;  --t-yellow-fg:#D0BC86;
  --t-red-bg:#4A3230;     --t-red-fg:#EAABA5;
  --t-fuchsia-bg:#443342; --t-fuchsia-fg:#DAADD5;
  --t-orange-bg:#483427;  --t-orange-fg:#E4B290;
  --t-slate-bg:#353B3B;   --t-slate-fg:#B7C0C0;
  --t-sky-bg:#243D47;     --t-sky-fg:#88C9E2;

  --bar-upcoming:#8C7A44;
  --bar-rolling:#3F6E75;
  --bar-inactive:#444848;

  --notice-bg:#34291A;    --notice-bd:#504330;  --notice-fg:#E1BC88;
  --alert-bg:#392624;     --alert-bd:#563E3C;   --alert-fg:#F2AFA9;
  --warn-bg:#37271D;      --warn-bd:#544033;    --warn-fg:#ECB591;
  --good-bg:#1F3025;      --good-bd:#364B3D;    --good-fg:#99D2AC;

  --sw:238px;              /* sidebar width */
  --nh:56px;               /* nav height */
  --mnh:58px;              /* mobile bottom bar height */
  --gutter:1rem;
  --r:12px;                /* standard corner */
  --tap:44px;              /* minimum touch target */
}

/* Light is the same construction inverted: the same neutral grey scale read
   from the other end, the same teal at the lightness that clears 4.5:1 on
   white. The old light theme dropped a near-black navy slab behind the nav and
   hero; that slab was the single loudest thing on the page and it belonged to
   a palette that no longer exists. It is now a soft teal panel two steps off
   the page, which is enough to separate it without shouting. */
:root[data-theme="light"]{
  color-scheme:light;

  --bg:#F1F5F5;
  --bg-2:#DBEEEE;
  --card:#FFFFFF;
  --card-2:#EFF3F3;
  --text:#1D2020;
  --muted:#5A5D5D;
  --faint:#717474;
  --accent:#007679;
  --accent-2:#005F63;
  --accent-ink:#FAFEFE;
  --border:#D9DDDD;
  --border-2:#C1C5C5;
  --tag-bg:#E7EFEF;
  --green:#117342;
  --amber:#976500;
  --red:#A14B46;
  --shadow:0 3px 16px rgba(20,32,32,.07);
  --shadow-lg:0 20px 48px rgba(20,32,32,.18);
  --scrim:rgba(18,28,28,.5);

  --band-ink:var(--text);
  --band-muted:#5A5D5D;
  --band-faint:#6C6F6F;
  --band-line:rgba(0,0,0,.10);
  --band-fill:rgba(0,0,0,.045);
  --band-fill-2:rgba(0,0,0,.09);

  --t-indigo-bg:#E6ECFF;  --t-indigo-fg:#3F4989;
  --t-emerald-bg:#DEF3E4; --t-emerald-fg:#036035;
  --t-blue-bg:#DDF0FF;    --t-blue-fg:#075485;
  --t-violet-bg:#F0E9FF;  --t-violet-fg:#594080;
  --t-yellow-bg:#F5ECD7;  --t-yellow-fg:#664C00;
  --t-red-bg:#FFE6E3;     --t-red-fg:#803531;
  --t-fuchsia-bg:#F9E6F7; --t-fuchsia-fg:#6F386B;
  --t-orange-bg:#FEE8DA;  --t-orange-fg:#7A3D02;
  --t-slate-bg:#E7EFEF;   --t-slate-fg:#4A5252;
  --t-sky-bg:#D9F2FC;     --t-sky-fg:#005A7B;

  --bar-upcoming:#B08A2E;
  --bar-rolling:#3C8792;
  --bar-inactive:#B4BCBC;

  --notice-bg:#FFF2E2;    --notice-bd:#EBD6B9;  --notice-fg:#704500;
  --alert-bg:#FFEEEC;     --alert-bd:#F6CECA;   --alert-fg:#803531;
  --warn-bg:#FFF0E4;      --warn-bd:#F2D2BE;    --warn-fg:#7A3D02;
  --good-bg:#E8FAED;      --good-bd:#C3E2CC;    --good-fg:#036035;
}

html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}

body{
  font-family:'DM Sans',system-ui,-apple-system,sans-serif;
  background:var(--bg);color:var(--text);
  font-size:15px;line-height:1.6;
  /* The bottom bar is fixed, so the page needs room to scroll past it. */
  padding-bottom:calc(var(--mnh) + env(safe-area-inset-bottom));
  overflow-x:hidden;
  -webkit-tap-highlight-color:transparent;
}
body.no-scroll{overflow:hidden}

button,input,select,textarea{font-family:inherit;color:inherit}
/* 16px is the threshold below which iOS Safari zooms the viewport on focus. */
input,select,textarea{font-size:16px}
a{color:var(--accent)}

:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}

/* The nav is sticky at the top and the bar is fixed at the bottom, so anything
   the browser scrolls to on its own — a Tab through the cards, a focused chip,
   an in-page anchor — lands underneath one of them. scroll-margin reserves the
   clearance so a focused control is always actually on screen. */
a,button,input,select,summary,[tabindex],.card,.ecard{
  scroll-margin-top:calc(var(--nh) + .5rem);
  scroll-margin-bottom:calc(var(--mnh) + .75rem);
}

.skip-link{position:absolute;left:0;top:0;z-index:900;background:var(--accent);color:var(--accent-ink);
  padding:.6rem 1rem;border-radius:0 0 8px 0;font-weight:600;font-size:.85rem;
  transform:translateY(-200%);transition:transform .12s}
.skip-link:focus{transform:translateY(0)}

.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:10px}
::-webkit-scrollbar-thumb:hover{background:var(--border-2)}

/* ── NAV ─────────────────────────────────────────────────────────────────── */
/* :not(.mobnav) matters. The phone bottom bar is also a <nav>, and while its own
   rules set position:fixed and bottom:0, an unscoped `top:0` here still applied
   to it — a box with both top:0 and bottom:0 stretches over the whole viewport,
   which silently covered the entire page with an invisible bar. */
nav:not(.mobnav){
  background:var(--bg-2);min-height:var(--nh);
  display:flex;align-items:center;gap:.5rem;
  padding:.4rem var(--gutter);padding-top:calc(.4rem + env(safe-area-inset-top));
  position:sticky;top:0;z-index:100;
  border-bottom:1px solid var(--band-line);
}
.logo{font-family:'Lora',serif;font-size:1.18rem;color:var(--band-ink);letter-spacing:-.01em;
  display:flex;align-items:center;gap:.45rem;cursor:pointer;flex-shrink:0;user-select:none;
  min-height:var(--tap);padding-right:.25rem}
.ldot{width:7px;height:7px;background:var(--accent);border-radius:50%;flex-shrink:0}
/* Desktop gets the tab row in the nav; on a phone the bottom bar has it. */
.nav-tabs{display:none;gap:2px;margin-left:1rem}
.ntab{color:var(--band-muted);padding:.4rem .85rem;border-radius:8px;cursor:pointer;
  font-size:.82rem;font-weight:500;border:none;background:none;transition:background .15s,color .15s}
.ntab:hover{color:var(--band-ink);background:var(--band-fill)}
.ntab.active{color:var(--band-ink);background:var(--band-fill-2)}
.nbadge{background:var(--accent);color:var(--accent-ink);font-size:.62rem;font-weight:700;
  padding:1px 5px;border-radius:10px;margin-left:4px;vertical-align:middle;display:inline-block}
.nav-right{margin-left:auto;display:flex;align-items:center;gap:.5rem;flex-shrink:0}
.nav-updated{display:none;font-size:.72rem;color:var(--band-faint);align-items:center;gap:.4rem}
.update-dot{width:5px;height:5px;background:var(--green);border-radius:50%;flex-shrink:0}
.icon-btn{width:var(--tap);height:var(--tap);display:flex;align-items:center;justify-content:center;
  border:1px solid var(--band-line);background:var(--band-fill);border-radius:10px;
  color:var(--band-ink);cursor:pointer;font-size:1rem;line-height:1;transition:background .15s,border-color .15s}
.icon-btn:hover{background:var(--band-fill-2);border-color:var(--band-fill-2)}

/* ── LOADING / EMPTY ─────────────────────────────────────────────────────── */
.loading-screen{display:flex;align-items:center;justify-content:center;min-height:55vh;
  flex-direction:column;gap:1rem;color:var(--muted);padding:2rem 1rem;text-align:center}
.spinner{width:32px;height:32px;border:2.5px solid var(--border);border-top-color:var(--accent);
  border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* ── HERO ────────────────────────────────────────────────────────────────── */
.hero{background:var(--bg-2);padding:1.05rem var(--gutter) 1rem;color:var(--band-ink)}
/* On a phone the eyebrow, the third line of the subtitle and two of the four
   stat tiles are the difference between landing on a page of programs and
   landing on a page about a page of programs. They all come back at 480px. */
.heyebrow{display:none;font-size:.65rem;font-weight:700;letter-spacing:.14em;color:var(--accent);
  text-transform:uppercase;margin-bottom:.5rem}
.hero h1{font-family:'Lora',serif;font-size:1.45rem;line-height:1.14;letter-spacing:-.025em;
  margin-bottom:.4rem;max-width:20ch}
.hero h1 em{font-style:italic;color:var(--accent)}
.hsub{color:var(--band-muted);font-size:.84rem;margin-bottom:.85rem;max-width:52ch;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.sbar{display:flex;position:relative;max-width:540px}
.sbar input{flex:1;min-width:0;padding:.6rem 2.4rem .6rem .9rem;border-radius:10px;
  border:1.5px solid var(--band-line);background:var(--band-fill);color:var(--band-ink);
  outline:none;transition:border-color .15s,background .15s}
/* type=search draws its own clear button in Safari; .sclear is ours and works
   in every browser, so suppress the native one rather than showing two. */
.sbar input::-webkit-search-cancel-button,
.sbar input::-webkit-search-decoration{-webkit-appearance:none;appearance:none}
.sbar input{-webkit-appearance:none;appearance:none}
.sbar input::placeholder{color:var(--band-faint)}
.sbar input:focus{border-color:var(--accent);background:var(--band-fill-2)}
.sclear{position:absolute;right:.35rem;top:50%;transform:translateY(-50%);
  width:32px;height:32px;border:none;background:none;color:var(--band-faint);
  cursor:pointer;font-size:1.1rem;border-radius:8px;display:none}
.sbar.has-value .sclear{display:block}
.sclear:hover{color:var(--band-ink);background:var(--band-fill)}
.hstats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.5rem 1rem;margin-top:.85rem;max-width:420px}
/* Programs and Accepting now. "Free programs" and "Subject areas" are one tap
   away as quick chips, so on a phone they cost a row they do not earn. */
.hstats .hs:nth-child(2),.hstats .hs:nth-child(4){display:none}
.hs{font-size:.72rem;color:var(--band-faint);display:flex;align-items:baseline;gap:.4rem}
.hs strong{font-size:1.05rem;font-weight:600;color:var(--band-ink);line-height:1.2}

/* ── THE "ALSO BUILT BY US" PANEL ────────────────────────────────────────────
   Sits in the hero's second column from 900px — the space the old ad card
   occupied. On a phone that column would undo the work of shortening the hero,
   so it collapses to a single scrollable row of two pills: about 50px, not the
   150px the card costs.
   ───────────────────────────────────────────────────────────────────────── */
/* On a phone the label sits on the same line as the pills. Stacking it cost a
   whole 26px row, and both pills still fit beside the shorter wording. */
.hpromo{margin-top:.9rem;display:flex;align-items:center;gap:.55rem}
.hpromo-label{flex-shrink:0;font-size:.6rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--band-faint)}
.hpromo-long{display:none}
.hpromo-list{flex:1;min-width:0;display:flex;gap:.45rem;overflow-x:auto;scrollbar-width:none;
  margin-right:calc(var(--gutter) * -1);padding:.1rem var(--gutter) .1rem 0;
  scroll-snap-type:x proximity;overscroll-behavior-x:contain}
.hpromo-list::-webkit-scrollbar{display:none}
.hpromo-item{flex-shrink:0;scroll-snap-align:start;min-height:34px;
  display:flex;align-items:center;gap:.4rem;padding:.3rem .75rem;border-radius:20px;
  border:1px solid var(--band-line);background:var(--band-fill);color:var(--band-ink);
  text-decoration:none;font-size:.8rem;transition:background .13s,border-color .13s}
.hpromo-item:hover{background:var(--band-fill-2);border-color:var(--band-fill-2)}
.hpromo-top{display:flex;align-items:center;gap:.35rem}
.hpromo-name{font-weight:600;white-space:nowrap}
.hpromo-go{color:var(--accent);font-weight:700}
/* The blurb and the domain are the card's content; a pill has room for neither. */
.hpromo-desc,.hpromo-host{display:none}

/* ── NOTICE BAR ──────────────────────────────────────────────────────────── */
.notice{background:var(--card);border-bottom:1px solid var(--border);
  padding:.45rem var(--gutter);display:flex;align-items:flex-start;gap:.5rem;
  font-size:.74rem;color:var(--muted);line-height:1.5}
.notice-left{display:flex;align-items:flex-start;gap:.55rem;flex:1}
.ndot{width:5px;height:5px;background:var(--green);border-radius:50%;flex-shrink:0;margin-top:.45rem}
.notice-date{display:none;font-size:.7rem;color:var(--faint);flex-shrink:0}
.nlong{display:none}

/* ── PAGES ───────────────────────────────────────────────────────────────── */
.page{display:none}
.page.active{display:block}
.layout{display:block}

/* ── FILTER PANEL ────────────────────────────────────────────────────────────
   One markup tree, two presentations: a bottom sheet on a phone, a docked
   column from 900px up. Doing it with one element means the filter state can
   never differ between the two. */
.sidebar{
  position:fixed;left:0;right:0;bottom:0;z-index:600;
  max-height:88dvh;display:flex;flex-direction:column;
  background:var(--card);border-top:1px solid var(--border);
  border-radius:18px 18px 0 0;box-shadow:var(--shadow-lg);
  transform:translateY(101%);transition:transform .24s ease;
  visibility:hidden;
}
.sidebar.open{transform:translateY(0);visibility:visible}
.sb-backdrop{position:fixed;inset:0;background:var(--scrim);z-index:599;
  opacity:0;visibility:hidden;transition:opacity .2s}
.sb-backdrop.open{opacity:1;visibility:visible}
.sb-head{display:flex;align-items:center;gap:.75rem;padding:.85rem var(--gutter) .7rem;
  border-bottom:1px solid var(--border);flex-shrink:0}
.sb-head h2{font-size:.95rem;font-weight:600}
.sb-grip{position:absolute;top:.45rem;left:50%;transform:translateX(-50%);
  width:36px;height:4px;border-radius:2px;background:var(--border-2)}
.sb-close{margin-left:auto;width:36px;height:36px;border:none;background:var(--card-2);
  border-radius:9px;color:var(--muted);font-size:1.1rem;cursor:pointer;flex-shrink:0}
.sb-close:hover{color:var(--text)}
.sb-body{overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  padding:.9rem var(--gutter) 1rem;flex:1}
.sb-foot{flex-shrink:0;display:flex;gap:.6rem;padding:.7rem var(--gutter);
  padding-bottom:calc(.7rem + env(safe-area-inset-bottom));
  border-top:1px solid var(--border);background:var(--card)}
.sb-apply{flex:1;min-height:var(--tap);border:none;border-radius:11px;background:var(--accent);
  color:var(--accent-ink);font-size:.9rem;font-weight:700;cursor:pointer}
.sb-reset{min-height:var(--tap);padding:0 1.1rem;border:1px solid var(--border);
  border-radius:11px;background:var(--card-2);color:var(--muted);font-size:.88rem;
  font-weight:600;cursor:pointer}
.sb-reset:hover{color:var(--text);border-color:var(--border-2)}

/* Collapsible filter groups — six of them stacked open is a long scroll on a
   phone, so each one is a <details> and only Status starts open. */
.fs{border-bottom:1px solid var(--border);padding:.1rem 0}
.fs:last-of-type{border-bottom:none}
.fs>summary{display:flex;align-items:center;gap:.5rem;cursor:pointer;list-style:none;
  padding:.75rem .1rem;font-size:.7rem;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted);min-height:var(--tap)}
.fs>summary::-webkit-details-marker{display:none}
.fs>summary::after{content:'⌄';margin-left:auto;font-size:1rem;color:var(--faint);
  transition:transform .18s;line-height:0}
.fs[open]>summary::after{transform:rotate(180deg)}
.fs>summary .fs-on{font-size:.62rem;font-weight:700;background:var(--accent);color:var(--accent-ink);
  border-radius:20px;padding:1px 6px;letter-spacing:0}
.fs-list{padding:0 .1rem .6rem}
.fo{display:flex;align-items:center;gap:.6rem;padding:.5rem .1rem;cursor:pointer;
  font-size:.88rem;color:var(--text);user-select:none;min-height:var(--tap);border-radius:8px}
.fo:hover{background:var(--card-2)}
.fo input[type=checkbox]{accent-color:var(--accent);width:17px;height:17px;cursor:pointer;flex-shrink:0}
.fc{margin-left:auto;font-size:.7rem;color:var(--muted);background:var(--tag-bg);
  padding:1px 7px;border-radius:20px;flex-shrink:0;font-variant-numeric:tabular-nums}
.fhint{font-size:.7rem;color:var(--faint);line-height:1.45;padding:.1rem .1rem .55rem}

/* ── MAIN COLUMN ─────────────────────────────────────────────────────────── */
.main{min-width:0;padding:.55rem var(--gutter) 1.5rem}

/* Quick chips: the six filters worth one tap, scrollable on a phone. */
.quick{display:flex;gap:.45rem;overflow-x:auto;scrollbar-width:none;
  padding:.1rem .1rem .55rem;margin:0 calc(var(--gutter) * -1);
  padding-left:var(--gutter);padding-right:var(--gutter);
  scroll-snap-type:x proximity;overscroll-behavior-x:contain}
.quick::-webkit-scrollbar{display:none}
.qchip{flex-shrink:0;scroll-snap-align:start;min-height:34px;padding:.25rem .75rem;
  border-radius:20px;border:1px solid var(--border);background:var(--card);
  color:var(--muted);font-size:.8rem;font-weight:500;cursor:pointer;white-space:nowrap;
  transition:background .13s,border-color .13s,color .13s}
.qchip:hover{border-color:var(--border-2);color:var(--text)}
.qchip.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600}

/* Active filters, each individually removable. */
.chips{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:.55rem}
.chips:empty{display:none}
.chip{display:inline-flex;align-items:center;gap:.35rem;font-size:.76rem;font-weight:500;
  background:var(--tag-bg);color:var(--text);border:1px solid var(--border);
  border-radius:20px;padding:.2rem .3rem .2rem .65rem}
.chip button{width:22px;height:22px;border:none;border-radius:50%;background:transparent;
  color:var(--muted);cursor:pointer;font-size:.9rem;line-height:1;display:grid;place-items:center}
.chip button:hover{background:var(--border);color:var(--text)}
.chip-clear{font-size:.76rem;font-weight:600;color:var(--accent);background:none;border:none;
  cursor:pointer;padding:.25rem .4rem;min-height:30px}

.rbar{display:flex;align-items:center;gap:.5rem;margin-bottom:.6rem}
/* The count is short and fixed; the sort select is the one that should give
   up width, or "All 125 programs" wraps onto two lines and the whole row
   grows for nothing. */
.rc{font-size:.8rem;color:var(--muted);white-space:nowrap;flex-shrink:0}
.rc strong{color:var(--text);font-weight:600}
.ssel{margin-left:auto;min-width:0;max-width:56vw;font-size:.8rem;padding:.38rem .5rem;
  border:1px solid var(--border);border-radius:9px;background:var(--card);color:var(--text);
  cursor:pointer;outline:none;min-height:38px}
/* Hidden at every width, and the markup is kept only because the sheet's
   click handler already covers both buttons. Below 900px the bottom bar
   carries a "Filters" button with the same badge, twenty pixels away; at 900px
   and up the panel is docked and neither is needed. Two buttons for one sheet
   were squeezing the sort select down to "Most pr…" on a phone. */
.filter-btn{display:none;align-items:center;gap:.4rem;flex-shrink:0;min-height:38px;
  padding:.35rem .8rem;border:1px solid var(--border);border-radius:9px;background:var(--card);
  color:var(--text);font-size:.8rem;font-weight:600;cursor:pointer}
.filter-btn .fs-on{background:var(--accent);color:var(--accent-ink);border-radius:20px;
  padding:0 6px;font-size:.68rem}

.unknown-note{background:var(--notice-bg);border:1px solid var(--notice-bd);color:var(--notice-fg);
  border-radius:10px;padding:.55rem .8rem;font-size:.76rem;line-height:1.5;margin-bottom:.8rem}

/* ── LAYOUT TOGGLE + SHOW MORE ───────────────────────────────────────────────
   The list used to draw all 125 programs at once — 58 screens of scrolling on
   a phone, and every one of them a full card. Two things fix that: only the
   first page is in the DOM, and a row layout for when the job is scanning
   names rather than reading each one.
   ───────────────────────────────────────────────────────────────────────── */
.vtog{display:flex;flex-shrink:0;gap:2px;padding:2px;border-radius:9px;
  border:1px solid var(--border);background:var(--card)}
.vbtn{min-width:32px;min-height:32px;border:none;border-radius:7px;background:none;
  color:var(--faint);font-size:.85rem;cursor:pointer;line-height:1;
  display:grid;place-items:center;transition:background .13s,color .13s}
.vbtn:hover{color:var(--text)}
.vbtn[aria-pressed="true"]{background:var(--accent);color:var(--accent-ink)}

.more{margin-top:1rem;text-align:center}
.more-btn{min-height:var(--tap);padding:.55rem 1.4rem;border-radius:10px;
  border:1px solid var(--border);background:var(--card);color:var(--text);
  font-size:.85rem;font-weight:600;cursor:pointer;
  transition:border-color .13s,background .13s}
.more-btn:hover{border-color:var(--accent);background:var(--card-2)}
.more-note{font-size:.75rem;color:var(--faint);margin-top:.5rem}

/* ── LIST VIEW ───────────────────────────────────────────────────────────── */
.grid[data-view="list"]{display:block;border:1px solid var(--border);
  border-radius:var(--r);overflow:hidden;background:var(--card)}
.row{display:flex;align-items:center;gap:.6rem;width:100%;text-align:left;
  padding:.55rem .7rem;cursor:pointer;border-bottom:1px solid var(--border);
  transition:background .12s}
.grid[data-view="list"] .row:last-child{border-bottom:none}
.row:hover{background:var(--card-2)}
.rlog{width:26px;height:26px;border-radius:7px;display:grid;place-items:center;
  font-weight:700;font-size:.6rem;color:#fff;flex-shrink:0;letter-spacing:-.02em;
  text-shadow:0 1px 2px rgba(0,0,0,.35)}
.rmain{flex:1;min-width:0;display:flex;flex-direction:column}
.rname{font-weight:600;font-size:.84rem;line-height:1.25;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rhost{font-size:.7rem;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rdl{font-size:.75rem;font-weight:500;flex-shrink:0;text-align:right;line-height:1.25}
.rlbl{display:block;font-size:.58rem;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint)}
/* On a phone the row carries the name, the host and the deadline; cost and
   the status pill would push the name down to an ellipsis. */
.rcost,.rtag{display:none}

/* ── PROGRAM GRID + CARDS ────────────────────────────────────────────────── */
.grid{display:grid;grid-template-columns:1fr;gap:.75rem}
.card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);
  padding:.8rem;cursor:pointer;display:flex;flex-direction:column;gap:.5rem;
  position:relative;overflow:hidden;text-align:left;width:100%;
  transition:border-color .15s,box-shadow .15s,transform .12s}
.card:hover{border-color:var(--border-2);box-shadow:var(--shadow)}
@media(hover:hover){.card:hover{transform:translateY(-1px)}}
.card:active{transform:scale(.995)}
.cbar{position:absolute;top:0;left:0;right:0;height:3px}
.cbar-open{background:var(--green)}
.cbar-closed{background:var(--red)}
.cbar-urgent{background:var(--amber)}
/* Tokenised, not hardcoded: on dark these were bright gradients tuned for a
   white page, and three of them across every card is most of the glare. */
.cbar-upcoming{background:var(--bar-upcoming)}
.cbar-rolling{background:var(--bar-rolling)}
.cbar-inactive{background:var(--bar-inactive)}
.ctop{display:flex;gap:.6rem;align-items:flex-start}
.clog{width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:.8rem;color:#fff;flex-shrink:0;letter-spacing:-.02em;
  text-shadow:0 1px 2px rgba(0,0,0,.35)}
.ctitle{font-weight:600;font-size:.92rem;line-height:1.3}
.chost{font-size:.74rem;color:var(--muted);margin-top:1px}
.cstars{font-size:10px;color:var(--amber);display:block;margin-top:2px;letter-spacing:1px}
.cbadges{display:flex;flex-direction:column;gap:3px;align-items:flex-end;flex-shrink:0;margin-top:2px}
/* Two lines on a phone, three from 700px. Clamping beats a shorter slice:
   the same text serves both, and nothing is lost — the modal has it in full. */
.cdesc{font-size:.8rem;color:var(--muted);line-height:1.45;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.tags{display:flex;flex-wrap:wrap;gap:.3rem}
.tag{font-size:.68rem;font-weight:600;padding:2px 8px;border-radius:20px;white-space:nowrap;letter-spacing:.02em}
.tc{background:var(--t-indigo-bg);color:var(--t-indigo-fg)}
.tip{background:var(--t-emerald-bg);color:var(--t-emerald-fg)}
.ton{background:var(--t-blue-bg);color:var(--t-blue-fg)}
.thy{background:var(--t-violet-bg);color:var(--t-violet-fg)}
.tg{background:var(--t-yellow-bg);color:var(--t-yellow-fg)}
.tf{background:var(--t-emerald-bg);color:var(--t-emerald-fg)}
.tcl{background:var(--t-red-bg);color:var(--t-red-fg)}
.tnew{background:var(--t-fuchsia-bg);color:var(--t-fuchsia-fg)}
.tup{background:var(--t-yellow-bg);color:var(--t-yellow-fg)}
.trl{background:var(--t-sky-bg);color:var(--t-sky-fg)}
.tdc{background:var(--t-slate-bg);color:var(--t-slate-fg)}
.tun{background:var(--t-orange-bg);color:var(--t-orange-fg)}
/* "expected date, not confirmed" marker */
.exp{border-bottom:1px dashed currentColor;cursor:help}
/* Deadline and Dates on a phone; Location and Grades join them at 700px.
   All four are always in the modal. */
.cmeta{display:grid;grid-template-columns:1fr 1fr;gap:.45rem}
.cmeta .mi:nth-child(n+3){display:none}
.mi{font-size:.78rem;min-width:0}
.ml{font-size:.63rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--faint);margin-bottom:1px}
.mv{font-weight:500;overflow-wrap:anywhere}
.urgent{color:var(--red)}
.soon{color:var(--amber)}
.closed-t{color:var(--faint)}
.cfoot{padding-top:.5rem;border-top:1px solid var(--border);display:flex;align-items:center;
  justify-content:space-between;gap:.6rem}
.cv{font-size:.82rem;font-weight:600}
.cvf{color:var(--green)}
.abtn{flex-shrink:0;font-size:.79rem;font-weight:600;min-height:38px;padding:.35rem .85rem;
  border-radius:9px;background:var(--accent);color:var(--accent-ink);border:none;cursor:pointer}
.abtn:hover{background:var(--accent-2)}

.nores{text-align:center;padding:2.5rem 1rem;color:var(--muted);grid-column:1/-1}
.nores h3{font-size:1rem;font-weight:600;color:var(--text);margin-bottom:.4rem}
.nores button{margin-top:1rem;min-height:var(--tap);padding:.5rem 1.2rem;border:none;
  border-radius:10px;background:var(--accent);color:var(--accent-ink);font-weight:700;cursor:pointer}

/* ── EVENTS ──────────────────────────────────────────────────────────────── */
/* Same treatment as the programs hero: on a phone this page is a list of
   events, not an essay about events. */
.ehero{background:var(--bg-2);padding:1rem var(--gutter) .9rem;color:var(--band-ink);
  border-bottom:1px solid var(--band-line)}
.ehero h2{font-family:'Lora',serif;font-size:1.3rem;letter-spacing:-.02em;margin-bottom:.3rem;
  line-height:1.18}
.ehero p{color:var(--band-muted);font-size:.82rem;max-width:60ch;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.ebar{background:var(--card);border-bottom:1px solid var(--border);
  padding:.5rem var(--gutter);display:flex;gap:.45rem;align-items:center;
  overflow-x:auto;scrollbar-width:none}
.ebar::-webkit-scrollbar{display:none}
.elabel{font-size:.72rem;color:var(--faint);font-weight:600;flex-shrink:0}
.efbtn{flex-shrink:0;font-size:.8rem;font-weight:500;min-height:36px;padding:.3rem .85rem;
  border-radius:20px;border:1px solid var(--border);background:var(--card);color:var(--muted);
  cursor:pointer;white-space:nowrap;transition:background .13s,border-color .13s,color .13s}
.efbtn:hover{border-color:var(--border-2);color:var(--text)}
.efbtn.active{background:var(--accent);border-color:var(--accent);color:var(--accent-ink);font-weight:600}
.ebody{padding:.75rem var(--gutter) 1.5rem}
.esec{margin-bottom:1.3rem}
.eslabel{font-size:.66rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-bottom:.7rem;padding-bottom:.4rem;border-bottom:1px solid var(--border)}
.egrid{display:grid;grid-template-columns:1fr;gap:.75rem}
.ecard{background:var(--card);border:1px solid var(--border);border-radius:var(--r);
  padding:.8rem;cursor:pointer;text-align:left;width:100%;
  transition:border-color .15s,box-shadow .15s,transform .12s}
.ecard:hover{border-color:var(--border-2);box-shadow:var(--shadow)}
@media(hover:hover){.ecard:hover{transform:translateY(-1px)}}
.etype{font-size:.66rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  padding:2px 8px;border-radius:20px;display:inline-block;margin-bottom:.5rem}
.eh{background:var(--t-indigo-bg);color:var(--t-indigo-fg)}
.ec{background:var(--t-orange-bg);color:var(--t-orange-fg)}
.ea{background:var(--t-fuchsia-bg);color:var(--t-fuchsia-fg)}
.ef2{background:var(--t-sky-bg);color:var(--t-sky-fg)}
.etitle{font-weight:600;font-size:.92rem;margin-bottom:.18rem;line-height:1.3}
.eorg{font-size:.76rem;color:var(--muted);margin-bottom:.55rem}
.edesc{font-size:.8rem;color:var(--muted);line-height:1.45;margin-bottom:.65rem;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
.emeta{display:grid;grid-template-columns:1fr 1fr;gap:.45rem}
.emi{font-size:.78rem;min-width:0}
.eml{font-size:.63rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--faint);margin-bottom:1px}
.emv{font-weight:500;overflow-wrap:anywhere}
.efoot{display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  margin-top:.8rem;padding-top:.6rem;border-top:1px solid var(--border)}
.eprize{font-size:.78rem;font-weight:600;color:var(--amber);min-width:0}
.ebtn{flex-shrink:0;font-size:.79rem;font-weight:600;min-height:38px;padding:.35rem .85rem;
  border-radius:9px;background:var(--accent);color:var(--accent-ink);border:none;cursor:pointer}
.ebtn:hover{background:var(--accent-2)}

/* ── PROGRAM MODAL ───────────────────────────────────────────────────────────
   A full-height sheet on a phone (sticky header and footer, only the body
   scrolls) and a centred dialog from 700px up. */
.mbg{position:fixed;inset:0;background:var(--scrim);z-index:700;
  display:flex;align-items:flex-end;justify-content:center;
  opacity:0;visibility:hidden;transition:opacity .18s}
.mbg.open{opacity:1;visibility:visible}
.modal{background:var(--card);border-radius:18px 18px 0 0;width:100%;max-width:600px;
  max-height:94dvh;display:flex;flex-direction:column;overflow:hidden;
  transform:translateY(2rem);transition:transform .22s ease}
.mbg.open .modal{transform:translateY(0)}
.mh{background:var(--bg-2);padding:1.25rem var(--gutter) 1.1rem;flex-shrink:0;position:relative}
.mhtop{display:flex;align-items:flex-start;gap:.8rem;margin-bottom:.8rem;padding-right:2.5rem}
.mlog{width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:1rem;color:#fff;flex-shrink:0;text-shadow:0 1px 2px rgba(0,0,0,.35)}
.mtitle{font-family:'Lora',serif;font-size:1.25rem;letter-spacing:-.02em;line-height:1.22;color:var(--band-ink)}
.mhost{color:var(--band-muted);font-size:.79rem;margin-top:.18rem}
.mstars{color:var(--amber);font-size:.82rem;margin-top:.15rem}
.mtags2{display:flex;gap:.35rem;flex-wrap:wrap}
/* .mtag is layout only. The subject and format pills add .mtag-plain for the
   neutral band fill; the status pill adds one of the themed .t* classes
   instead, the same ones the cards use. Keeping the colours off .mtag is what
   lets a .t* class win — they are declared earlier in this file, so on equal
   specificity .mtag would otherwise take it. */
.mtag{font-size:.69rem;font-weight:500;padding:2px 9px;border-radius:20px}
.mtag-plain{background:var(--band-fill-2);color:var(--band-ink)}
.mx{position:absolute;top:.85rem;right:.75rem;width:36px;height:36px;border:none;border-radius:50%;
  background:var(--band-fill-2);color:var(--band-ink);font-size:1.1rem;cursor:pointer;
  display:grid;place-items:center;line-height:1}
.mb{padding:1.1rem var(--gutter);overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;flex:1}
.ms{margin-bottom:1.15rem}
.msl{font-size:.65rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--faint);margin-bottom:.4rem}
.mdesc{font-size:.87rem;line-height:1.65}
.mgrid{display:grid;grid-template-columns:1fr 1fr;gap:.6rem}
.mbox{background:var(--card-2);border:1px solid var(--border);border-radius:9px;padding:.6rem .75rem;min-width:0}
.mbl{font-size:.63rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;
  color:var(--faint);margin-bottom:.2rem}
.mbv{font-size:.85rem;font-weight:500;overflow-wrap:anywhere}
.mhist{font-size:.81rem;color:var(--muted);line-height:1.7}
.mhist strong{color:var(--text)}
.mfooter{flex-shrink:0;display:flex;align-items:center;gap:.75rem;
  padding:.75rem var(--gutter);padding-bottom:calc(.75rem + env(safe-area-inset-bottom));
  background:var(--card);border-top:1px solid var(--border)}
.mclose{font-size:.85rem;color:var(--muted);cursor:pointer;border:none;background:none;
  min-height:var(--tap);padding:0 .2rem}
.mclose:hover{color:var(--text)}
.mapp{flex:1;min-height:var(--tap);padding:.5rem 1rem;background:var(--accent);color:var(--accent-ink);
  border:none;border-radius:11px;font-size:.88rem;font-weight:700;cursor:pointer}
.mapp:hover{background:var(--accent-2)}
.mnotice,.mnote,.murgent,.mgood{border-radius:9px;padding:.6rem .85rem;font-size:.8rem;
  line-height:1.55;margin-bottom:.9rem}
/* A confirmed date is good news and must not wear the same amber as "expected,
   not confirmed" — they were visually identical, which is the one distinction
   this whole data model exists to make. */
.mgood{background:var(--good-bg);border:1px solid var(--good-bd);color:var(--good-fg)}
.mnotice{background:var(--alert-bg);border:1px solid var(--alert-bd);color:var(--alert-fg)}
.mnote{background:var(--notice-bg);border:1px solid var(--notice-bd);color:var(--notice-fg)}
.murgent{background:var(--warn-bg);border:1px solid var(--warn-bd);color:var(--warn-fg)}
.mb .mnote:last-child,.mb .mgood:last-child{margin-bottom:0}

/* ── MOBILE BOTTOM BAR ───────────────────────────────────────────────────── */
.mobnav{position:fixed;top:auto;left:0;right:0;bottom:0;z-index:500;display:flex;
  background:var(--bg-2);border:none;border-top:1px solid var(--band-line);
  min-height:0;padding:0;padding-bottom:env(safe-area-inset-bottom)}
.mobnav button{flex:1;min-height:var(--mnh);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:2px;border:none;background:none;
  color:var(--band-faint);font-size:.66rem;font-weight:600;cursor:pointer;padding:.3rem}
.mobnav button .mn-ico{font-size:1.05rem;line-height:1.1}
.mobnav button.active{color:var(--accent)}
.mn-count{font-size:.6rem;font-weight:700;background:var(--accent);color:var(--accent-ink);
  border-radius:20px;padding:0 5px;margin-left:3px}

/* ── BACK TO TOP ─────────────────────────────────────────────────────────── */
.totop{position:fixed;right:var(--gutter);z-index:450;
  bottom:calc(var(--mnh) + env(safe-area-inset-bottom) + .7rem);
  width:var(--tap);height:var(--tap);border-radius:50%;border:1px solid var(--border);
  background:var(--card);color:var(--text);box-shadow:var(--shadow);cursor:pointer;
  font-size:1.05rem;opacity:0;visibility:hidden;transition:opacity .18s,visibility .18s}
.totop.show{opacity:1;visibility:visible}

/* ── THE NO-JAVASCRIPT INDEX ─────────────────────────────────────────────────
   Only ever rendered when scripting is off, so it is plain on purpose: the
   job is that the database is readable at all, not that it is pretty.
   ───────────────────────────────────────────────────────────────────────── */
.ns{max-width:70ch;margin:0 auto;padding:1.5rem var(--gutter) 2.5rem}
.ns h2{font-family:'Lora',serif;font-size:1.3rem;margin:1.6rem 0 .5rem}
.ns p{color:var(--muted);font-size:.85rem;margin-bottom:1rem}
.ns ul{padding-left:1.1rem}
.ns li{font-size:.85rem;line-height:1.6;margin-bottom:.5rem;color:var(--muted)}
.ns a{color:var(--accent);font-weight:600}

/* ── FOOTER ──────────────────────────────────────────────────────────────── */
footer{background:var(--bg-2);padding:1.4rem var(--gutter);margin-top:1.5rem;
  color:var(--band-faint);font-size:.75rem;border-top:1px solid var(--band-line);line-height:1.6}
footer p{margin-bottom:.3rem}
footer strong{color:var(--band-muted)}
.fcontact{margin-top:.55rem}
footer a{color:var(--accent);font-weight:600}

/* The advertising panel. It sits above the boilerplate because it is the one
   thing in the footer anybody is meant to act on. */
.fad{border:1px solid var(--band-line);background:var(--band-fill);
  border-radius:var(--r);padding:.9rem 1rem;margin-bottom:1.1rem;max-width:46rem}
.fad-title{font-size:.86rem;font-weight:600;color:var(--band-ink);margin-bottom:.25rem}
.fad-body{font-size:.78rem;color:var(--band-muted);line-height:1.55;max-width:52ch}
.fad-mail{display:inline-flex;align-items:center;margin-top:.7rem;min-height:var(--tap);
  padding:.45rem .9rem;border-radius:9px;background:var(--accent);color:var(--accent-ink);
  font-size:.82rem;font-weight:700;text-decoration:none;letter-spacing:.01em}
.fad-mail:hover{background:var(--accent-2);color:var(--accent-ink)}
/* The @ lives here, not in the markup, so the address is never one scrapable
   string in the HTML. The href still spells it out in full. */
.fad-user::after{content:'@'}

/* ═══ 480px — two-up stat and card grids ═══════════════════════════════════ */
@media(min-width:480px){
  .heyebrow{display:block}
  .hstats{grid-template-columns:repeat(4,minmax(0,1fr));max-width:none;gap:.75rem 1rem;margin-top:1.1rem}
  .hs,.hstats .hs:nth-child(2),.hstats .hs:nth-child(4){display:block}
  .hs strong{display:block;font-size:1.15rem;margin-bottom:1px}
  .hsub,.ehero p{-webkit-line-clamp:none;display:block;overflow:visible}
  .ehero h2{font-size:1.55rem}
  .grid,.egrid{grid-template-columns:repeat(auto-fill,minmax(290px,1fr))}
}

/* ═══ 700px — the modal becomes a centred dialog ═══════════════════════════ */
@media(min-width:700px){
  :root{--gutter:1.5rem}
  .hero{padding:2.2rem var(--gutter) 1.9rem}
  .hero h1{font-size:2.3rem}
  .hsub{font-size:.88rem;margin-bottom:1.1rem}
  .nshort{display:none}
  .nlong{display:inline}
  .card{padding:1rem;gap:.6rem}
  .clog{width:38px;height:38px}
  .cdesc{font-size:.81rem;line-height:1.5;-webkit-line-clamp:3}
  .cmeta .mi:nth-child(n+3){display:block}
  .row{padding:.6rem .85rem;gap:.85rem}
  .rlog{width:30px;height:30px;font-size:.65rem}
  .rname{font-size:.88rem}
  /* The columns line up from here, so the per-row "DEADLINE" caption is 50
     repetitions of something the layout already says. It stays on a phone,
     where the rows are not aligned into columns. */
  .rdl{width:9.5rem}
  .rlbl{display:none}
  .rcost{display:block;width:7rem;flex-shrink:0;font-size:.78rem;font-weight:600;text-align:right}
  .rtag{display:inline-block;flex-shrink:0;width:6.2rem;text-align:center}
  .ehero{padding:1.4rem var(--gutter) 1.2rem}
  .ecard{padding:1rem}
  .edesc{font-size:.81rem;line-height:1.5;-webkit-line-clamp:4}
  .mbg{align-items:flex-start;padding:2.5rem 1rem 2rem;overflow-y:auto}
  .modal{border-radius:14px;max-height:none}
  .mb{overflow:visible}
  .notice-date{display:block}
  .notice{align-items:center;justify-content:space-between}
}

/* ═══ 900px — filters dock, bottom bar retires ═════════════════════════════ */
@media(min-width:900px){
  body{padding-bottom:0}
  .nav-tabs{display:flex}
  /* From here the nav carries the "Updated" date, so the copy of it on the
     right of the notice bar is a duplicate. It stays for 700-899px, where the
     nav version is still hidden. */
  .nav-updated{display:flex}
  .notice-date{display:none}
  .mobnav{display:none}
  .totop{bottom:1.25rem}
  /* No bottom bar up here, so only the sticky nav needs clearance. */
  a,button,input,select,summary,[tabindex],.card,.ecard{scroll-margin-bottom:1rem}

  .layout{display:flex;align-items:flex-start;min-height:60vh}
  .main{flex:1;padding:1.1rem 1.25rem 2rem}

  /* The hero's two columns. hero-main is capped so the four stat tiles stay a
     readable row instead of stretching the full page width. */
  .hero{display:flex;align-items:flex-start;justify-content:space-between;gap:2.5rem}
  .hero-main{flex:1;min-width:0;max-width:640px}
  .hstats{max-width:560px}

  .hpromo{width:300px;flex-shrink:0;margin-top:.35rem;display:block;
    border:1px solid var(--band-line);background:var(--band-fill);
    border-radius:var(--r);padding:.9rem .95rem}
  .hpromo-label{margin-bottom:.6rem}
  .hpromo-short{display:none}
  .hpromo-long{display:inline}
  .hpromo-list{display:block;overflow:visible;margin:0;padding:0}
  .hpromo-item{display:flex;flex-direction:column;align-items:stretch;gap:.15rem;
    width:100%;min-height:0;border-radius:10px;padding:.6rem .7rem;
    background:var(--band-fill);border-color:var(--band-line)}
  .hpromo-item + .hpromo-item{margin-top:.45rem}
  .hpromo-top{justify-content:space-between}
  .hpromo-name{font-size:.88rem}
  .hpromo-go{transition:transform .15s}
  .hpromo-item:hover .hpromo-go{transform:translateX(3px)}
  .hpromo-desc{display:block;font-size:.75rem;line-height:1.45;color:var(--band-muted)}
  .hpromo-host{display:block;font-size:.66rem;color:var(--band-faint);margin-top:.15rem}

  .sidebar{
    position:sticky;top:var(--nh);left:auto;right:auto;bottom:auto;
    width:var(--sw);flex-shrink:0;height:calc(100dvh - var(--nh));max-height:none;
    transform:none;visibility:visible;border-radius:0;box-shadow:none;
    border-top:none;border-right:1px solid var(--border);
  }
  .sb-backdrop,.sb-grip,.sb-close{display:none}
  .sb-head{padding:1rem 1rem .7rem}
  .sb-body{padding:.4rem 1rem 1rem}
  .sb-foot{padding:.7rem 1rem;border-top:1px solid var(--border)}
  .sb-apply{display:none}
  .sb-reset{flex:1}
  .fo{font-size:.83rem;min-height:34px;padding:.32rem .2rem}
  .ssel{flex-shrink:0}
  /* .quick bleeds to the screen edge with a -1rem margin so the chip strip can
     scroll edge to edge on a phone. Here .main's padding is 1.25rem, not the
     1rem gutter the bleed is calculated from, so it overhung by 4px a side and
     gave the desktop page a horizontal scrollbar. The chips all fit up here
     anyway, so drop the bleed rather than re-deriving it. */
  .quick{margin:0;padding-left:0;padding-right:0}
  .grid,.egrid{grid-template-columns:repeat(auto-fill,minmax(296px,1fr))}
  .ssel{max-width:none}
}

@media(min-width:1100px){
  .hero{padding:2.6rem 2rem 2.2rem}
  .hero h1{font-size:2.5rem}
  .hpromo{width:330px}
}
