/* ============================================================
   Dr. Shaun Hurley — Tutoring  ·  site design system
   Ink navy · cool porcelain · antique brass
   Spectral (display) · Libre Franklin (body) · IBM Plex Mono (utility)
   Signature motif: the calculus curve — tangent (f′=0) + integral area
   ============================================================ */

:root{
  /* --- brand palette --- */
  --ink:#0E2138;
  --ink-2:#15304c;
  --ink-3:#1d3c5c;
  --ink-4:#294a6d;
  --porcelain:#EDF1F5;
  --porcelain-2:#E4EAF0;
  --paper:#FBFCFE;
  --brass:#B0894A;
  --brass-2:#C39A57;
  --brass-deep:#795B2B;
  --brass-glow:#E7C892;
  --brass-soft:rgba(176,137,74,.14);
  --brass-line:rgba(176,137,74,.42);
  --slate:#54687C;
  --slate-2:#6b7f92;
  --line:#D6DEE7;
  --line-soft:#E3E9EF;
  --rose:#C15268;
  --ink-on-dark:#EAF0F6;
  --slate-on-dark:#A7BACC;
  --line-on-dark:rgba(167,186,204,.20);

  /* --- type --- */
  --serif:'Spectral', Georgia, 'Times New Roman', serif;
  --sans:'Libre Franklin', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono:'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* --- rhythm --- */
  /* THE SHELL SCALES; THE PROSE DOES NOT. That is the whole width system (2026-09-11).
     `--wrap` and `--wrap-wide` are LAYOUT containers — the hero, card grids, two-column
     bands — and they grow with the viewport, because a grid of cards genuinely gets better
     with more room. `--wrap-mid`, `--wrap-narrow` and `--measure` are READING containers and
     stay fixed, because a line of text does not get better past ~75 characters.
     Why this changed: both were fixed, so on a 1920px screen the shell sat at 1180px with
     370px dead on each side, while `.hero h1` kept scaling with vw up to 64px inside a 547px
     column — six lines of headline. Bigger screen, more wrapping, which is backwards.
     The clamp floor equals the old fixed value, so nothing at or below ~1340px moves. */
  --wrap:clamp(1180px, 88vw, 1560px);
  /* Must stay wider than --wrap at every viewport, or `.wrap--wide` bands (the home and
     testimonials proof rows) would render NARROWER than the page around them. */
  --wrap-wide:clamp(1400px, 94vw, 1760px);
  --wrap-mid:960px;
  /* 730px put body copy at 54 characters per line — under the 60–75 band where prose
     actually reads. 860px lands it at ~65. Site-wide on purpose: .narrow is the prose
     container on 13 pages, and per-page overrides are exactly the container-width drift
     R22 was about. (2026-09-09) */
  --wrap-narrow:860px;
  /* Prose measure for hero leads and intro paragraphs. In PX-equivalent units on purpose:
     `ch` is relative to each element's own font, so a 66ch serif lead and a 66ch sans
     paragraph come out ~100px apart and look misaligned. 48rem = the 66ch the body font
     was already using, so the two now share a right edge. (2026-09-09) */
  --measure:48rem;
  --tcard-max:520px;         /* one knob: widest a sprinkled testimonial card ever gets, at any viewport */
  --para-gap:1.15em;         /* one knob for paragraph spacing site-wide — just past the line gap, not airy */
  --gutter:clamp(1.15rem, 4vw, 2.75rem);
  --section-y:clamp(4rem, 8.5vw, 7.5rem);
  --radius:16px;
  --radius-lg:22px;
  --radius-sm:10px;
  --shadow-sm:0 1px 2px rgba(14,33,56,.05), 0 6px 20px rgba(14,33,56,.06);
  --shadow-md:0 2px 8px rgba(14,33,56,.07), 0 24px 54px rgba(14,33,56,.13);
  --shadow-lg:0 4px 12px rgba(14,33,56,.10), 0 40px 90px rgba(14,33,56,.20);
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
}

/* ---------- reset / base ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;
  font-family:var(--sans);
  font-size:clamp(1rem,.5vw + .92rem,1.09rem);
  line-height:1.68;
  color:var(--ink);
  background:var(--porcelain);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,svg{max-width:100%;display:block}
[hidden]{display:none !important}   /* we set display on a lot of elements — keep the attribute winning */
a{color:inherit}
h1,h2,h3,h4{font-family:var(--serif);font-weight:500;line-height:1.12;margin:0;letter-spacing:-.015em}
p{margin:0 0 var(--para-gap)}
p:last-child{margin-bottom:0}
strong{font-weight:600}
em{font-style:italic}
code{font-family:var(--mono);font-size:.9em;background:var(--brass-soft);color:var(--brass-deep);padding:.08em .38em;border-radius:5px}
::selection{background:var(--brass-soft);color:var(--ink)}
:focus-visible{outline:2.5px solid #2E6FB0;outline-offset:3px;border-radius:5px}

/* ---------- layout helpers ---------- */
.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter)}
/* Deliberate exception to the site's standard measure. Two users, and they are the same
   content: the home proof band (3 columns) and the "Two more that didn't come from me" band
   on Testimonials (2 columns, added 2026-09-09). It needs no media query: below roughly
   1180px of viewport both variants resolve to the same viewport-limited width, so narrower
   layouts are untouched and only the multi-column bands actually widen.
   The test for adding a third user is NOT "this section feels cramped" — it's "this is a
   multi-column band, so widening the container SHORTENS each column's line rather than
   lengthening it." A single run of prose never qualifies; measure is capped on purpose. */
.wrap--wide{max-width:var(--wrap-wide)}
/* The header bar only — see the .nav note. Nothing else on the site is full-bleed. */
.wrap--bar{max-width:none}
.mid{max-width:var(--wrap-mid)}
.narrow{max-width:var(--wrap-narrow)}
.section{padding-block:var(--section-y)}
.section--tight{padding-block:clamp(2.75rem,5.5vw,4.5rem)}
.center{text-align:center}
.stack > * + *{margin-top:1.4em}
.mt-0{margin-top:0}

/* eyebrow: mono label with the ∫ mark */
.eyebrow{
  font-family:var(--sans);
  font-size:.76rem;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--brass-deep);
  display:inline-flex;
  align-items:center;
  gap:.7ch;
  margin:0 0 1.1rem;
  font-weight:600;
}
.eyebrow::before{content:"∫";font-family:var(--serif);font-size:1.6em;line-height:0;transform:translateY(-.04em);color:var(--brass);font-weight:600}
.eyebrow::after{content:"";height:1.5px;width:1.6rem;background:linear-gradient(90deg,var(--brass),transparent);border-radius:2px;opacity:.85}
.eyebrow--center{justify-content:center}
.eyebrow--center::after{display:none}
.dark .eyebrow::after,.hero__eyebrow::after,.cta-band .eyebrow::after,.press .eyebrow::after{background:linear-gradient(90deg,var(--brass-glow),transparent)}

.lede{font-size:clamp(1.14rem,1.4vw,1.36rem);color:var(--slate);line-height:1.56}
.muted{color:var(--slate)}
h1.h-page{font-size:clamp(2.1rem,4.6vw,3.4rem);font-weight:500;letter-spacing:-.02em}
h2.h-section{font-size:clamp(1.75rem,3.4vw,2.7rem);letter-spacing:-.018em}
h3.h-card{font-size:1.24rem;letter-spacing:-.008em}

/* section divider: thin brass curve mark */
.rule-curve{border:0;height:24px;margin:2.4rem auto;width:130px;background:no-repeat center/130px 24px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='130' height='24' viewBox='0 0 130 24'%3E%3Cpath d='M2 20 C 34 20, 38 5, 65 5 S 98 20, 128 7' fill='none' stroke='%23B0894A' stroke-width='1.6' stroke-linecap='round'/%3E%3Ccircle cx='65' cy='5' r='2.6' fill='%23B0894A'/%3E%3C/svg%3E")}

/* ---------- buttons ---------- */
.btn{
  --bg:var(--brass);--fg:#fff;--bd:var(--brass);
  display:inline-flex;align-items:center;gap:.6ch;
  font-family:var(--sans);font-weight:600;font-size:.97rem;
  letter-spacing:.005em;
  padding:.82em 1.5em;border-radius:999px;
  background:var(--bg);color:var(--fg);border:1.5px solid var(--bd);
  cursor:pointer;text-decoration:none;white-space:nowrap;
  transition:transform .2s var(--ease), box-shadow .2s var(--ease), background .2s var(--ease), color .2s ease;
  box-shadow:0 1px 2px rgba(140,106,51,.25), 0 12px 26px rgba(140,106,51,.24);
}
.btn:hover{transform:translateY(-2px);background:var(--brass-deep);box-shadow:0 4px 8px rgba(140,106,51,.3),0 18px 34px rgba(140,106,51,.3)}
.btn:active{transform:translateY(0)}
.btn--ghost{--bg:transparent;--fg:var(--ink);--bd:var(--line);box-shadow:none;font-weight:600}
.btn--ghost:hover{background:var(--paper);--bd:var(--brass);color:var(--brass-deep);box-shadow:var(--shadow-sm)}
.btn--lg{padding:.95em 1.8em;font-size:1.02rem}
.btn--on-dark.btn--ghost{--fg:#fff;--bd:rgba(231,200,146,.4)}
.btn--on-dark.btn--ghost:hover{background:rgba(231,200,146,.08);--bd:var(--brass-glow);color:#fff}
.btn-row{display:flex;flex-wrap:wrap;gap:.85rem;align-items:center}
.arrow{transition:transform .2s var(--ease)}
.btn:hover .arrow,.textlink:hover .arrow{transform:translateX(3px)}

.textlink{
  color:var(--brass-deep);text-decoration:none;font-weight:600;
  display:inline-flex;align-items:center;gap:.45ch;
  border-bottom:1.5px solid var(--brass-line);padding-bottom:1px;
  transition:border-color .2s var(--ease),color .2s var(--ease);
}
.textlink:hover{color:var(--ink);border-color:var(--brass)}

/* inline prose link — wraps naturally across lines (unlike the inline-flex .textlink) */
a.ilink{color:var(--brass-deep);font-weight:600;text-decoration:none;border-bottom:1.5px solid var(--brass-line);transition:border-color .2s var(--ease),color .2s var(--ease)}
a.ilink:hover{color:var(--ink);border-color:var(--brass)}
.dark a.ilink{color:var(--brass-glow);border-color:rgba(231,200,146,.4)}
.dark a.ilink:hover{color:#fff;border-color:var(--brass-glow)}

/* ---------- header / nav ---------- */
.site-header{
  position:sticky;top:0;z-index:80;
  background:rgba(237,241,245,.72);
  backdrop-filter:saturate(150%) blur(14px);
  -webkit-backdrop-filter:saturate(150%) blur(14px);
  border-bottom:1px solid transparent;
  transition:border-color .25s ease, background .25s ease;
}
.site-header.scrolled{border-bottom-color:var(--line);background:rgba(237,241,245,.9)}
/* Bar layout (2026-09-09). The header is the ONE thing on the site that is not inside the
   1180 container: the brand sits at the window's left edge and the actions at its right, with
   the primary links centred on the PAGE between them. `1fr auto 1fr` is what makes the centre
   truly page-centred — the two flexible columns are equal by definition, so the middle column
   lands on the page's axis no matter how wide the brand is. Centring the links inside the
   leftover space instead would push them ~175px right of centre, which is the thing that
   looks almost-right and reads wrong.
   `.nav__cta` is taken OUT OF FLOW and pinned to the right edge rather than made a third grid
   item. That is deliberate: it keeps the mobile markup untouched — the CTA is still
   the last <li> of .nav__links, so it still rides inside the mobile sheet with no duplicate
   copies of them in the DOM. The cost is that the pinned CTA reserves no space, so the centred
   links can collide with it if the bar is too narrow; that is what the 1180px breakpoint below
   is for. If you ever restructure this, don't "fix" it by duplicating the CTA markup. */
.nav{display:flex;align-items:center;justify-content:space-between;gap:1.2rem;height:74px}
/* CENTRED NAV — only where it actually fits (raised 1151 -> 1400 on 2026-09-11).
   This block pins the links to the BAR's centre and takes the CTA out of flow at the right
   edge. Absolute positioning means no collision detection, so whenever brand + centred links
   grow past the CTA's left edge, the last link slides underneath the button. That is exactly
   what happened when the wordmark took on a third course: the brand went ~275 -> 329px, and
   between 1151 and ~1300 the FAQ link sat under "Book a consultation" (21px of overlap at
   1180, 50px at 1151).
   Below 1400 the bar falls back to the plain flex `space-between` row defined on `.nav`,
   where brand, links and CTA are ordinary siblings that cannot overlap. The centred version
   is the nicer one, so it is kept — just gated to widths that can hold it.
   If you add a nav link or lengthen the wordmark again, re-check this threshold: the centred
   layout needs roughly brand + links + CTA + 150px of slack. */
@media (min-width:1400px){
  .nav{display:grid;grid-template-columns:1fr auto 1fr;position:relative}
  .brand{justify-self:start}
  .nav__links{justify-self:center}
  /* `.nav__links > li` sets position:relative at 0,2,1 — this has to outrank it, hence the
     compound selector rather than a bare `.nav__cta`. */
  .nav__links > li.nav__cta{position:absolute;right:0;top:0;bottom:0;margin-left:0}
}
.brand{display:flex;align-items:center;gap:.7rem;text-decoration:none;color:var(--ink);flex:0 0 auto}
.brand__mark{width:34px;height:34px;flex:0 0 auto;transition:transform .4s var(--ease)}
.brand:hover .brand__mark{transform:rotate(-6deg)}
.brand__name{font-family:var(--serif);font-weight:600;font-size:1.2rem;letter-spacing:-.01em;line-height:1.05}
.brand__name small{display:block;font-family:var(--sans);font-weight:400;font-size:.55rem;letter-spacing:.2em;text-transform:uppercase;color:var(--brass-deep);margin-top:3px;white-space:nowrap}
/* The wordmark carries all three courses as of 2026-09-10. `white-space:nowrap` is load-
   bearing: the brand box sizes to the serif name above, so without it the longer course
   line wraps to two lines even at 1280px, where the nav row still has ~340px to spare.
   On a phone there is no such slack, so tighten the tracking there rather than drop a
   course. Desktop nav links only exist above 1151px. */
@media (max-width:560px){
  .brand__name small{letter-spacing:.11em;font-size:.52rem;white-space:normal}
  /* `.brand` is flex:0 0 auto in the base rule, so it never shrinks and `white-space:normal`
     alone cannot wrap — the brand just pushed the hamburger off-screen at 320px. Letting it
     shrink here is what actually lets the course line wrap on the narrowest phones. */
  .brand{flex:0 1 auto;min-width:0}
  .brand__name{min-width:0}
}
/* `white-space:normal` above is only a release valve for the very narrowest phones. Down to
   375px the tightened line still fits on one row and nothing wraps; at 320px it wraps to two
   rather than pushing the page into a horizontal scroll, which is what nowrap did there. */

.nav__links{display:flex;align-items:center;gap:.1rem;list-style:none;margin:0;padding:0}
.nav__links > li{position:relative}
.nav__links a,.nav__links .navbtn{
  text-decoration:none;color:var(--ink);font-weight:500;font-size:.94rem;font-family:var(--sans);
  padding:.55rem .8rem;border-radius:9px;position:relative;background:none;border:0;cursor:pointer;
  display:inline-flex;align-items:center;gap:.35ch;
  transition:color .16s ease, background .16s ease;
}
.nav__links a:hover,.nav__links .navbtn:hover{color:var(--brass-deep);background:rgba(176,137,74,.08)}
.nav__links a[aria-current="page"]{color:var(--brass-deep)}
.nav__links a[aria-current="page"]::after{
  content:"";position:absolute;left:.8rem;right:.8rem;bottom:.3rem;height:1.5px;background:var(--brass);border-radius:2px}
.navbtn .caret{width:.6em;height:.6em;transition:transform .2s var(--ease);margin-left:.1ch;opacity:.65}

/* dropdown */
.has-drop > .drop{
  position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%) translateY(-6px);
  min-width:248px;background:var(--paper);border:1px solid var(--line);border-radius:14px;
  box-shadow:var(--shadow-md);padding:.5rem;list-style:none;margin:0;
  opacity:0;pointer-events:none;transition:opacity .18s ease,transform .18s var(--ease);z-index:90;
}
.has-drop > .drop::before{content:"";position:absolute;top:-8px;left:0;right:0;height:8px}
/* Open on hover, on KEYBOARD focus, or when the mobile JS sets data-open.
   NOT on :focus-within, which is what this used to say and was a real bug (2026-09-09):
   clicking a .navbtn focuses it, that focus outlives the pointer, and moving to the next
   menu left TWO panels hanging open at once. :has(:focus-visible) keeps the keyboard path
   working — a button matches :focus-visible when tabbed to, but not when clicked — without
   pinning the panel open for a mouse user. The @supports block is the fallback for engines
   without :has(); there the old focus-within behaviour is better than no keyboard access. */
.has-drop:hover > .drop,.has-drop:has(:focus-visible) > .drop,.has-drop[data-open="true"] > .drop{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0)}
@supports not selector(:has(*)){
  .has-drop:focus-within > .drop{opacity:1;pointer-events:auto;transform:translateX(-50%) translateY(0)}
}
.has-drop:hover .navbtn .caret,.has-drop:has(:focus-visible) .navbtn .caret,.has-drop[data-open="true"] .navbtn .caret{transform:rotate(180deg)}
.drop li{margin:0}
.drop a{display:block;padding:.62rem .8rem;border-radius:9px;font-weight:500;font-size:.93rem;color:var(--ink)}
.drop a small{display:block;font-family:var(--sans);font-weight:400;font-size:.78rem;color:var(--slate);margin-top:.1rem;letter-spacing:0;text-transform:none}
.drop a:hover{background:var(--porcelain);color:var(--brass-deep)}

/* Current-page marker inside a dropdown: a bar down the LEFT edge, not the underline the
   top-level links use (2026-09-10). In a vertical list an underline reads as link decoration
   and crowds the item below it, while a left rule reads as a list marker — and a 3px brass
   left rule is already this system's marker elsewhere (.quote-card, .mini-quote).
   It sits inside the item's existing left padding, so nothing shifts between states.
   Insets rather than a height so it spans two-line items (the About menu) and one-line ones
   (Courses) alike. Only the geometry is overridden; content/colour/radius come from the
   base .nav__links a[aria-current] rule, which this outranks at (0,3,2) vs (0,2,2). */
.nav__links .drop a[aria-current="page"]{color:var(--brass-deep)}
.nav__links .drop a[aria-current="page"]::after{
  left:.3rem;right:auto;top:.35rem;bottom:.35rem;width:3px;height:auto}
/* `.drop__sep` (the rule between AP Calculus and AP CSA in the Courses menu) was removed
   2026-09-10 at Shaun's request, markup and all. It only ever showed on desktop — the mobile
   sheet hid it — so removing it makes the two views agree. `.drop__index` was relabelled
   2026-09-10 from "The math path", and again 2026-09-12 to "Courses I tutor": with the divider gone it sits above
   all three items, and AP CSA is not a math course. It now also states the scope boundary
   (CLAUDE.md §4) in the one place every page shows. Precalc, calc and CSA are peers as of
   2026-09-10 — do not reintroduce a divider or a label that groups only two of them. */
.drop__index{font-family:var(--sans);font-size:.62rem;letter-spacing:.16em;text-transform:uppercase;color:var(--brass-deep);padding:.5rem .8rem .3rem;opacity:.8}

/* The Login link that used to sit beside this button was removed 2026-09-12 — dashboards
   are private links, so there is nothing to log in to. `row-reverse` is inert with a single
   child and is kept so the original order returns if a login is ever added back; the CSS for
   it is archived in "Code Notes/Not Shipping Yet/login-page.css". */
.nav__cta{margin-left:.5rem;display:flex;align-items:center;gap:.9rem;flex-direction:row-reverse}
.nav__toggle{display:none;background:none;border:1.5px solid var(--line);border-radius:11px;width:46px;height:42px;cursor:pointer;align-items:center;justify-content:center}
.nav__toggle span,.nav__toggle span::before,.nav__toggle span::after{content:"";display:block;width:19px;height:2px;background:var(--ink);border-radius:2px;transition:transform .24s var(--ease),opacity .18s ease;position:relative}
.nav__toggle span::before{position:absolute;top:-6px}
.nav__toggle span::after{position:absolute;top:6px}
.nav[data-open="true"] .nav__toggle span{background:transparent}
.nav[data-open="true"] .nav__toggle span::before{transform:translateY(6px) rotate(45deg)}
.nav[data-open="true"] .nav__toggle span::after{transform:translateY(-6px) rotate(-45deg)}

/* Nav collapse point raised 940 → 1150 (2026-09-09). The full bar needs 1147px to lay out
   (brand 275 + six links 504 + actions 261 + gap + gutters, measured), so at 940–1090 it was
   overflowing the window by ~67px and every page scrolled sideways — a real bug, present long
   before the bar was restructured. Raising it means iPad landscape (1024) gets the hamburger,
   which is a deliberate trade: a menu is better than a header that scrolls off-screen.
   KEEP IN SYNC with `mobileNav` in main.js. (The centred-nav block above is now gated at
   1400, not 1150 — see its note; the two thresholds are deliberately different.) */
@media (max-width:1150px){
  .nav__toggle{display:inline-flex;order:3}
  .nav__links{
    position:absolute;top:74px;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:.1rem;
    background:var(--paper);border-bottom:1px solid var(--line);
    padding:.9rem var(--gutter) 1.5rem;
    box-shadow:var(--shadow-md);max-height:calc(100vh - 74px);overflow-y:auto;
    transform:translateY(-10px);opacity:0;pointer-events:none;
    transition:transform .24s var(--ease),opacity .18s ease;
  }
  .nav[data-open="true"] .nav__links{transform:translateY(0);opacity:1;pointer-events:auto}
  .nav__links > li{border-bottom:1px solid var(--line-soft)}
  .nav__links a,.nav__links .navbtn{padding:.85rem .4rem;font-size:1.04rem;width:100%;justify-content:space-between;border-radius:0}
  .nav__links a:hover,.nav__links .navbtn:hover{background:none}
  .has-drop > .drop{
    position:static;transform:none;opacity:1;pointer-events:auto;box-shadow:none;border:0;padding:.2rem 0 .6rem 1rem;
    min-width:0;background:none;display:none;
  }
  /* `transform:none` HAS to be repeated here. The shared open rule up top carries
     `translateX(-50%)` — correct for the desktop popover, which is centred under its button
     — and `.has-drop[data-open="true"] > .drop` (0,3,0) outranks the `.has-drop > .drop`
     (0,2,0) reset a few lines above, so the reset lost and every open submenu inside the
     mobile sheet was translated 483px off the left edge. It looked like the sub-pages
     "didn't appear": the <li>s were there, laid out, reserving height, just parked
     off-screen. Long-standing — it only surfaced once the collapse point moved to 1150 and
     a desktop-sized window started using the sheet. (2026-09-10) */
  .has-drop[data-open="true"] > .drop{display:block;transform:none}
  .has-drop[data-open="true"] .navbtn .caret{transform:rotate(180deg)}
  /* In the sheet the item's left padding is only .4rem and .drop is indented 1rem, so the
     desktop offset would nearly touch the label. Park the bar in that indent gutter. */
  .nav__links .drop a[aria-current="page"]::after{left:-.6rem;top:.5rem;bottom:.5rem}
  .nav__cta{order:2;margin:1rem 0 0;flex-direction:column;align-items:stretch;width:100%}
  .nav__cta .btn{width:100%;justify-content:center}
}

/* ---------- HERO (dark, signature) ---------- */
.hero{
  position:relative;overflow:hidden;color:var(--ink-on-dark);
  background:
    radial-gradient(120% 100% at 82% 10%, #1e3a58 0%, transparent 55%),
    linear-gradient(165deg, #12293f 0%, #0E2138 46%, #0b1a2c 100%);
  background-color:var(--ink);
  padding-block:clamp(3rem,7vw,6rem) clamp(3.5rem,8vw,7rem);
}
.hero__glow{position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(60% 55% at 78% 18%, rgba(176,137,74,.22), transparent 62%);opacity:.9}
.hero__grid{position:relative;display:grid;grid-template-columns:1.06fr .94fr;gap:clamp(1.5rem,4vw,3.75rem);align-items:center}
.hero__eyebrow{color:var(--brass-glow);margin-bottom:1.25rem}
.hero__eyebrow::before{color:var(--brass-glow)}
.hero h1{font-size:clamp(2.35rem,4.9vw,4rem);font-weight:500;letter-spacing:-.022em;color:#fff}
.hero h1 em{font-style:italic;color:var(--brass-glow)}
.hero__sub{margin-top:1.5rem;max-width:42ch;color:var(--slate-on-dark);font-size:clamp(1.08rem,1.3vw,1.24rem);line-height:1.6}
.hero__cta{margin-top:2rem}
.hero__meta{margin-top:clamp(2.2rem,4vw,3rem);display:flex;flex-wrap:wrap;gap:.55rem;justify-content:center;max-width:var(--wrap-narrow);margin-inline:auto}
.tag{font-family:var(--sans);font-size:.71rem;letter-spacing:.03em;color:var(--slate);
  background:var(--paper);border:1px solid var(--line);border-radius:999px;padding:.34rem .75rem;white-space:nowrap}
.tag--dark{background:rgba(255,255,255,.04);border-color:var(--line-on-dark);color:var(--slate-on-dark)}
.hero__art{position:relative}
.curve-fig{width:100%;height:auto;filter:drop-shadow(0 30px 50px rgba(0,0,0,.35))}
/* Framed portrait in the hero. Wide: under the curve. Narrow: beside it (880px block).
   This replaced a bare transparent cut-out (2026-09-03) — on the navy the cut-out had
   nothing holding it, and the fade we used to hide the photo's mid-forearm crop just made
   him dissolve. A card gives the photo an edge to sit against, and 4:5 (not square, not a
   circle) is the one ratio that keeps the crossed-arms pose intact.
   The frame is deliberately the same porcelain-gradient + brass-hairline treatment as
   `.portrait-card`, so the two portraits on the site read as one design idea. */
.hero__portrait{margin:.4rem auto 0;max-width:252px}
.hero__portrait-frame{overflow:hidden;aspect-ratio:1/1;border-radius:var(--radius-lg);
  border:1px solid var(--brass-line);box-shadow:var(--shadow-md);
  background:radial-gradient(120% 120% at 50% 8%,#fff,var(--porcelain) 55%,var(--porcelain-2))}
.hero__portrait-frame img{width:100%;height:100%;display:block;
  object-fit:cover;object-position:center 8%}

@media (max-width:880px){
  .hero__grid{grid-template-columns:1fr;gap:2.25rem}
  .hero__art{order:-1;max-width:580px;margin-inline:auto;
    display:grid;grid-template-columns:1fr minmax(0,.56fr);align-items:end;gap:1.1rem}
  .hero__portrait{margin:0;max-width:none}
  .hero__sub{max-width:52ch}
  /* Stacked hero: the art above and the credential tags below are both centred, so a
     left-hugging button row was the only thing off the centre axis. The text itself stays
     left — the h1 is long enough that centring it rags badly. */
  .hero__cta{justify-content:center}
}
@media (max-width:560px){
  /* At phone widths the two-up art gets tight: at 375px the default split leaves the
     portrait ~123px wide, which is too small to read as a face. Give it a bigger share and
     close the gap. */
  .hero__art{grid-template-columns:1fr minmax(0,.72fr);gap:.6rem}
}
@media (max-width:460px){
  /* Narrow enough that centring two pills leaves awkward gaps — give them the full measure
     and a real tap target instead. */
  .hero__cta{display:grid;gap:.7rem}
  .hero__cta .btn{width:100%;justify-content:center}
}

/* ---------- animated curve (signature) ---------- */
.curve .axis{stroke:var(--line-on-dark);stroke-width:1.2}
.curve .grid{stroke:rgba(167,186,204,.08);stroke-width:1}
.curve .area{fill:rgba(176,137,74,.16);opacity:0}
.curve .fx{fill:none;stroke:#fff;stroke-width:3;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:1}
.curve .tangent{stroke:var(--brass-glow);stroke-width:2.2;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:1;opacity:0}
.curve .pt{fill:var(--brass-glow);opacity:0;transform-box:fill-box;transform-origin:center}
.curve .lbl{font-family:var(--mono);font-size:13px;fill:var(--slate-on-dark);opacity:0}
.curve .lbl--fx{fill:#fff}
.curve .lbl--d{fill:var(--brass-glow)}
.curve .lbl-int{font-family:var(--mono);font-size:12px;fill:var(--brass-glow);opacity:0}

/* light variant of the animated curve (used on light pages) */
.curve--light .axis{stroke:var(--line)}
.curve--light .area{fill:var(--brass-soft)}
.curve--light .fx{stroke:var(--ink)}
.curve--light .tangent{stroke:var(--brass)}
.curve--light .pt{fill:var(--brass)}
.curve--light .lbl{fill:var(--slate)}
.curve--light .lbl--fx{fill:var(--ink-2)}
.curve--light .lbl--d{fill:var(--brass-deep)}
.curve--light .lbl-int{fill:var(--brass-deep)}

.curve.run .area{animation:area-in 1.1s var(--ease) .9s forwards}
.curve.run .fx{animation:draw 1.6s var(--ease) .15s forwards}
.curve.run .tangent{animation:draw 1s var(--ease) 1.2s forwards, fade-in .4s ease 1.2s forwards}
.curve.run .pt{animation:pop .5s var(--ease) 1.4s forwards}
.curve.run .lbl--fx{animation:fade-in .6s ease 1.55s forwards}
.curve.run .lbl--d{animation:fade-in .6s ease 1.75s forwards}
.curve.run .lbl-int{animation:fade-in .6s ease 1.35s forwards}
@keyframes draw{to{stroke-dashoffset:0}}
@keyframes area-in{from{opacity:0}to{opacity:1}}
@keyframes fade-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
@keyframes pop{0%{opacity:0;transform:scale(.4)}70%{transform:scale(1.25)}100%{opacity:1;transform:scale(1)}}

/* ---------- generic reveal ---------- */
.reveal{opacity:0;transform:translateY(20px);transition:opacity .8s var(--ease-out),transform .8s var(--ease-out)}
.reveal.in{opacity:1;transform:none}
.reveal[data-d="1"]{transition-delay:.09s}
.reveal[data-d="2"]{transition-delay:.18s}
.reveal[data-d="3"]{transition-delay:.27s}
.reveal[data-d="4"]{transition-delay:.36s}

/* ---------- surfaces / cards ---------- */
.panel{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm)}
.grid{display:grid;gap:clamp(1rem,2vw,1.5rem)}
/* A grid of .unit cards is text, not furniture: at the full 1560 shell each card ran 724px
   for a two-line description. Every course page's unit count divides by two (4, 8, 4, and
   the BC pair), so a third column would strand a card on each one. Keep two columns and cap
   the grid at the shell's floor instead, which lands each card near 550px. */
.grid:has(> .unit){max-width:1180px;margin-inline:auto}
.grid-2{grid-template-columns:repeat(2,1fr)}
.grid-3{grid-template-columns:repeat(3,1fr)}
@media (max-width:840px){.grid-3{grid-template-columns:1fr}.grid-2{grid-template-columns:1fr}}

.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(1.5rem,2.6vw,2.1rem);
  box-shadow:var(--shadow-sm);transition:transform .25s var(--ease),box-shadow .25s var(--ease),border-color .25s var(--ease);
  position:relative;height:100%}
.card--link{cursor:pointer}
.card--link:hover{transform:translateY(-5px);box-shadow:var(--shadow-md);border-color:var(--brass-line)}
.card h3{margin-bottom:.55rem}
.card__kicker{font-family:var(--sans);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;color:var(--brass-deep);margin-bottom:.7rem}
.card__foot{margin-top:1.2rem}

/* subject cards with the mini-curve mark */
.subject-card{display:block;text-decoration:none;color:inherit}
.subject-card .mini-curve{height:36px;width:68px;margin-bottom:1.1rem;overflow:visible}
.subject-card .mini-curve path{transition:stroke-dashoffset .8s var(--ease)}

/* "who this is for" check-list */
.check-list{list-style:none;margin:0;padding:0;display:grid;gap:1rem}
/* Independent stacks prevent a tall item in one column from creating space in the other. */
.check-list-columns{display:grid;gap:1rem}
/* two-column variants (single column on small screens) */
@media (min-width:680px){
  .check-list-columns{grid-template-columns:1fr 1fr;gap:clamp(1.6rem,4vw,3rem)}
  .check-list--row{grid-template-columns:1fr 1fr;gap:.85rem clamp(1.6rem,4vw,3rem)}
}
.check-list li{position:relative;padding-left:2.3rem;line-height:1.58}
.check-list li::before{
  content:"";position:absolute;left:0;top:.12em;width:1.5rem;height:1.5rem;border-radius:50%;
  background:var(--brass-soft);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 14 14'%3E%3Cpath d='M2 7.5 L6 11 L12 3' fill='none' stroke='%238C6A33' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:15px}

/* problem-list (subject "why it trips them up") */
.reason-list{list-style:none;margin:0;padding:0;display:grid;gap:1.05rem}
.reason-list li{position:relative;padding-left:1.9rem;line-height:1.58}
.reason-list li::before{content:"";position:absolute;left:.15rem;top:.62em;width:8px;height:8px;border-radius:50%;
  background:var(--brass);box-shadow:0 0 0 4px var(--brass-soft)}
.reason-list li strong{color:var(--ink)}

/* numbered process (real order) */
.steps{list-style:none;margin:0;padding:0;counter-reset:step;display:grid;gap:1.15rem}
.steps li{position:relative;padding-left:3.4rem;min-height:2.3rem}
.steps li::before{counter-increment:step;content:counter(step);
  position:absolute;left:0;top:-.1rem;width:2.3rem;height:2.3rem;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-family:var(--sans);font-size:.95rem;font-weight:500;color:var(--brass-deep);
  border:1.5px solid var(--brass-line);background:var(--paper)}
.steps li strong{color:var(--brass-deep)}
.dark .steps li strong{color:var(--brass-glow)}

/* dark feature section */
.dark{background:var(--ink);color:var(--ink-on-dark);position:relative;overflow:hidden}
.dark--grad{background:linear-gradient(165deg,#12293f 0%,#0E2138 55%,#0b1a2c 100%)}
.dark .eyebrow,.dark .eyebrow::before{color:var(--brass-glow)}
.dark h2,.dark h3,.dark h1{color:#fff}
.dark p{color:var(--slate-on-dark)}
.dark .lede{color:var(--slate-on-dark)}
.dark .textlink{color:var(--brass-glow);border-color:rgba(231,200,146,.4)}
.dark .textlink:hover{color:#fff;border-color:var(--brass-glow)}
.dark-curve{position:absolute;inset:0;pointer-events:none;opacity:.55}

.pull-quote{font-family:var(--serif);font-size:clamp(1.4rem,2.7vw,2.15rem);line-height:1.34;color:#fff;font-weight:400;letter-spacing:-.012em}
.pull-quote .em{color:var(--brass-glow);font-style:italic}
.quote-cite{margin-top:1.5rem;font-family:var(--sans);font-size:.8rem;letter-spacing:.03em;color:var(--slate-on-dark)}

/* the promise block — dual "your job / my job" */
.promise{display:grid;gap:1rem;margin:0}
@media (min-width:760px){.promise{grid-template-columns:1fr 1fr}}
.promise__row{display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:start;
  background:rgba(255,255,255,.03);border:1px solid var(--line-on-dark);border-radius:14px;padding:1.15rem 1.35rem}
.promise__tag{font-family:var(--sans);font-size:.66rem;letter-spacing:.15em;text-transform:uppercase;color:var(--brass-glow);
  border:1px solid rgba(231,200,146,.4);border-radius:999px;padding:.35rem .7rem;white-space:nowrap;margin-top:.15rem}
.promise__row p{margin:0;color:#eaf0f6;font-size:1.04rem}

/* testimonials */
.quote-card{background:var(--paper);border:1px solid var(--line);border-left:3px solid var(--brass);border-radius:var(--radius);
  padding:clamp(1.5rem,2.5vw,2rem);height:100%;box-shadow:var(--shadow-sm);
  transition:transform .25s var(--ease),box-shadow .25s var(--ease)}
.quote-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
.quote-card blockquote{margin:0;font-family:var(--serif);font-size:1.14rem;line-height:1.52;color:var(--ink-2)}
.quote-card blockquote::before{content:"\201C";font-family:var(--serif);font-size:2.6rem;line-height:0;color:var(--brass-line);display:block;height:.6em}
.quote-card figcaption{margin-top:1.1rem;font-family:var(--sans);font-size:.75rem;letter-spacing:.03em;color:var(--slate)}
.quote-card figcaption b{color:var(--brass-deep);font-weight:600}
.quote-card--dark{background:rgba(255,255,255,.03);border-color:var(--line-on-dark);border-left-color:var(--brass-glow)}
.quote-card--dark blockquote{color:#eef3f8}
.quote-card--dark blockquote::before{color:rgba(231,200,146,.45)}
.quote-card--dark figcaption{color:var(--slate-on-dark)}
.quote-card--dark figcaption b{color:var(--brass-glow)}

/* inline pull quote inside prose flow */
.mini-quote{border-left:3px solid var(--brass);background:var(--paper);border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  padding:1.2rem 1.5rem;box-shadow:var(--shadow-sm);margin:1.8em 0}
.mini-quote p{margin:0;font-family:var(--serif);font-size:1.14rem;line-height:1.5;color:var(--ink-2)}
.mini-quote cite{display:block;margin-top:.7rem;font-family:var(--sans);font-style:normal;font-size:.75rem;letter-spacing:.03em;color:var(--slate)}
.mini-quote cite b{color:var(--brass-deep)}

/* ---------- testimonial cards (with photo) ---------- */
/* Testimonials get one signature look nothing else on the site shares:
   a warm cream fill + a full antique-brass border + the brass photo ring. */
.tcard{position:relative;background:linear-gradient(180deg,#FFFFFF 0%,#FCF3DE 62%,#F4E4BF 100%);border:1.5px solid var(--brass-line);border-radius:var(--radius-lg);
  padding:clamp(1.55rem,2.6vw,2.15rem);box-shadow:var(--shadow-md);height:100%;
  transition:transform .3s var(--ease),box-shadow .3s var(--ease)}
.tcard blockquote{margin:0;font-family:var(--serif);font-size:1.14rem;line-height:1.52;color:var(--ink-2)}
.tcard__by{display:flex;align-items:center;gap:.85rem;margin-top:1.35rem}
.tcard__by img{width:54px;height:54px;flex:0 0 auto;border-radius:50%;object-fit:cover;
  border:2px solid var(--paper);box-shadow:0 0 0 1.5px var(--brass-line),var(--shadow-sm)}
.tcard__who b{display:block;font-family:var(--sans);color:var(--brass-deep);font-weight:600;font-size:.98rem;line-height:1.2}
.tcard__who span{display:block;font-size:.84rem;color:var(--slate);line-height:1.35;margin-top:.15rem}
/* line 1 = the course they took with me; line 2 (optional) = where they landed.
   Second line recedes so the pair doesn't read as one wrapped run-on. */
.tcard__who span + span{font-size:.79rem;opacity:.82}

/* dark context */
.tcard--dark{background:rgba(255,255,255,.03);border-color:var(--line-on-dark);box-shadow:var(--shadow-sm)}
.tcard--dark blockquote{color:#eef3f8}
.tcard--dark blockquote::before{color:rgba(231,200,146,.45)}
.tcard--dark .tcard__by img{border-color:var(--ink-2);box-shadow:0 0 0 1.5px rgba(231,200,146,.5)}
.tcard--dark .tcard__who b{color:var(--brass-glow)}
.tcard--dark .tcard__who span{color:var(--slate-on-dark)}

/* grid used on the dedicated page + in-flow sections */
.tgrid{display:grid;gap:clamp(1.1rem,2.2vw,1.6rem);grid-template-columns:repeat(2,1fr)}
.tgrid--3{grid-template-columns:repeat(3,1fr)}
@media (max-width:900px){.tgrid,.tgrid--3{grid-template-columns:1fr}}

/* angled, offset "pinned" testimonial for single in-flow placements (desktop only).
   Sprinkled course/story cards tilt UP toward the right; the dedicated Testimonials page stays flat. */
.tcard--float{max-width:var(--tcard-max);transform:rotate(-2.3deg)}
.tcard--float:hover{transform:rotate(0);box-shadow:var(--shadow-lg)}
.tcard--float.tcard--right{margin-left:auto;transform:rotate(-2.3deg)}
.tcard--float.tcard--right:hover{transform:rotate(0)}
/* Narrow: lie flat — but KEEP the width cap. A testimonial stretched across the full
   column reads as a wall of text, not as a pinned note. Margins are deliberately NOT
   reset here: `.tcard--right` must keep its `margin-left:auto` or it strands dead space
   on the right in the 520–760px band, where the cap bites but the column is still wide. */
@media (max-width:760px){
  .tcard--float,.tcard--float.tcard--right{transform:none}
}

/* one centered, slanted "pinned" testimonial in flow */
.tsolo{display:flex;justify-content:center;margin-top:clamp(1.6rem,3vw,2.4rem)}
.tsolo .tcard--float{margin:0}

/* two slanted testimonials side by side, tilting toward each other */
.tpair{display:flex;flex-wrap:wrap;gap:clamp(1.4rem,3.5vw,2.8rem);justify-content:center;align-items:flex-start}
.tpair .tcard--float{flex:1 1 440px;margin:0}
.tcard--float.tcard--alt{transform:rotate(2.3deg)}
.tcard--float.tcard--alt:hover{transform:rotate(0)}
@media (max-width:640px){
  .tpair{gap:1.2rem}
  .tpair .tcard--float,.tpair .tcard--float.tcard--alt{transform:none}
}

/* ---------- "How I fell into this" — the coaster-to-schoolhouse line drawing ----------
   Faint, literal illustration of the paragraph it sits behind (roller coasters → teaching).
   Anchored to the BOTTOM of its band with preserveAspectRatio="xMidYMax meet" so the ground
   line always sits on the band's floor no matter how tall the copy runs; the section clips
   the top when the copy is short. One opacity knob: --coaster-ink. If you raise it past
   about .3 the drawing starts fighting the prose — don't.
   Lowered .22 → .16 on 2026-09-09. The prose measure went 730px → 860px the same day, so
   the copy now runs across the schoolhouse around a 900–1000px viewport instead of stopping
   beside it; at .16 the drawing reads as texture under the text rather than as lines
   crossing it. .12 is about the floor before the schoolhouse stops registering at all. */
.coaster-band{position:relative;overflow:hidden;--coaster-ink:.16}
.coaster-bg{
  position:absolute;left:0;right:0;bottom:clamp(.5rem,1.4vw,1.1rem);width:100%;height:auto;
  pointer-events:none;opacity:var(--coaster-ink);
  fill:none;stroke:var(--brass);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
}
.coaster-bg__track{stroke-width:2.6}
.coaster-bg__posts{stroke-width:1.4;opacity:.7}
.coaster-bg__ground{stroke:var(--brass);stroke-width:1.4;opacity:.7}
.coaster-bg__train{stroke-width:2;opacity:.95}
.coaster-bg__school{stroke-width:2.2}
/* The band's own copy must always win. The prose sits in normal flow above the absolute
   SVG, but give it an explicit stacking context so nothing here can ever paint over it. */
.coaster-band > .wrap{position:relative;z-index:1}
@media (max-width:640px){
  /* At phone widths the drawing scales down to a scribble and the schoolhouse is unreadable.
     Better to drop it than to ship a smudge. */
  .coaster-bg{display:none}
}

/* ---------- portrait / headshot ---------- */
/* framed profile photo — soft porcelain-to-brass panel behind a cut-out figure */
.portrait-card{max-width:330px;margin:0 auto}
.portrait-card__frame{position:relative;border-radius:var(--radius-lg);overflow:hidden;aspect-ratio:1/1;
  background:radial-gradient(120% 120% at 50% 8%,#fff,var(--porcelain) 55%,var(--porcelain-2));
  border:1px solid var(--brass-line);box-shadow:var(--shadow-md)}
.portrait-card__frame img{width:100%;height:100%;object-fit:cover;object-position:center 12%}
.portrait-card figcaption{margin-top:.95rem;text-align:center;font-family:var(--mono);
  font-size:.7rem;letter-spacing:.13em;text-transform:uppercase;color:var(--brass-deep)}

/* featured "hero" testimonial */
.tfeature{position:relative;background:linear-gradient(180deg,#fff,var(--paper));border:1px solid var(--brass-line);
  border-radius:var(--radius-lg);padding:clamp(1.7rem,3.4vw,2.9rem);box-shadow:var(--shadow-md);
  display:grid;grid-template-columns:auto 1fr;gap:clamp(1.3rem,3vw,2.4rem);align-items:center;
  margin-bottom:clamp(1.3rem,2.6vw,2rem)}
.tfeature__photo{width:clamp(84px,9vw,116px);height:clamp(84px,9vw,116px);flex:0 0 auto;border-radius:50%;object-fit:cover;
  border:3px solid #fff;box-shadow:0 0 0 1.5px var(--brass-line),var(--shadow-md)}
.tfeature blockquote{margin:0;font-family:var(--serif);font-size:clamp(1.3rem,2.1vw,1.72rem);line-height:1.4;
  color:var(--ink-2);font-weight:400;letter-spacing:-.01em}
.tfeature .tcard__who{margin-top:1.1rem}
.tfeature .tcard__who b{font-size:1.02rem}
/* The spotlight now carries each student's COMPLETE note (2026-09-11) rather than a trimmed
   pull-quote — Brian's runs ~700 characters. At the display size above that filled more than a
   phone screen and a half, pushing the note list below it out of sight on load. Step the quote
   down to a reading size here; it stays a serif pull-quote on desktop, where the full length
   fits comfortably. If these ever go back to short excerpts, this rule can go with them. */
@media (max-width:640px){
  .tfeature{grid-template-columns:1fr;gap:1.1rem}
  .tfeature blockquote{font-size:1.06rem;line-height:1.52;letter-spacing:0}
}

/* masonry "quote wall" — cards size to their own content (no stretch) */
.twall{column-count:3;column-gap:clamp(1rem,1.8vw,1.4rem)}
.twall > .tcard{display:inline-block;width:100%;height:auto;break-inside:avoid;-webkit-column-break-inside:avoid;
  box-shadow:var(--shadow-sm);margin:0 0 clamp(1rem,1.8vw,1.4rem)}
.twall > .tcard:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
@media (max-width:1000px){.twall{column-count:2}}
@media (max-width:640px){.twall{column-count:1}}

/* spotlight + clickable preview list (dedicated testimonials page) */
#tspot{scroll-margin-top:92px;transition:opacity .2s var(--ease)}
#tspot.swapping{opacity:0}
.tpreviews{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(.8rem,1.5vw,1.15rem);margin-top:clamp(1.5rem,2.8vw,2.15rem)}
@media (max-width:820px){.tpreviews{grid-template-columns:repeat(2,1fr)}}
@media (max-width:520px){.tpreviews{grid-template-columns:1fr}}
.tpreview{font-family:inherit;text-align:left;color:inherit;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--radius);padding:1.1rem 1.2rem;cursor:pointer;display:flex;gap:.85rem;align-items:flex-start;
  box-shadow:var(--shadow-sm);transition:transform .2s var(--ease),box-shadow .2s var(--ease),border-color .2s var(--ease)}
.tpreview:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);border-color:var(--brass-line)}
.tpreview[aria-pressed="true"]{border-color:var(--brass);box-shadow:var(--shadow-md);background:linear-gradient(180deg,#fff,var(--paper))}
.tpreview img{width:46px;height:46px;flex:0 0 auto;border-radius:50%;object-fit:cover;border:2px solid var(--paper);box-shadow:0 0 0 1.5px var(--brass-line)}
.tpreview__b{min-width:0}
.tpreview__q{display:block;font-family:var(--serif);font-size:1.03rem;line-height:1.38;color:var(--ink-2)}
.tpreview__n{display:block;margin-top:.55rem;font-size:.78rem;color:var(--brass-deep);font-weight:600}
.tpreview__n span{color:var(--slate);font-weight:400}
.tpreview__full{display:none}
.tspot-hint{margin-top:1.3rem;font-size:.85rem;color:var(--slate);display:flex;align-items:center;gap:.5ch}

/* credential chips */
.creds{display:flex;flex-wrap:wrap;gap:.55rem;margin-top:.4rem}
.creds .tag{background:var(--paper)}

/* ---------- credential cards: four labelled groups of three (home) ----------
   History: consolidated 2026-08-21 from the two competing credential lists we used to run
   (the home "short version" and the My Story "full version"). Was a 3 · 4 · 3 stack grouped
   by tint alone; restructured 2026-09-09 to 3 · 3 · 3 · 3 with a hairline label per group,
   because the middle argument changed from "leadership" to "other institutions vouched
   for me" and that needed saying out loud, not just shading.
   Labels now carry the grouping, so the styles are free to be quiet — see the palindrome
   note below. Four cards is the most that fit one line at --wrap (1180px): five wrap 4+1.
   If you add a credential, add a group or swap one out; do NOT push a row to four, it
   breaks the 3·3·3·3 rhythm the labels depend on. Keep every blurb to about one line. */
.credgrid{display:grid;gap:clamp(1.7rem,3.2vw,2.4rem);margin-top:clamp(1.8rem,3.5vw,2.6rem)}
/* A group = one hairline label + its row. The gap INSIDE a group is the card gap; the gap
   BETWEEN groups is roughly double, which is what keeps four rows from reading as one
   twelve-card mush. Don't equalize them. */
.credgrid__group{display:grid;gap:clamp(.75rem,1.6vw,1rem)}
/* Deliberately NOT .eyebrow — the section already has one directly above, and a second
   brass ∫ label four more times would fight it. Mono, slate, hairlines out to both edges:
   reads as a divider, i.e. subordinate to the eyebrow. */
.credgrid__label{display:flex;align-items:center;gap:1ch;margin:0;
  font-family:var(--mono);font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--slate);font-weight:500}
.credgrid__label::before,.credgrid__label::after{content:"";flex:1;height:1px;background:var(--line)}
.credgrid__row{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(.75rem,1.6vw,1rem)}
.credcard{flex:1 1 250px;max-width:480px;border-radius:var(--radius);
  padding:clamp(1.05rem,2vw,1.35rem) clamp(1.1rem,2vw,1.4rem);
  border:1px solid var(--line);background:var(--paper);box-shadow:var(--shadow-sm);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease)}
.credcard:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
.credcard b{display:block;font-family:var(--sans);font-weight:600;font-size:.95rem;
  line-height:1.28;color:var(--ink);margin-bottom:.3rem}
.credcard span{display:block;font-size:.88rem;line-height:1.45;color:var(--slate)}

/* ---- The four group styles (2026-09-09, rev 2) ----
   ONE variable, four steps: the colour of the 3px rule across the top of the card. The
   fill is uniform --paper on all twelve cards.
     1 Where I trained         --brass-2    #C39A57  light gold
     2 Trusted by universities --brass-deep #795B2B  dark bronze
     3 Recognized in the field --slate-2    #6b7f92  steel blue
     4 In the classroom        --ink        #0E2138  navy
   Warm pair then cool pair, but the SEPARATION is carried by lightness inside each pair:
   light gold against dark bronze, steel against navy. Rev 2 used --brass/--brass-deep and
   --slate/--ink and both adjacent pairs read as nearly the same colour at 3px — the fix was
   to push 1 and 3 lighter and take the rule to 4px, where hue actually registers.
   If you retune these, the constraint is that each ADJACENT pair must differ in lightness,
   not just in hue; a 4px line is too thin to carry a hue-only difference.
   WHY NOT the obvious alternatives — all five were rendered in the real page first:
     · Mirroring rule position (top·top·bottom·bottom) was rev 1. Rejected: a palindrome
       implies groups 1+4 and 2+3 belong together, and they don't.
     · Ramping the FILL warmer down the page went custard by group 4 — the same reason
       brass was never allowed as a large flat fill on this site.
     · Ramping the fill darker makes whichever end is darkest look like the important one,
       which is the bottom-heavy problem from R139 wearing a different hat.
   Because the fill never changes, no group can look demoted — that's the whole point of
   putting the variation in the rule instead. Don't reintroduce a per-group fill.
   The rule is a background-image, not a real border, so it clips to the card radius and
   leaves the 1px border, shadow and hover system alone. */
.credcard--edu,.credcard--uni,.credcard--field,.credcard--exp{
  background-repeat:no-repeat;background-size:100% 4px;background-position:0 0}
.credcard--edu{background-image:linear-gradient(var(--brass-2),var(--brass-2))}
.credcard--uni{background-image:linear-gradient(var(--brass-deep),var(--brass-deep))}
.credcard--field{background-image:linear-gradient(var(--slate-2),var(--slate-2))}
.credcard--exp{background-image:linear-gradient(var(--ink),var(--ink))}
@media (max-width:900px){
  .credcard{flex:1 1 calc(50% - .5rem);max-width:none}
  /* Once a 3-card row splits 2/1, the leftover card grows to full width. Left alone that
     lands on whichever card wraps last. This forces each row's headline credential to be
     the wide one AND to stay on top, since flex wraps in source order. Every group's
     FIRST card carries --full. */
  .credcard--full{flex-basis:100%}
}
@media (max-width:600px){.credcard{flex:1 1 100%}}

.cred-list{list-style:none;margin:0;padding:0;display:grid;gap:.85rem}
.cred-list li{position:relative;padding-left:1.7rem;line-height:1.5}
.cred-list li::before{content:"";position:absolute;left:0;top:.55em;width:9px;height:9px;border-radius:2px;transform:rotate(45deg);
  background:var(--brass);box-shadow:0 0 0 4px var(--brass-soft)}

/* press band */
.press{background:var(--porcelain-2);border-block:1px solid var(--line)}
.press__quote{font-family:var(--serif);font-style:italic;font-size:clamp(1.2rem,2.2vw,1.6rem);line-height:1.4;color:var(--ink-2)}

/* ---------- proof band: press · testimonial · press (rebuilt 2026-08-01) ----------
   All three are "what other people said about me" — a former student, a columnist, and an
   independent course reviewer — so they share one centred header. Deliberately NOT three
   matching cards: the testimonial keeps the signature slanted brass card and sits in the
   MIDDLE as the anchor; the two press items stay unboxed and editorial on either side.

   Three layouts, and the source order (card → TCPalm → Class Central) is the narrow one,
   so only the two wider layouts do explicit placement:
     ≥1041px  press | CARD | press          — card centred between them
     ≤1040px  press | press  /  CARD        — articles pair up, card below, centred
     ≤620px   CARD / press / press          — stacked, card on top (pure DOM order)

   Dividers are drawn by the columns themselves, positioned into the middle of the grid gap
   via --proof-gap. That's why the gap is a variable and not a literal — if you change the
   gap, change it in one place or the rules land off-centre. */
.proof{
  --proof-gap:clamp(1.8rem,3.6vw,3.2rem);
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.1fr) minmax(0,1fr);
  gap:var(--proof-gap);
  align-items:stretch;      /* columns span the full row so the dividers do too */
  margin-top:clamp(2rem,3.6vw,2.9rem);
}
/* Centered header — this one is deliberately different from every other section header on
   the site, which are left-aligned. Left-aligned it sat over the testimonial column and read
   as that card's header, leaving the press half looking orphaned. Centering it makes it
   plainly the header for ALL THREE. The 60ch cap needs `margin-inline:auto` or the text
   just centers inside a box that's still pinned left. */
.proof__head{max-width:60ch;margin-inline:auto;text-align:center}
/* flex + justify-content:center keeps each column's CONTENT vertically centred while the
   column box itself still stretches to the full row height (which the dividers need). */
.proof__col{min-width:0;position:relative;display:flex;flex-direction:column;justify-content:center}
/* centred at every width — the link belongs to the card above it, and the card fills its
   column, so centring in the column centres it under the card */
.proof__more{margin-top:1.6rem;text-align:center}
.proof .tcard--float{margin:0}   /* keeps the global --tcard-max cap; just kills the auto-centering */
.proof__press{text-align:center}
/* the press quote is set for a half-width column; in thirds it needs to come down a step
   or the pull-quote wraps into a narrow ladder */
.proof__press .press__quote{font-size:clamp(1.12rem,1.45vw,1.34rem)}

/* wide: card in the middle, a hairline in each gap beside it */
.proof__card{grid-column:2;grid-row:1}
.proof__press--a{grid-column:1;grid-row:1}
.proof__press--b{grid-column:3;grid-row:1}
.proof__card::before,.proof__card::after{
  content:"";position:absolute;top:.35rem;bottom:.35rem;width:1px;
  background:linear-gradient(180deg,transparent,var(--line) 18%,var(--line) 82%,transparent);
}
.proof__card::before{left:calc(var(--proof-gap) / -2)}
.proof__card::after{right:calc(var(--proof-gap) / -2)}

/* ---- medium: the two articles pair up, the card drops below and centres ----
   1140px, not 1040px: `.wrap` caps at ~1092px, so three columns bottom out around 324px
   each and shrink from there. Below ~1140 the press columns fall under ~300px and the
   centred copy starts laddering — two wider columns read better than three cramped ones. */
@media (max-width:1140px){
  /* set the VARIABLE, never `gap` directly — the dividers offset by half of it */
  .proof{--proof-gap:clamp(2rem,4.5vw,2.8rem);grid-template-columns:repeat(2,minmax(0,1fr))}
  .proof__press--a{grid-column:1;grid-row:1}
  .proof__press--b{grid-column:2;grid-row:1}
  .proof__card{grid-column:1 / -1;grid-row:2}
  .proof__card .tcard--float{margin-inline:auto}
  /* card's side rules become one rule above it; the vertical rule moves between the pair */
  .proof__card::after{display:none}
  .proof__card::before{
    left:0;right:0;top:calc(var(--proof-gap) / -2);bottom:auto;width:auto;height:1px;
    background:linear-gradient(90deg,transparent,var(--line) 18%,var(--line) 82%,transparent);
  }
  .proof__press--b::before{
    content:"";position:absolute;top:.35rem;bottom:.35rem;left:calc(var(--proof-gap) / -2);width:1px;
    background:linear-gradient(180deg,transparent,var(--line) 18%,var(--line) 82%,transparent);
  }
}

/* ---- narrow: all three stacked, card on top (source order — no placement needed) ----
   820px, not 620px: the press copy is centred, so two columns below ~820 gives each about
   32 characters a line and the paragraphs ladder into unreadable slivers. Stacking earlier
   reads far better than defending the two-up layout down to phone widths. */
@media (max-width:820px){
  .proof{--proof-gap:clamp(2.2rem,6vw,2.8rem);grid-template-columns:1fr}
  /* the rows MUST be reset too, not just the columns — the 1040px block pins both articles
     to row 1 and the card to row 2, and leaving that in place stacks the two articles on
     top of each other in the single column. (Cost me a debugging round; don't remove.) */
  .proof__card{grid-column:1;grid-row:1}
  .proof__press--a{grid-column:1;grid-row:2}
  .proof__press--b{grid-column:1;grid-row:3}
  /* stacked, a press block would otherwise run the full wrap width — far wider than the
     capped card above it. Hold it to a readable measure so the blocks feel related. */
  .proof__press > *{max-width:58ch;margin-inline:auto}
  .proof__card::before,.proof__card::after{display:none}
  .proof__press--a::before,.proof__press--b::before{
    content:"";position:absolute;left:0;right:0;top:calc(var(--proof-gap) / -2);bottom:auto;
    width:auto;height:1px;
    background:linear-gradient(90deg,transparent,var(--line) 18%,var(--line) 82%,transparent);
  }
}

/* Editorial correction inside a real quote (2026-08-01). These are students' own words, and
   some are years old — when a fact has since moved on (Zach has graduated), we show the
   change rather than silently rewriting someone's sentence. Struck text stays legible but
   recedes; the bracketed replacement is plain, per normal editorial convention. */

/* video frame */
.video-frame{position:relative;border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-lg);border:1px solid var(--line);background:var(--paper)}
.video-frame iframe{width:100%;aspect-ratio:16/9;border:0;display:block}
.video-caption{margin-top:1rem;font-family:var(--sans);font-size:.76rem;letter-spacing:.05em;color:var(--slate);text-align:center}
/* click-to-play poster — nothing loads or animates until the parent presses play */
.video-facade{position:relative;display:block;width:100%;aspect-ratio:16/9;border:0;cursor:pointer;
  background:radial-gradient(120% 140% at 50% 30%,var(--ink-3),var(--ink) 72%);overflow:hidden;
  transition:filter .25s var(--ease)}
.video-facade:hover{filter:brightness(1.06)}
.video-facade__bg{position:absolute;inset:0;background:
  radial-gradient(60% 90% at 78% 22%,rgba(231,200,146,.18),transparent 60%);pointer-events:none}
.video-facade__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:clamp(58px,7vw,78px);height:clamp(58px,7vw,78px);border-radius:50%;
  display:grid;place-items:center;background:rgba(251,252,254,.94);
  box-shadow:0 0 0 1.5px var(--brass-line),var(--shadow-md);transition:transform .25s var(--ease)}
.video-facade:hover .video-facade__play{transform:translate(-50%,-50%) scale(1.06)}
.video-facade__play svg{width:42%;height:42%;fill:var(--ink);margin-left:8%}
.video-facade__label{position:absolute;left:0;right:0;bottom:clamp(1rem,2.4vw,1.6rem);
  font-family:var(--serif);font-size:clamp(1.05rem,2vw,1.35rem);color:#fff;text-align:center;
  letter-spacing:-.01em;text-shadow:0 1px 12px rgba(14,33,56,.5);pointer-events:none}

/* ---------- prose (article-style pages) ---------- */
.prose{max-width:72ch}
/* when a prose block is also a .narrow reading column, keep them the same width so the
   hero, prose, and any other narrow sections on a reading page share one measure */
.wrap.narrow.prose{max-width:var(--wrap-narrow)}
/* neutralize default block margins on direct children, then let ONE engine add the gap.
   (do the reset with the same specificity as the engine so nothing silently out-ranks it) */
.prose > *{margin-block:0}
.prose > * + *{margin-top:var(--para-gap)}
.prose h2{font-size:clamp(1.5rem,2.7vw,2.1rem);margin-top:1.7em}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:1.28rem;margin-top:1.5em}
.prose > h2 + *,.prose > h3 + *{margin-top:.5em}   /* first block under a heading sits close to it */
.prose ul{padding-left:0;list-style:none;display:grid;gap:.85rem}
.prose ul li{position:relative;padding-left:1.7rem;line-height:1.58}
.prose ul li::before{content:"";position:absolute;left:.15rem;top:.62em;width:7px;height:7px;border-radius:50%;
  background:var(--brass);box-shadow:0 0 0 4px var(--brass-soft)}
.prose ol{padding-left:1.3em;display:grid;gap:.7rem}
.prose blockquote{padding:1.2em 1.5em;background:var(--paper);border-left:3px solid var(--brass);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;box-shadow:var(--shadow-sm)}
.prose blockquote p{font-family:var(--serif);font-size:1.14rem;line-height:1.5;color:var(--ink-2)}
.prose strong{color:var(--ink)}

/* ---------- per-course background motif (subtle, fixed watermark) ---------- */
body.theme-precalc,body.theme-calc,body.theme-cs{
  background-color:var(--porcelain);
  background-repeat:no-repeat;
  background-position:center -30px;
  background-size:min(1180px,145%) auto;
  background-attachment:fixed;
}
body.theme-precalc{background-image:url("../assets/bg-precalc.svg")}
body.theme-calc{background-image:url("../assets/bg-calc.svg")}
body.theme-cs{background-image:url("../assets/bg-cs.svg")}
@media (max-width:840px){
  body.theme-precalc,body.theme-calc,body.theme-cs{background-size:min(760px,190%) auto;background-attachment:scroll}
}

/* ---------- page hero (interior, light) ---------- */
.page-hero{position:relative;padding-block:clamp(2.8rem,6vw,4.75rem) clamp(1.8rem,3.5vw,2.75rem);overflow:hidden}
.page-hero::after{content:"";position:absolute;top:0;right:0;width:min(46%,540px);height:100%;pointer-events:none;
  background:radial-gradient(60% 70% at 100% 0%,var(--brass-soft),transparent 70%)}
.page-hero__inner{position:relative}
.page-hero h1{font-size:clamp(2.1rem,4.4vw,3.35rem);font-weight:500;letter-spacing:-.02em}
/* No measure cap on a hero lede: it fills whatever container the hero is in. A `ch` cap here
   put it at ~590px inside a 1092px hero, narrower than every paragraph below it. Heroes that
   want a short centred measure set it inline (FAQ). (2026-09-09) */
.page-hero .lede{margin-top:1.2rem}
.page-hero .sub-strong{font-size:clamp(1.15rem,1.7vw,1.4rem);color:var(--ink-2);font-family:var(--serif);font-weight:500;line-height:1.4;margin-top:1.1rem;text-wrap:pretty}
/* `pretty`, NOT `balance` (changed 2026-09-09 — balance was R174's fix and it backfired).
   balance evens every line, which on My Story turned a 772px container into lines of 507 and
   554 while the paragraph directly beneath ran the full 772. The lead looked like it was
   trapped in a narrower box than the body copy — the exact complaint R177 was supposed to
   have settled. `pretty` only protects the LAST line from an orphan, so line one fills the
   container (747 of 772, measured) and the right edges line up again. Engines without
   `pretty` fall back to normal wrapping, which is also full-width — the safe direction. */
/* The hero lead takes the full width of whatever container it is in — no measure cap. It is
   a one-sentence headline-adjacent line, not body copy, and capping it at --measure broke it
   onto two ragged lines while the container still had room, which read as an accident.
   Earlier attempts here were a 56ch cap (made it visibly shorter than the .lede below it,
   which looked like a mistake) and then --measure. Don't cap it in `ch` — see --measure. */
/* The course-page hero ran one step WIDER than its body sections for about an hour on
   2026-09-09 (--wrap-hero, 1320). Reverted the same day: it isn't a convention anywhere, and
   it read as drift rather than as an opening. Every hero is now the page's own container
   width. Don't reintroduce a hero-only width — see the note at the top of a course page. */

/* course quick-facts rail */
.factbar{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:1.6rem}
.factbar .tag{background:var(--paper)}

/* two-col split (why-me + facts, etc.) */
.split{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(1.5rem,4vw,3.25rem);align-items:start}
/* The wider shell makes the left column ~816px — about 105 characters a line. The column
   should stay wide (it carries the heading), but its prose gets the system measure. */
.split > div > p{max-width:var(--measure)}
@media (max-width:840px){.split{grid-template-columns:1fr;gap:2rem}}

/* ---------- pricing ---------- */
.price-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(1rem,2vw,1.5rem);align-items:stretch}
@media (max-width:940px){.price-grid{grid-template-columns:1fr}}
.price-card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(1.6rem,2.6vw,2.1rem);
  box-shadow:var(--shadow-sm);display:flex;flex-direction:column;position:relative;height:100%}
.price-card--feature{border-color:var(--brass-line);box-shadow:var(--shadow-md);background:linear-gradient(180deg,#fff,var(--paper))}
.price-card__name{font-family:var(--serif);font-size:1.35rem;color:var(--ink);letter-spacing:-.01em}
.price{font-family:var(--serif);font-size:2.6rem;color:var(--ink);line-height:1;margin:.5rem 0 .1rem;letter-spacing:-.02em}
.price small{font-family:var(--sans);font-size:.72rem;letter-spacing:.04em;color:var(--slate);text-transform:uppercase;display:inline-block;margin-left:.3rem;font-weight:400}
.price-card .desc{color:var(--slate);margin:.5rem 0 1.2rem;font-size:.98rem}
.price-card ul{list-style:none;margin:0 0 1.5rem;padding:0;display:grid;gap:.7rem}
.price-card ul li{position:relative;padding-left:1.7rem;font-size:.95rem;line-height:1.5}
.price-card ul li::before{content:"";position:absolute;left:0;top:.15em;width:1.15rem;height:1.15rem;border-radius:50%;background:var(--brass-soft);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 14 14'%3E%3Cpath d='M2 7.5 L6 11 L12 3' fill='none' stroke='%238C6A33' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:12px}
.price-card .btn{margin-top:auto}
.terms-line{font-family:var(--sans);font-size:.82rem;color:var(--slate);letter-spacing:.01em;margin:-.6rem 0 1.3rem;display:flex;flex-wrap:wrap;gap:.55ch;align-items:baseline}
.terms-line .dot{color:var(--brass);font-weight:700}
.price-foot-note{margin:1.1rem 0 0;font-size:.85rem;color:var(--slate);line-height:1.45}
.price-cta{margin-top:clamp(1.8rem,3vw,2.6rem);text-align:center;display:flex;flex-direction:column;align-items:center;gap:1rem}
.price-cta p{margin:0;max-width:46ch;color:var(--slate)}
.flag{display:inline-flex;align-items:center;gap:.4ch;font-family:var(--sans);font-size:.64rem;letter-spacing:.15em;text-transform:uppercase;
  color:var(--brass-deep);background:var(--brass-soft);border-radius:999px;padding:.3rem .75rem;margin-bottom:1rem;align-self:flex-start}
.flag--foot{margin:1rem 0 0}
.price-note{font-family:var(--sans);font-size:.78rem;color:var(--slate);letter-spacing:.02em}

/* ---------- FAQ accordion ---------- */
.faq-list{display:grid;gap:.9rem;max-width:var(--wrap-narrow);margin-inline:auto}
.faq-item{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-sm);transition:border-color .2s ease}
.faq-item[open]{border-color:var(--brass-line)}
.faq-item summary{list-style:none;cursor:pointer;padding:1.25rem 1.5rem;display:flex;align-items:center;justify-content:space-between;gap:1rem;
  font-family:var(--serif);font-size:1.14rem;font-weight:500;color:var(--ink);letter-spacing:-.01em}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary:hover{color:var(--brass-deep)}
.faq-item .plus{flex:0 0 auto;width:1.5rem;height:1.5rem;position:relative;transition:transform .25s var(--ease)}
.faq-item .plus::before,.faq-item .plus::after{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--brass);border-radius:2px}
.faq-item .plus::before{width:14px;height:2px}
.faq-item .plus::after{width:2px;height:14px;transition:transform .25s var(--ease)}
.faq-item[open] .plus::after{transform:translate(-50%,-50%) rotate(90deg);opacity:0}
.faq-item .faq-body{padding:0 1.5rem 1.4rem;color:var(--slate)}
.faq-item .faq-body p{margin:0 0 1em}
.faq-item .faq-body p:last-child{margin-bottom:0}

/* ---------- article / resources list ---------- */
.article-list{display:grid;gap:1rem;margin-top:2rem}
.article-card{display:flex;gap:1.1rem;align-items:baseline;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:1.35rem 1.6rem;box-shadow:var(--shadow-sm);text-decoration:none;color:inherit;transition:transform .22s var(--ease),box-shadow .22s var(--ease),border-color .22s var(--ease)}
.article-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);border-color:var(--brass-line)}
.article-card .idx{font-family:var(--sans);font-size:.8rem;color:var(--brass-deep);flex:0 0 auto;padding-top:.15rem}
.article-card h3{font-size:1.16rem;margin:0 0 .2rem}
.article-card p{margin:0;color:var(--slate);font-size:.95rem}
.article-card--soon{opacity:.72}
.article-card--soon .soon{font-family:var(--sans);font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--slate);
  border:1px solid var(--line);border-radius:999px;padding:.2rem .55rem;margin-left:auto;flex:0 0 auto;white-space:nowrap}
.article-card--feature{border-color:var(--brass-line);background:linear-gradient(180deg,#fff,var(--paper))}

/* ---------- contact form ---------- */
.field{display:block;margin-bottom:1.15rem}
.field > span{display:block;font-weight:600;font-size:.9rem;margin-bottom:.4rem}
.field > span .opt{font-weight:400;color:var(--slate);font-size:.82rem}
.field input,.field select,.field textarea{
  width:100%;font-family:var(--sans);font-size:1rem;color:var(--ink);
  background:var(--paper);border:1.5px solid var(--line);border-radius:11px;padding:.75rem .9rem;
  transition:border-color .16s ease,box-shadow .16s ease}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--brass);box-shadow:0 0 0 3px var(--brass-soft)}
.field textarea{min-height:120px;resize:vertical}

/* honeypot — parked off-canvas so only bots find it (display:none would let them skip it) */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* submit feedback: "Sending…" in slate, failures in rose */
.form-status{margin-top:1rem;font-size:.95rem;color:var(--slate)}
.form-status.is-error{color:var(--rose);font-weight:500}
.form-status:focus{outline:none}

/* replaces the form once the note is actually delivered */
.form-sent{padding:clamp(1.5rem,3vw,2rem);margin-top:1.4rem}
.form-sent:focus{outline:none}
.form-sent h3{color:var(--ink);margin:.55rem 0 .7rem}
.form-sent p+p{margin-top:var(--para-gap)}

/* "how the call works" list above the booking widget. Became an <ol> 2026-09-11 — these are
   three steps in order, not three facts — so the brass dot is now a brass numeral. The number
   is drawn with a counter rather than list-style:decimal so it can take the mono face and the
   brass colour; list-style markers only inherit the text colour. `list-style:none` therefore
   has to stay, or the browser marker and the counter would both render. */
.how-it-works{list-style:none;margin:1.25rem 0 0;padding:0;counter-reset:howstep}
.how-it-works li{position:relative;padding-left:1.9rem;margin-bottom:.7rem;
  font-size:.95rem;color:var(--slate);line-height:1.55;counter-increment:howstep}
.how-it-works li:last-child{margin-bottom:0}
.how-it-works li::before{content:counter(howstep) ".";position:absolute;left:0;top:0;
  font-family:var(--mono);font-size:.8rem;font-weight:600;line-height:1.85;
  color:var(--brass-deep);font-variant-numeric:tabular-nums}
.how-it-works strong{color:var(--ink);font-weight:600}

/* Cal.com booking widget. NOTE: don't name this `.cal-embed` — Cal's own injected
   stylesheet claims that class and its min-height:300px wins over ours.
   min-height holds the space so the column doesn't jump while the iframe loads;
   Cal auto-resizes the iframe from there. */
.booking-embed{margin-top:1.5rem;min-height:620px;
  border:1px solid var(--line);border-radius:var(--radius);
  background:var(--paper);box-shadow:var(--shadow-sm);overflow:hidden}
.booking-embed iframe{border-radius:var(--radius)}
@media (max-width:900px){.booking-embed{min-height:470px}}


/* ---------- CTA band ---------- */
.cta-band{position:relative;overflow:hidden;background:linear-gradient(165deg,#12293f,#0E2138 60%,#0b1a2c);color:#fff;text-align:center}
.cta-band .eyebrow,.cta-band .eyebrow::before{color:var(--brass-glow)}
.cta-band h2{font-size:clamp(1.7rem,3.2vw,2.55rem);max-width:24ch;margin-inline:auto;color:#fff}
.cta-band p{color:var(--slate-on-dark);max-width:52ch;margin:1rem auto 1.9rem}
.cta-curve{position:absolute;inset:0;opacity:.5;pointer-events:none}

/* ---------- home closing sign-off (home only; interior pages don't close) ---------- */
.signoff{background:var(--ink);color:var(--slate-on-dark);padding-block:1.6rem;border-top:1px solid var(--line-on-dark)}
.signoff .wrap{display:flex;flex-wrap:wrap;gap:.6rem 1.4rem;align-items:center;justify-content:space-between}
.signoff .mono{font-family:var(--sans);font-size:.72rem;letter-spacing:.04em}
.signoff a{color:var(--slate-on-dark);text-decoration:none;transition:color .16s ease}
.signoff a:hover{color:var(--brass-glow)}

/* ---------- misc ---------- */
.skip{position:absolute;left:-999px;top:.5rem;background:var(--ink);color:#fff;padding:.6rem 1rem;border-radius:8px;z-index:200}
.skip:focus{left:.5rem}
.lead-in{font-family:var(--serif);font-size:clamp(1.25rem,2vw,1.55rem);line-height:1.45;color:var(--ink-2);font-weight:500;letter-spacing:-.01em}
/* a single line lifted out of the prose as a styled statement */
.pull-line{font-family:var(--serif);font-style:italic;font-size:clamp(1.4rem,2.6vw,2rem);line-height:1.28;color:var(--brass-deep);letter-spacing:-.012em;margin:0}
/* "Long story short" — the closing summary on How I Teach's Fit section. Porcelain FILL,
   deliberately: that section is paper-coloured and the two .callout cards in it are
   paper-on-paper leaning on their borders, so a fill is the only move left that reads as
   "different thing" rather than as a third card. No shadow for the same reason — shadow is
   what makes the callouts read as cards, and this should sit flat like a plinth.
   The 56ch measure is wider than the 46ch this block used as bare text: padding eats into
   the measure, and at 46ch inside a filled box the copy came out as a cramped gray pill. */
.summary-panel{background:var(--porcelain-2);border:1px solid var(--line);
  border-radius:var(--radius);padding:clamp(1.5rem,2.8vw,2.1rem) clamp(1.4rem,2.6vw,2rem);
  max-width:56ch;margin:clamp(2.2rem,4vw,2.9rem) auto 0;text-align:center}
.summary-panel .eyebrow{margin-bottom:.9rem}
.summary-panel .lead-in{margin:0}

.callout{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(1.4rem,2.4vw,1.9rem);box-shadow:var(--shadow-sm)}

/* numbered "principles" — deliberately not card-like, to read differently from testimonial cards */
.principles{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(1.4rem,3vw,2.2rem) clamp(2rem,4vw,3.4rem)}
.principle{display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:start}
.principle__n{font-family:var(--serif);font-size:1.9rem;line-height:.9;color:var(--brass);font-weight:500;
  padding-top:.1rem;position:relative}
.principle__n::after{content:"";display:block;width:1.4rem;height:2px;background:var(--brass-line);margin-top:.45rem;border-radius:2px}
.principle__t{font-size:1.16rem;letter-spacing:-.005em;margin:0 0 .4rem;color:var(--ink)}
.principle p{margin:0;color:var(--slate);line-height:1.55}
@media (max-width:640px){.principles{grid-template-columns:1fr}}
.callout--brass{border-left:3px solid var(--brass);background:linear-gradient(180deg,#fff,var(--paper))}

/* numbered syllabus unit cards (course "what we might work on" grids) */
.unit{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(1.3rem,2.4vw,1.75rem);box-shadow:var(--shadow-sm)}
/* BC-only units: a warm golden tint so they read as an addition to the eight AB units */
.unit--bc{background:linear-gradient(180deg,#FBF3DF,#F5E9CE);border-color:var(--brass-line)}
.unit__n{display:block;font-family:var(--sans);font-size:.66rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--brass-deep);margin-bottom:.5rem}
.unit__t{font-family:var(--serif);font-size:1.12rem;color:var(--ink);letter-spacing:-.006em;line-height:1.22;margin:0 0 .5rem}
.unit p{margin:0;color:var(--slate);line-height:1.5;font-size:.97rem}

/* an inline "note / aside" — deliberately NOT a card, so it reads differently from the grids above it */
.aside-note{background:var(--brass-soft);border:1px solid var(--brass-line);border-left:4px solid var(--brass);border-radius:var(--radius);
  padding:clamp(1.35rem,2.6vw,1.9rem)}
.aside-note .eyebrow{margin-bottom:.7rem}
.aside-note p{margin:0}
.aside-note p + p{margin-top:.9rem}

/* inline cross-reference "see also" — a hairline-ruled note, deliberately not a card */
.crosslink{font-size:1.02rem;line-height:1.62;color:var(--slate);border-top:1px solid var(--line);padding-top:1.4rem;margin:0}
.crosslink__label{font-family:var(--serif);font-style:italic;font-weight:500;color:var(--ink-2)}

/* "setting the record straight" — advice list with headers (How I Teach) */
.setlist{display:grid;gap:1.7rem;margin-top:1.7rem}
.setlist__item{display:grid;gap:.4rem}
.setlist__item h3{font-family:var(--serif);font-size:1.2rem;color:var(--ink);margin:0;letter-spacing:-.008em;
  padding-left:1rem;border-left:3px solid var(--brass);line-height:1.25}
.setlist__item p{margin:0;padding-left:1rem}
.dark .setlist__item h3{color:#fff}

/* ---------- 404 (page not found) ---------- */
.notfound{padding-block:clamp(3rem,7vw,6rem)}
.notfound__grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(1.5rem,4vw,3.75rem);align-items:center}
.notfound h1{font-size:clamp(2.1rem,4.4vw,3.35rem);letter-spacing:-.02em}
.notfound .lede{margin-top:1.15rem;max-width:50ch}
/* the hero's curve carries a heavy drop-shadow tuned for the dark band — wrong on a light page */
.notfound__art .curve-fig{filter:none}
.notfound__art figcaption{margin-top:1rem;text-align:center;font-family:var(--mono);font-size:.78rem;
  letter-spacing:.01em;color:var(--slate);max-width:34ch;margin-inline:auto;line-height:1.5}
.notfound__links{margin-top:2.1rem;border-top:1px solid var(--line);padding-top:1.5rem}
.notfound__links h2{margin-bottom:.9rem}
.notfound__courses{list-style:none;margin:0 0 1.25rem;padding:0;display:grid;gap:.5rem}
/* the secondary row reuses .terms-line, which is built for plain text — give its links a hairline */
.notfound .terms-line{margin:0}
.notfound .terms-line a{color:var(--ink-2);text-decoration:none;border-bottom:1px solid var(--line);
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.notfound .terms-line a:hover{color:var(--brass-deep);border-color:var(--brass)}
.notfound__note{margin-top:1.6rem;font-size:.94rem;color:var(--slate)}
@media (max-width:840px){
  /* the hero puts its art first on mobile; an error page leads with the message instead */
  .notfound__grid{grid-template-columns:1fr;gap:2.5rem}
  .notfound__art{max-width:400px;margin-inline:auto}
}

/* the missing point: an open circle (removable discontinuity) instead of a filled one */
.curve--light .pt--open{fill:var(--porcelain);stroke:var(--brass);stroke-width:2.4}
.curve .drop{stroke:var(--line);stroke-width:1.2;stroke-dasharray:4 5;opacity:0}
.curve.run .drop{animation:fade-in .6s ease 1.45s forwards}
/* this figure renders smaller than the hero's, so the punchline label needs the size back */
.notfound__art .curve .lbl--d{font-size:15px}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important}
  .curve .fx,.curve .tangent{stroke-dashoffset:0}
  .curve .area,.curve .pt,.curve .lbl,.curve .lbl-int,.curve .drop{opacity:1}
  .reveal{opacity:1;transform:none}
}
