@import url("../fonts/fonts.css");

/* ==========================================================================
   Eddie's School of Driving — "Sheet 12"

   THESIS
     The site is a street-atlas sheet. Eddie's only defensible claim is
     locality — one instructor, eight towns, door-to-door pick-up, the actual
     local test routes — so the atlas IS the layout system rather than a
     decoration on top of one. It refuses the category default: a blue-gradient
     hero with a smiling instructor, a tick list and three star-rating cards.

   OWN-WORLD
     Atlas navy (#0a1b3c) and cool printing paper (#e8e9e2) alternate as full
     bands, ruled behind by a magenta grid. Two map inks point: A-road amber
     and signal red. Zero border radius anywhere; depth is a 2px offset shadow
     read as printing mis-registration. Archivo for display, Archivo Narrow for
     map labels, Martian Mono for grid references.

   STORY
     A nervous person comparing three instructors on a phone learns in one
     viewport that this is one named man who covers their postcode, sees an
     honest price, and reaches an enquiry form or a phone number without
     scrolling far.

   FIRST VIEWPORT
     A drawn road fills the whole band — sky, hills, treeline, carriageway —
     with the atlas grid ruled back over the top of it. Wordmark left. Headline
     with the promise in amber, lede, three actions on one line, three verified
     figures on a ruled strip. The branded car stands on the tarmac to the
     right, at the scale a car actually is beside a road.

   FORM
     Street atlas — candidate 6 of the grounded list, seed defb8a73.
     See DESIGN.md for the system this file implements, PRODUCT.md for what may
     and may not be claimed.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Ink */
  --ink:        #0a1b3c;
  --ink-2:      #122a55;
  --ink-3:      #1d3d74;
  --ink-soft:   rgba(10, 27, 60, .62);
  --ink-mute:   rgba(10, 27, 60, .48);  /* placeholders and disabled only */
  --ink-faint:  rgba(10, 27, 60, .34);  /* hairlines and dots — never text */

  /* Paper */
  --paper:      #e8e9e2;
  --paper-2:    #f4f5f0;
  --paper-soft: rgba(232, 233, 226, .70);
  --paper-faint:rgba(232, 233, 226, .40);

  /* Map inks */
  --red:        #d5001c;
  --red-dark:   #a70016;
  --amber:      #f2a100;
  --green:      #4e8e4a;
  --water:      #7fb2c9;
  --grid:       rgba(229, 0, 125, .14);
  --grid-navy:  rgba(127, 178, 201, .13);

  /* Geometry */
  --u:    8px;
  --sq:   88px;
  --wide: 1280px;
  --read: 62ch;
  --rule: 2px;

  /* Measured heights of the two fixed bands either side of the hero. The hero
     subtracts both so that the header, the hero and the specialisms marquee
     together fill exactly one screen — the marquee is the first thing that
     tells a visitor what the school is for, and it should not need a scroll. */
  --header-h: 71px;
  --ticker-h: 51px;

  /* Type */
  --f-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --f-narrow:  "Archivo Narrow", "Archivo", Arial, sans-serif;
  --f-mono:    "Martian Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  --t-hero:  clamp(38px, 5vw, 76px);    /* one hero rung for every page. Bounded by "CONFIDENCE" fitting the home column, which the photograph narrows — re-check if either changes */
  --t-h1:    clamp(34px, 5.4vw, 70px);
  --t-h2:    clamp(30px, 4.2vw, 52px);
  --t-h2s:   clamp(26px, 3.4vw, 40px);  /* second-rank h2 — a block inside a section */
  --t-h3:    clamp(21px, 2.4vw, 27px);
  --t-h3s:   clamp(19px, 2vw, 22px);    /* h3 inside a card or a table */
  --t-lede:  clamp(17px, 1.6vw, 21px);  /* the descriptive line under a heading */
  --t-body:  17px;
  --t-sm:    15px;                      /* dense copy: cards, tables, notes */
  --t-small: 14px;
  --t-ref:   12px;

  /* Buttons: three sizes, no fourth. Anything denser uses .btn--sm; anything
     that leads a page uses .btn--lg. Nothing invents its own padding. */
  --btn-pad:    15px 26px;
  --btn-pad-sm: 10px 16px;
  --btn-pad-lg: 19px 34px;

  /* Motion */
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-out:    cubic-bezier(.22, .61, .36, 1);
  --d-state:   120ms;
  --d-element: 320ms;
  --d-section: 640ms;
}

@media (max-width: 720px) {
  :root { --sq: 56px; --t-body: 16px; }
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
  /* Lets block-size transition to/from `auto`, which is what animates the FAQ
     disclosure. Browsers without it simply open the details instantly. */
  interpolate-size: allow-keywords;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--ink);
  font-family: var(--f-display);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.65;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, h3, h4 {
  font-weight: 800;
  line-height: .96;
  letter-spacing: -.03em;
  text-transform: uppercase;
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); letter-spacing: -.02em; }

p  { margin: 0 0 1em; max-width: var(--read); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }

ul, ol { margin: 0; padding: 0; list-style: none; }

button, input, textarea, select { font: inherit; color: inherit; }

:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
}

::selection { background: var(--amber); color: var(--ink); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: absolute; left: var(--u); top: -100px; z-index: 999;
  background: var(--amber); color: var(--ink);
  padding: 12px 20px; font-family: var(--f-narrow); font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; text-decoration: none;
  transition: top var(--d-state) var(--ease-out);
}
.skip-link:focus { top: var(--u); }

/* --------------------------------------------------------------------------
   3. Bands — the alternating navy / paper sheets
   -------------------------------------------------------------------------- */
.band { position: relative; }

.band--paper {
  background-color: var(--paper);
  color: var(--ink);
  background-image:
    repeating-linear-gradient(to right,  var(--grid) 0 1px, transparent 1px var(--sq)),
    repeating-linear-gradient(to bottom, var(--grid) 0 1px, transparent 1px var(--sq));
}

.band--ink {
  background-color: var(--ink);
  color: var(--paper);
  background-image:
    repeating-linear-gradient(to right,  var(--grid-navy) 0 1px, transparent 1px var(--sq)),
    repeating-linear-gradient(to bottom, var(--grid-navy) 0 1px, transparent 1px var(--sq));
}

.band--ink h1, .band--ink h2, .band--ink h3 { color: var(--paper-2); }
.band--ink p  { color: var(--paper-soft); }
.band--ink a  { color: var(--paper-2); }

/* The amber rule that marks every band boundary */
.band + .band::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: var(--rule);
  background: var(--amber);
  transform-origin: left center;
}

.wrap {
  width: 100%;
  max-width: var(--wide);
  margin: 0 auto;
  padding-inline: clamp(20px, 5vw, 56px);
}

.section     { padding-block: clamp(64px, 9vw, 128px); }
.section--sm { padding-block: clamp(44px, 6vw, 80px); }

/* --------------------------------------------------------------------------
   4. Sheet header — the eyebrow every section carries
   -------------------------------------------------------------------------- */
.eyebrow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px;
  font-family: var(--f-narrow); font-weight: 700;
  font-size: var(--t-ref); letter-spacing: .2em; text-transform: uppercase;
  color: var(--red);
  margin: 0 0 18px;
  max-width: none;
}
.band--ink .eyebrow { color: var(--amber); }

.eyebrow::before {
  content: ""; width: 28px; height: var(--rule);
  background: currentColor; flex: none;
}

.section-head {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: clamp(16px, 3vw, 40px);
  margin-bottom: clamp(32px, 5vw, 56px);
}
.section-head > :first-child { flex: 1 1 min(520px, 100%); }
/* The lead under a section heading. The eyebrow is excluded: an eyebrow is one
   size everywhere on the site, and letting this rule catch it produced a 14px
   eyebrow here and a 12px eyebrow everywhere else. */
.section-head p:not(.eyebrow) { font-size: var(--t-small); color: var(--ink-soft); max-width: 38ch; }
.band--ink .section-head p { color: var(--paper-soft); }

/* --------------------------------------------------------------------------
   5. Grid reference chips + index rows
   -------------------------------------------------------------------------- */
.ref {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--f-mono); font-size: 10px; font-weight: 500;
  letter-spacing: .04em; text-transform: uppercase;
  padding: 4px 8px 3px;
  border: 1px solid currentColor;
  color: var(--ink-soft);
  white-space: nowrap;
}
.band--ink .ref { color: rgba(232, 233, 226, .68); }
.ref--amber { color: var(--amber); border-color: var(--amber); }
.ref--red   { color: var(--red);   border-color: var(--red); }

.index { border-top: var(--rule) solid currentColor; }
.index__row {
  display: flex; align-items: baseline; gap: 12px;
  padding: 15px 0;
  border-bottom: 1px solid var(--ink-faint);
}
.band--ink .index__row { border-bottom-color: rgba(232, 233, 226, .18); }
.index__name { font-family: var(--f-narrow); font-weight: 700; font-size: 19px;
               text-transform: uppercase; letter-spacing: .01em; flex: none; }
.index__dots { flex: 1 1 auto; border-bottom: 2px dotted var(--ink-faint); transform: translateY(-4px); }
.band--ink .index__dots { border-bottom-color: rgba(232, 233, 226, .28); }
.index__ref  { font-family: var(--f-mono); font-size: 11px; letter-spacing: .04em;
               color: var(--ink-soft); flex: none; }

/* Some rows carry a block of copy rather than a single name. Without this the
   block is the only flexible item competing with `flex: none` siblings, gets
   squeezed to a hundred pixels, and its heading spills out of it. */
.index__row > div { flex: 1 1 auto; min-width: 0; }

/* A row split into a label column and a reading column. This was 27 copies of
   the same inline grid, which is why it never collapsed on a phone — an inline
   style cannot carry a media query, so the label column stayed at 42% of a
   390px screen and every heading in it overflowed. */
.index__row--split {
  display: grid;
  grid-template-columns: minmax(0, .42fr) minmax(0, 1fr);
  gap: clamp(14px, 2.2vw, 34px);
  align-items: start;
  padding: clamp(22px, 2.8vw, 38px) 0;
}
@media (max-width: 780px) {
  .index__row--split { grid-template-columns: 1fr; gap: 12px; }
}

/* On a phone the leader dots have nowhere to go, so the row stacks: name, then
   reference underneath. Keeping it on one line is what pushed the postcode
   reference past the right edge of the screen. */
@media (max-width: 700px) {
  .index__row { flex-wrap: wrap; row-gap: 4px; }
  .index__dots { display: none; }
  .index__name { flex: 1 1 auto; min-width: 0; }
  .index__ref { flex: 0 0 100%; }
}

/* A gazetteer row that leads somewhere. The whole row is the target, so it is
   as easy to hit on a phone as it looks. */
.index__row.is-link { position: relative; transition: background-color var(--d-state) var(--ease-out); }
.index__row.is-link:hover { background: rgba(242, 161, 0, .16); }
a.index__name { text-decoration: none; color: inherit; }
a.index__name::after { content: ""; position: absolute; inset: 0; }
.index__row.is-link:focus-within { outline: 3px solid var(--amber); outline-offset: 2px; }
.index__go { width: 17px; height: 17px; flex: none; opacity: .45; align-self: center;
             fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;
             transition: transform var(--d-state) var(--ease-out), opacity var(--d-state) var(--ease-out); }
.index__row.is-link:hover .index__go { transform: translateX(4px); opacity: 1; }
.band--ink .index__ref { color: var(--amber); }

/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-shadow: var(--ink);
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 26px;
  font-family: var(--f-narrow); font-weight: 700; font-size: var(--t-sm);
  letter-spacing: .12em; text-transform: uppercase; text-decoration: none;
  border: var(--rule) solid var(--ink);
  background: transparent; color: var(--ink);
  cursor: pointer; border-radius: 0;
  box-shadow: 4px 4px 0 0 var(--btn-shadow);
  transition: transform var(--d-state) var(--ease-out),
              box-shadow var(--d-state) var(--ease-out),
              background-color var(--d-state) var(--ease-out),
              color var(--d-state) var(--ease-out);
}
.btn:hover  { transform: translate(2px, 2px); box-shadow: 2px 2px 0 0 var(--btn-shadow); }
.btn:active { transform: translate(4px, 4px); box-shadow: 0 0 0 0 var(--btn-shadow); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

.btn--primary { background: var(--red); border-color: var(--red); color: #fff; --btn-shadow: var(--ink); }
.btn--primary:hover { background: var(--red-dark); border-color: var(--red-dark); }

.btn--amber { background: var(--amber); border-color: var(--amber); color: var(--ink); }

.btn--ghost { background: transparent; }

.band--ink .btn {
  border-color: var(--paper); color: var(--paper); --btn-shadow: var(--ink-3);
}
.band--ink .btn--primary { background: var(--red); border-color: var(--red); color: #fff; --btn-shadow: var(--paper); }
.band--ink .btn--amber   { background: var(--amber); border-color: var(--amber); color: var(--ink); --btn-shadow: var(--paper); }

.btn--sm { padding: 10px 16px; font-size: 13px; letter-spacing: .1em; box-shadow: 3px 3px 0 0 var(--btn-shadow); }
.btn--lg { padding: 19px 34px; font-size: 17px; }

.btn__ico { width: 17px; height: 17px; flex: none; }

/* --------------------------------------------------------------------------
   8. Wordmark
   -------------------------------------------------------------------------- */
/* The mark: four bars, the top two equal, the third and fourth progressively
   shorter, all flush RIGHT so their right edges form one straight vertical line
   and the stack steps in towards the E.

   Their right edges form one straight line in the lockup's own (skewed) frame,
   which is what makes the stack read as part of the italic rather than pinned
   beside it.

   Vertically the stack is set against the E, not centred on the whole lockup:
   16.5px tall against an ~18.2px cap height, offset 3px from the top of the
   wordmark's line box. That puts the bottom bar on the E's baseline and the top
   bar just inside the top of the E. (Flex `baseline` alignment looks like the
   tidy way to do this, but a flex column's baseline is not its bottom edge, so
   it lands the stack too low.)

   `gap` is the only value setting the distance from the bars to the E. */
/* The whole lockup leans right together — bars and both lines of type share one
   skew on this element, so they stay in register no matter what changes inside.
   Skewing them separately drifts them apart at different heights. */
.mark {
  display: inline-flex; align-items: flex-start; gap: 7px;
  text-decoration: none; color: inherit;
  transform: skewX(-8deg); transform-origin: left bottom;
}

.mark__bars {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 1.5px; flex: none; margin-top: 3px;
}
.mark__bars i { display: block; height: 3px; background: var(--red); transform-origin: right center; }
.mark__bars i:nth-child(1) { width: 19px; }
.mark__bars i:nth-child(2) { width: 19px; }
.mark__bars i:nth-child(3) { width: 12px; }
.mark__bars i:nth-child(4) { width: 7px;  }

/* The two lines are width-matched by tracking the WORDMARK, not by stretching
   the sub-line — SCHOOL OF DRIVING keeps its designed .19em spacing and
   EDDIE'S is tracked to meet it. Each line carries a negative margin equal to
   its own letter-spacing, which removes the trailing gap CSS adds after the
   last character, so the two right edges land on the same pixel rather than
   one em-fraction apart. */
.mark__type { display: inline-flex; flex-direction: column; align-items: flex-start; line-height: 1; }
.mark__type b {
  display: block;
  font-weight: 900; font-size: 25px; text-transform: uppercase;
  letter-spacing: .049em; margin-right: -.049em;
}
.mark__type span {
  display: block;
  font-family: var(--f-narrow); font-weight: 600; font-size: 10px;
  text-transform: uppercase; margin-top: 5px; color: var(--red);
  letter-spacing: .19em; margin-right: -.19em;
}
.siteheader .mark__type span, .band--ink .mark__type span { color: var(--amber); }

/* --------------------------------------------------------------------------
   9. Header + navigation
   -------------------------------------------------------------------------- */
.siteheader {
  position: sticky; top: 0; z-index: 60;
  background: var(--ink);
  color: var(--paper);
  border-bottom: var(--rule) solid var(--ink-3);
  transition: border-color var(--d-element) var(--ease-out);
}
.siteheader[data-scrolled="true"] { border-bottom-color: var(--amber); }

.siteheader__in {
  display: flex; align-items: center; gap: clamp(12px, 2vw, 32px);
  padding-block: 12px;
}

.nav { display: flex; align-items: center; gap: clamp(10px, 1.6vw, 26px); margin-left: auto; }
.nav a {
  font-family: var(--f-narrow); font-weight: 600; font-size: 14px;
  letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
  padding: 6px 0; position: relative; white-space: nowrap;
  color: var(--paper-soft);
  transition: color var(--d-state) var(--ease-out);
}
.nav a:hover { color: var(--paper-2); }
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--rule); background: var(--amber);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--d-element) var(--ease-out);
}
.nav a:hover::after, .nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: var(--paper-2); }

/* ---------------------------------------------------------- nav dropdown --
   A real disclosure, not a hover-only menu: it opens on click and on hover,
   closes on Escape and on outside click, and every item stays reachable by
   keyboard. Hover-only menus are unusable on a touchscreen and invisible to a
   keyboard, and this nav has to work on a phone first. */
.nav__group { position: relative; }
.nav__toggle {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; padding: 6px 0; cursor: pointer;
  font-family: var(--f-narrow); font-weight: 600; font-size: 14px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--paper-soft);
  position: relative;
}
.nav__toggle:hover, .nav__group[data-open="true"] .nav__toggle { color: var(--paper-2); }
.nav__toggle::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--rule); background: var(--amber);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--d-element) var(--ease-out);
}
.nav__group[data-open="true"] .nav__toggle::after,
.nav__group:hover .nav__toggle::after { transform: scaleX(1); }
.nav__chev {
  width: 11px; height: 11px; flex: none;
  transition: transform var(--d-state) var(--ease-out);
}
.nav__group[data-open="true"] .nav__chev { transform: rotate(180deg); }

/* The menu slides out from under the toggle like a sheet from a drawer:
   ease-out in, faster out. Visibility keeps closed items out of the tab order,
   as display:none used to. */
.nav__menu {
  position: absolute; top: 100%; left: -14px; z-index: 70;
  min-width: 232px; padding: 6px 0;
  background: var(--ink); border: var(--rule) solid var(--amber);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(8px);
  transform-origin: top left;
  transition: opacity 120ms var(--ease-out),
              transform 120ms var(--ease-out),
              visibility 0s linear 120ms;
}
.nav__group[data-open="true"] .nav__menu {
  opacity: 1; visibility: visible; pointer-events: auto; transform: none;
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.nav__menu a {
  display: block; padding: 11px 18px; font-size: 14px;
  letter-spacing: .06em; color: var(--paper-soft); white-space: nowrap;
}
.nav__menu a::after { display: none; }
.nav__menu a:hover, .nav__menu a:focus-visible {
  background: var(--ink-2); color: var(--paper-2);
}
.nav__menu a[aria-current="page"] { color: var(--amber); }

/* Pointer users get hover; the click/keyboard path still works underneath. */
@media (hover: hover) and (min-width: 1081px) {
  .nav__group:hover .nav__menu {
    opacity: 1; visibility: visible; pointer-events: auto; transform: none;
    transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
  }
}

.tel {
  display: inline-flex; align-items: center; gap: 9px;
  text-decoration: none; white-space: nowrap;
  font-family: var(--f-narrow); font-weight: 700; font-size: 16px; letter-spacing: .04em;
  color: var(--paper-2);
}
.tel:hover { color: var(--amber); }

.flag {
  display: inline-block; width: 22px; height: 14px; flex: none;
  border: 1px solid rgba(255, 255, 255, .35);
}
.band--paper .flag, .sheet .flag { border-color: var(--ink-faint); }

.navtoggle { display: none; }

@media (max-width: 1080px) {
  .siteheader .nav, .siteheader .tel, .siteheader .btn { display: none; }
  .navtoggle {
    display: inline-flex; align-items: center; gap: 10px; margin-left: auto;
    background: none; border: var(--rule) solid var(--paper); color: var(--paper);
    padding: 10px 15px; cursor: pointer;
    font-family: var(--f-narrow); font-weight: 700; font-size: 13px;
    letter-spacing: .14em; text-transform: uppercase;
  }
  .navtoggle svg { width: 16px; height: 16px; }
}

/* Mobile drawer */
.drawer {
  position: fixed; inset: 0; z-index: 80;
  background: var(--ink);
  /* Without this the drawer inherits the body's ink colour and the wordmark
     is navy on navy — the E of EDDIE'S simply disappears. */
  color: var(--paper);
  display: flex; flex-direction: column;
  padding: 20px clamp(20px, 5vw, 40px) 40px;
  transform: translateY(-100%);
  visibility: hidden;
  /* Closing is quicker than opening: the visitor asked for it to go away. */
  transition: transform 340ms var(--ease-in-out), visibility 0s linear 340ms;
  overflow-y: auto;
}
.drawer[data-open="true"] {
  transform: none; visibility: visible;
  transition: transform 520ms cubic-bezier(.32, .72, 0, 1), visibility 0s;
}

/* The menu items follow the sheet in, one after another — the same stagger the
   hero uses. The delays only exist on the open state, so closing is instant. */
[data-anim-ready] .drawer nav a {
  opacity: 0; transform: translateY(12px);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-out);
}
[data-anim-ready] .drawer[data-open="true"] nav a { opacity: 1; transform: none; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(1) { transition-delay: 120ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(2) { transition-delay: 155ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(3) { transition-delay: 190ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(4) { transition-delay: 225ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(5) { transition-delay: 260ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(6) { transition-delay: 295ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(7) { transition-delay: 330ms; }
[data-anim-ready] .drawer[data-open="true"] nav a:nth-child(8) { transition-delay: 365ms; }
[data-anim-ready] .drawer__foot {
  opacity: 0; transform: translateY(12px);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-out);
}
[data-anim-ready] .drawer[data-open="true"] .drawer__foot {
  opacity: 1; transform: none; transition-delay: 400ms;
}
.drawer__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: clamp(22px, 4vw, 36px); }
.drawer nav { display: flex; flex-direction: column; }
/* Eight items have to fit one phone screen without scrolling. At the size this
   was set to, two of them wrapped and the last two fell below the fold. */
.drawer nav a {
  font-family: var(--f-display); font-weight: 800; font-size: clamp(19px, 4.8vw, 26px);
  letter-spacing: -.015em; text-transform: uppercase; text-decoration: none;
  color: var(--paper-2); padding: 13px 0;
  border-bottom: 1px solid var(--ink-3);
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
}
.drawer nav a span { font-family: var(--f-mono); font-size: 11px; color: var(--amber); letter-spacing: .04em; }
.drawer__foot { margin-top: auto; padding-top: 32px; display: grid; gap: 12px; }

/* --------------------------------------------------------------------------
   10. Hero

   The photograph is not a picture beneath the hero — it IS the hero. The
   branded car on a wet Manchester road fills the whole band and the atlas grid
   is ruled back over the top, so the photograph sits inside the design system
   rather than interrupting it.

   The photograph arrives already graded: dark on the left where the copy sits,
   open on the right where the car is. A replacement has to be graded the same
   way, and has to park the car in the right-hand 40% — the copy column and the
   scrim stops below are both cut to this master's geometry. See design/source/
   for the master and README for the contrast check that has to pass.
   -------------------------------------------------------------------------- */
.hero {
  /* Header + hero + marquee = one screen. svh rather than vh so a phone's
     collapsing address bar does not leave a gap. The second term is the
     photograph's own 2:1: past it the band starts cropping horizontally and
     the first thing lost is the lettering on the car door, so filling the
     screen gives way to keeping the livery.

     This is a MINIMUM, not a height. On a short screen it binds and the band
     lands at 2:1 or wider, so the crop is vertical and only object-position's
     second number matters. On a tall one — a portrait tablet especially — the
     copy is taller than the minimum, the band goes past 2:1 in height, and the
     crop turns horizontal: the car then moves inward from its 56% and the
     first number is what holds it clear of the text. Measured at 1024x1366,
     the tightest case on the range, the copy clears the car by 28px. */
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: center;
  min-height: min(
    calc(100svh - var(--header-h) - var(--ticker-h)),
    calc(100vw / 2)
  );
  padding-block: clamp(40px, 4.5vw, 72px);
}

/* The photograph, edge to edge. object-position is what holds the car and the
   road in frame as the band changes shape — it is the one number to touch if a
   replacement photograph crops badly. */
.hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
/* Biased left so the crop pushes the car towards the right edge, away from
   the copy. The car is white; no amount of scrim makes white type readable on
   it, so the copy has to stay off it. */
.hero__photo { width: 100%; height: 100%; object-fit: cover; object-position: 62% 62%; }

/* Where the band sits at 2:1 or wider — every short screen, which is most
   desktops — the crop is vertical, so a percentage across this gradient is the
   same percentage across the photograph and these stops are exact:

     51%  where the copy column ends (the wrap puts it there at every width)
     56%  the car's front bumper — the tint is essentially gone by here
     60%  fully transparent, so the livery, the skyline and the wet road
          reflections are the photograph's own contrast and nothing else

   On a tall viewport the band goes past 2:1 in height and the crop turns
   horizontal, which slides the photograph inward under these stops. They stop
   being exact there and become approximate — which is fine, because the scrim
   only ever deepens what the master already has, and npm run contrast measures
   the real composite at thirteen sizes rather than trusting this arithmetic.

   The master already arrives graded dark on the left, so this only tops up the
   shortfall behind the words. It is deliberately lighter than the scrim the
   previous photograph needed. */
.hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgba(10, 27, 60, .70)  0%,
    rgba(10, 27, 60, .64) 40%,
    rgba(10, 27, 60, .47) 51%,
    rgba(10, 27, 60, .14) 56%,
    rgba(10, 27, 60, 0)   60%);
}

/* The hero sits on the same centred 1280 wrap as every other section, so the
   headline starts on the page's one left margin rather than on a margin of its
   own — the eyebrow, the H1 and the section headings further down all begin at
   the same x. That is only affordable because this photograph parks the car at
   56–88% of the frame and grades everything to its left; the copy column below
   is held short enough to stop well clear of it. */
.hero__in { position: relative; z-index: 2; }

/* The copy holds the left of the wrap; the car stands to the right of it.
   The measure has to be wide enough to carry the three actions on one line,
   which is what actually sets this number — not the headline. Capped as a
   share of the wrap so it cannot grow into the car on a wide screen. */
.hero__copy { max-width: min(52%, 600px); }
@media (max-width: 1000px) { .hero__copy { max-width: 100%; } }

/* The general two-column split used by content sections. */
.split {
  display: grid; gap: clamp(28px, 5vw, 64px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
}
.split--figure  { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); align-items: center; }
.split--reading { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); }

@media (max-width: 900px) {
  .split, .split--figure, .split--reading { grid-template-columns: 1fr; }
}

.hero h1 {
  /* The same rung as every other page's hero — the home headline is not a
     special case. --t-hero is bounded by CONFIDENCE fitting this column. */
  font-size: var(--t-hero); font-weight: 900; letter-spacing: -.045em; line-height: .86;
  margin: 0 0 22px;
}
.hero h1 em { font-style: normal; color: var(--amber); display: block; }

.hero__lede { font-size: var(--t-lede); max-width: 46ch; color: var(--paper-soft); }

/* One row, all three actions, across the full width of the hero rather than
   inside the text column — three uppercase labels will not fit a half-width
   column at any readable size. */
.hero__actions {
  display: flex; flex-wrap: wrap; gap: 12px;
  margin: clamp(26px, 3vw, 36px) 0 0;
}
.hero__actions .btn { flex: 0 1 auto; }

/* The hero carries three actions rather than one, so they are set at the
   standard .btn size rather than .btn--lg — three --lg labels will not hold a
   line at any width. This is the only place on the site a button departs from
   the three standard sizes. */
.hero__actions .btn--lg { padding: var(--btn-pad); font-size: var(--t-sm); }

/* On desktop they step down one further notch, because the copy column is now
   capped at a share of the 1280 wrap rather than growing with the viewport —
   so the row has the same 600px to fit into at 1280 and at 2560, and the three
   labels need this size to hold one line in it. Measured: 591px at this size
   against a 600px column. Buttons are standardised on height, padding and type
   — never on width, which is why BOOK YOUR FIRST LESSON is wider than
   WHATSAPP; they wrap when the row runs out. */
@media (min-width: 1001px) {
  .hero__actions { gap: 10px; }
  .hero__actions .btn--lg { padding: var(--btn-pad-sm); font-size: 13.5px; }
}
@media (max-width: 1000px) {
  .hero__actions .btn--lg { padding: var(--btn-pad); letter-spacing: .1em; }
  .hero__actions { gap: 12px; }
}
/* A laptop screen is short. Without giving some padding back, the hero fills
   the window on its own and pushes the marquee off the first screen. */
@media (min-width: 1001px) and (max-height: 920px) {
  .hero { padding-block: clamp(24px, 2.4vw, 40px); }
  .hero h1 { margin-bottom: 14px; }
  .hero__actions { margin-top: clamp(18px, 2vw, 26px); }
  .hero .stats { margin-top: clamp(16px, 1.8vw, 26px); padding-block: 9px; }
}

/* On a phone a full-width stack is the readable shape, and there the equal
   width is the point rather than an accident. */
@media (max-width: 700px) {
  .hero__actions { display: grid; grid-template-columns: 1fr; }
  .hero__actions .btn--lg { width: 100%; padding: var(--btn-pad); font-size: var(--t-sm); }
}

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
         border-top: var(--rule) solid var(--ink-3); max-width: 620px; }

/* In the hero the three figures read as one ruled line across the band, number
   and label side by side rather than stacked, so they sit over the road in the
   photograph instead of blocking it. */
.hero .stats {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px clamp(16px, 1.8vw, 32px);
  max-width: none;
  border-top: var(--rule) solid var(--ink-3);
  border-bottom: var(--rule) solid var(--ink-3);
  padding-block: 13px;
  margin-top: clamp(26px, 3vw, 40px);
}
.hero .stats > div { display: flex; align-items: baseline; gap: 10px;
                     padding: 0; border: 0; }
.hero .stats > div + div { padding-left: 0; border-left: 0; }
.hero .stats b { font-size: clamp(20px, 1.7vw, 25px); }
.hero .stats > div > span { margin-top: 0; }
.hero .stats > div { flex: 0 1 auto; }
/* The ruled line ends where the copy column ends, so the eyebrow, the
   headline, the buttons and this rule all share one right edge — and it stops
   inside the graded half of the photograph rather than running at the car. */
.hero .stats { max-width: min(52%, 600px); }
@media (max-width: 1000px) { .hero .stats { max-width: none; } }
@media (max-width: 700px) {
  .hero .stats { gap: 10px 26px; }
  .hero .stats > div > span { white-space: normal; }
}
.stats > div { padding: 15px 18px 15px 0; min-width: 0;
               border-bottom: var(--rule) solid var(--ink-3); }
.stats > div + div { padding-left: 18px; border-left: 1px solid var(--ink-3); }
.stats b { display: block; font-family: var(--f-display); font-weight: 900; font-size: clamp(26px, 3vw, 32px);
           line-height: 1; letter-spacing: -.03em; color: var(--amber); white-space: nowrap; }
.stats b span { font: inherit; color: inherit; letter-spacing: inherit; margin: 0; text-transform: none; }
.stats > div > span { display: block; font-family: var(--f-narrow); font-weight: 600; font-size: 10.5px;
                      letter-spacing: .1em; text-transform: uppercase; color: var(--paper-soft);
                      margin-top: 7px; text-wrap: balance; }

@media (max-width: 1000px) {
  /* A phone viewport is roughly 1:2 and the photograph is 2:1, so `cover`
     across the whole band throws away nine tenths of the frame and leaves a
     wheel arch. The photograph therefore stops covering and becomes a band at
     the foot of the hero at close to its own aspect — the whole car, the road
     and the skyline, edge to edge — with the copy on flat ink above it. */
  .hero {
    /* Two things are going on here.

       The SHAPE. The master is composed for the desktop layout: its left half
       is empty graded sky for the headline to sit on. Shown at 2:1 or wider —
       which a short strip is — a phone gets half a picture of nothing and a
       car the size of a thumbnail against the right edge. Under 2:1 the crop
       turns horizontal instead, throwing the empty half away and keeping the
       full height of the frame. At 78vw this runs about 1.3:1 on a phone,
       which shows roughly the right two thirds of the master: the car, whole
       and large, with the skyline behind it.

       The JOIN. The photograph must not read as a separate block pasted under
       the copy, which is what a hard top edge on a flat navy panel looks like.
       It is masked instead, so it dissolves upward into the band — the skyline
       fades out of the ink and the car is solid below.

       The mask is what removes the seam, so the copy does not also have to sit
       on the picture to look joined. It is held just clear of it: at .74 the
       figures landed 14% into the strip, where the mask is already a fifth
       open and a bright skyline sits behind 10.5px labels — measured 3.81:1 at
       430px, under AA. At .92 they stop above it and the blend is unchanged. */
    --photo-strip: clamp(300px, 78vw, 560px);
    min-height: 0; align-items: flex-start;
    padding-bottom: calc(var(--photo-strip) * .92 + clamp(24px, 4vw, 40px));
  }
  .hero__bg { background-color: var(--ink); }

  /* The desktop scrim runs left-to-right, across a layout where the copy is
     beside the car. Stacked, the copy is ABOVE it and that gradient only dims
     the left of the photograph for no reason. The mask below does the blending
     now, so this comes off entirely. */
  .hero__bg::after { background: none; }

  .hero__photo {
    position: absolute; inset: auto 0 0 0;
    width: 100%; height: var(--photo-strip);
    /* Held right, because that is where the car is. The vertical number stops
       mattering once the crop is horizontal — the full height is in frame. */
    object-fit: cover; object-position: 92% 50%;
    /* Fully solid by 44%, which is exactly where the car's roof begins in the
       master — so the sky dissolves and the car never does. */
    -webkit-mask-image: linear-gradient(to bottom,
      transparent 0, rgba(0,0,0,.28) 18%, rgba(0,0,0,.75) 33%, #000 44%);
    mask-image: linear-gradient(to bottom,
      transparent 0, rgba(0,0,0,.28) 18%, rgba(0,0,0,.75) 33%, #000 44%);
  }
}

/* ----------------------------------------------------------- join the team --
   Recruitment, addressed to instructors rather than pupils. It sits on the
   amber ground so it reads as a different audience at a glance and nobody
   halfway through choosing lessons mistakes it for another offer. */
.recruit { background: var(--amber); color: var(--ink); }
.recruit h2, .recruit h3 { color: var(--ink); }
.recruit p { color: rgba(10, 27, 60, .78); }
.recruit .eyebrow { color: var(--red); }
.recruit .btn { border-color: var(--ink); color: var(--ink); --btn-shadow: var(--ink); }
.recruit .btn:hover { background: rgba(10, 27, 60, .1); }
.recruit .btn--primary { background: var(--ink); border-color: var(--ink); color: var(--paper-2); --btn-shadow: rgba(10,27,60,.35); }
.recruit .btn--primary:hover { background: #061431; }
.recruit__grid { display: grid; gap: clamp(24px, 4vw, 56px);
                 grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 900px) { .recruit__grid { grid-template-columns: 1fr; } }
.recruit__list { border-top: var(--rule) solid var(--ink); }
.recruit__list li {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 0; border-bottom: 1px solid rgba(10, 27, 60, .28);
  font-size: var(--t-sm); line-height: 1.6;
}
.recruit__list b { font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
                   letter-spacing: .14em; text-transform: uppercase; color: var(--red);
                   flex: none; min-width: 26px; padding-top: 2px; }

/* ---------------------------------------------------------- the owner's voice --
   What is left of the instructor block after the founder section came off the
   home page: two pieces of typography, used on /about under "In Bejoy's
   words". The grid, the framed portrait and the badge that went with them are
   gone, because nothing set them any more. */
.owner__quote {
  font-size: clamp(21px, 2.8vw, 32px); line-height: 1.3; font-weight: 500;
  letter-spacing: -.015em; max-width: 22ch; margin: 0 0 20px;
}
.band--ink .owner__quote { color: var(--paper-2); }
.owner__by {
  font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--amber);
}

.hero__figure { position: relative; margin: 0; }
.hero__portrait {
  position: relative; z-index: 2;
  background: var(--paper);
  border: var(--rule) solid var(--paper);
  box-shadow: 10px 10px 0 0 var(--red);
  overflow: hidden;
  aspect-ratio: 4 / 5;
}
.hero__portrait img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 2%; }

.hero__tag {
  position: absolute; z-index: 3; left: 0; bottom: -18px;
  background: var(--ink); border: var(--rule) solid var(--amber);
  padding: 12px 16px; max-width: 240px;
}
@media (min-width: 901px) { .hero__tag { left: -16px; } }
.hero__tag b { display: block; font-family: var(--f-display); font-weight: 800;
               font-size: 21px; text-transform: uppercase; letter-spacing: -.02em; color: var(--paper-2); }
.hero__tag span { display: block; font-family: var(--f-mono); font-size: 10px;
                  letter-spacing: .06em; color: var(--amber); margin-top: 3px; }

/* --------------------------------------------------------------------------
   11. Ticker
   -------------------------------------------------------------------------- */
.ticker { overflow: hidden; background: var(--amber); color: var(--ink);
          border-block: var(--rule) solid var(--ink); padding-block: 11px; }
.ticker__track { display: flex; width: max-content; }
.ticker__set { display: flex; align-items: center; gap: 34px; padding-right: 34px; white-space: nowrap;
               font-family: var(--f-narrow); font-weight: 700; font-size: var(--t-sm);
               letter-spacing: .18em; text-transform: uppercase; }
.ticker__set i { display: block; width: 9px; height: 9px; background: var(--ink);
                 transform: rotate(45deg); flex: none; }

/* --------------------------------------------------------------------------
   12. Cards
   -------------------------------------------------------------------------- */
.cards { display: grid; gap: clamp(16px, 2vw, 24px);
         grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); }

.card {
  position: relative;
  background: var(--paper-2);
  border: var(--rule) solid var(--ink);
  padding: clamp(22px, 2.4vw, 30px);
  display: flex; flex-direction: column; gap: 11px;
  transition: transform var(--d-element) var(--ease-out), box-shadow var(--d-element) var(--ease-out);
}
.card__no { font-family: var(--f-mono); font-size: 11px; letter-spacing: .08em; color: var(--red); }
/* Cards sit three or four across, so their headings run at the smaller of the
   two h3 rungs. At the full size a single long place name — Wythenshawe — is
   wider than the card it sits in. */
.card h3 { margin: 0; font-size: var(--t-h3s); }
.card p  { margin: 0; font-size: var(--t-small); color: var(--ink-soft); }
.card__foot { margin-top: auto; padding-top: 14px; display: flex; align-items: center;
              justify-content: space-between; gap: 12px; border-top: 1px solid var(--ink-faint); }
.card__price { font-family: var(--f-mono); font-size: 13px; font-weight: 600; }

a.card, .card--link { text-decoration: none; }
/* The lift is a pointer affordance; on touch it only flashes mid-tap, so it is
   gated to devices that can actually hover. */
@media (hover: hover) and (pointer: fine) {
  a.card:hover, .card--link:hover { transform: translate(-3px, -3px); box-shadow: 6px 6px 0 0 var(--amber); }
}

.band--ink .card { background: var(--ink-2); border-color: var(--ink-3); }
.band--ink .card p { color: var(--paper-soft); }
.band--ink .card__foot { border-top-color: var(--ink-3); }

/* ------------------------------------------------- specialist lessons band --
   The one section on the page whose backdrop is a photograph. The signpost
   master is composed for exactly this job: empty near-white down its left
   third, the sign and the road held in the right two thirds, and the site's
   own dot grid and red/white/blue diagonals already in the corners.

   Three things make it sit in the sheet instead of on top of it:

     multiply     the master's white is #f1f0f0 and the band is #e8e9e2, so an
                  opaque image would show as a lighter rectangle. Multiplied,
                  white becomes the paper exactly, nothing needs to be matched
                  by hand, and the atlas grid still rules through the sky.
     the mask     the photograph has no bottom edge — it dissolves before it
                  reaches the cards, so no hard line ever crosses the section.
     the crop     anchored to the top right, which is where the sign is. The
                  copy runs on the empty side and never sits on the subject.
   -------------------------------------------------------------------------- */
.spec {
  position: relative; overflow: hidden;
  /* The section's own padding, named so the backdrop can climb back out
     through it to the band's top edge. Must track .section. */
  --spec-pad: clamp(64px, 9vw, 128px);
}
.spec > .wrap { position: relative; }

/* In the source the photograph sits between the lede and the cards, which is
   the phone layout: a band of its own with nothing over it. Full bleed to both
   edges, and short enough that it reads as a rule between the copy and the
   cards rather than as a picture demanding attention. */
.spec__bg {
  position: relative; z-index: 0;
  margin-inline: calc(50% - 50vw);
  margin-block: 0 clamp(26px, 4vw, 44px);
  height: clamp(150px, 30vw, 250px);
  pointer-events: none;
}

.spec__bg img {
  width: 100%; height: 100%; display: block;
  object-fit: cover; object-position: 86% 30%;
  /* The master's white is #f1f0f0 and the band is #e8e9e2, so an opaque image
     would show as a lighter rectangle. Multiplied, that white becomes the
     paper exactly — nothing has to be colour-matched by hand — and the atlas
     grid still rules through the sky. */
  mix-blend-mode: multiply;
  /* Masks intersected, so the picture has no edges of its own to cut across
     the sheet. The left fade also means a replacement master does not have to
     be graded to white to sit here. */
  -webkit-mask-image:
    linear-gradient(to bottom, #000 0 52%, transparent 99%),
    linear-gradient(to right, transparent 0, #000 16%, #000 88%, transparent 100%);
  mask-image:
    linear-gradient(to bottom, #000 0 52%, transparent 99%),
    linear-gradient(to right, transparent 0, #000 16%, #000 88%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* Wide enough for the reference layout: the photograph leaves the flow, climbs
   back through the section's top padding to the band's edge, and bleeds off
   the right of the screen — so the heading and the lede read across its empty
   graded third and the cards land over its lower edge.

   The copy has to be lifted over it explicitly. The backdrop is positioned and
   its siblings are not, so without this the heading would paint underneath. */
@media (min-width: 1001px) {
  .spec .section-head,
  .spec .lede,
  .spec .cards,
  .spec__cta { position: relative; z-index: 1; }

  .spec__bg {
    position: absolute; z-index: 0;
    top: calc(-1 * var(--spec-pad));
    right: calc(50% - 50vw);
    margin: 0;
    width: min(74vw, 1180px);
    /* Deep enough to carry the heading, the lede and the top of the first card
       row — where the reference puts the cards over the picture. */
    height: clamp(340px, 44vw, 620px);
  }

  .spec__bg img {
    /* The box is wider than the master's 1.599:1, so this crops vertically.
       Held high and right: the sign's arms are the subject and they sit in the
       master's top right. */
    object-position: 88% 26%;
    /* The left fade has to clear the copy column, not just the frame edge —
       this is the number that keeps the heading off the hillside. */
    -webkit-mask-image:
      linear-gradient(to bottom, #000 0 46%, rgba(0,0,0,.5) 74%, transparent 97%),
      linear-gradient(to right, transparent 0, #000 34%);
    mask-image:
      linear-gradient(to bottom, #000 0 46%, rgba(0,0,0,.5) 74%, transparent 97%),
      linear-gradient(to right, transparent 0, #000 34%);
  }
}

/* ---------------------------------------------------------- areas covered --
   The same idea as the specialist band, inverted for the navy sheet.

   There the master was near-white where the copy sits and was MULTIPLIED into
   the paper. Here the master is darker than the band everywhere it is empty —
   (4,24,54) against --ink's (10,27,60), lower in all three channels — so it is
   LIGHTENED into the navy instead. `lighten` takes the brighter of the two per
   channel, so the empty ground resolves to exactly --ink and disappears, and
   only the roads, the river and the junction labels come through. As with
   multiply on the paper, nothing has to be colour-matched by hand and a
   regrade cannot introduce a seam.

   It is the ground, not the subject: the schematic coverage map with the six
   pins still sits on top and is still what you read.
   -------------------------------------------------------------------------- */
.areas { position: relative; overflow: hidden; }

/* Anchored to the two columns rather than to the section. The heading's
   supporting paragraph sits top right, which is exactly where this master
   keeps its brightest pixels — the white-on-blue M60 and M56 junction chips —
   and behind that paragraph they took it to 1.03:1. Starting at the columns
   puts the map below the heading entirely, and the only copy near it is then
   the index list, which runs down the side the mask has already taken out.
   `.split` is full wrap width and shares the viewport's centre line, so
   `50% - 50vw` still reaches the edge of the screen from in here. */
.areas .split { position: relative; }
/* :not() is load-bearing — `.areas .split > *` outweighs `.areas__bg`, so
   without it the backdrop would be handed position:relative and fall back into
   the grid as a third column. */
.areas .split > *:not(.areas__bg) { position: relative; z-index: 1; }

.areas__bg {
  position: absolute; z-index: 0;
  top: calc(-1 * clamp(18px, 3vw, 40px));
  bottom: calc(-1 * clamp(18px, 3vw, 40px));
  right: calc(50% - 50vw);
  width: min(72vw, 1180px);
  pointer-events: none;
}

.areas__bg img {
  width: 100%; height: 100%; display: block;
  /* Anchored right, where the master's detail is; the index list runs down the
     empty side. */
  object-fit: cover; object-position: 100% 42%;
  mix-blend-mode: lighten;
  /* Held back from the copy column, and faded off the top and bottom so the
     map has no edges of its own against the band rules. */
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 38%),
    linear-gradient(to bottom, transparent 0, #000 14%, #000 82%, transparent 100%);
  mask-image:
    linear-gradient(to right, transparent 0, #000 38%),
    linear-gradient(to bottom, transparent 0, #000 14%, #000 82%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* The coverage figure already fills a phone screen with a map of the same
   ground, so a second one underneath is bytes for nothing. display:none on a
   lazy image also means it is never fetched at this size. */
@media (max-width: 1000px) {
  .areas__bg { display: none; }
}

/* ------------------------------------------------------- join our team top --
   The recruitment hero: the pitch on the left, the car on the right with an
   instructor and a learner in it. The page is addressed to instructors, so the
   picture has to show the job rather than the school.

   The photograph is cut out of a page mockup and 548px is every pixel of it
   there is, so this column is capped BELOW that rather than filling the half a
   50/50 split would give it. At 520 the image renders at 1.05x its own width
   and stays sharp; at 720 it would be visibly soft, and a soft photograph of
   two faces is worse than a smaller crisp one. If a real photograph is ever
   supplied, raise the cap and the crop in tools/images.js comes out.
   -------------------------------------------------------------------------- */
.jointop {
  display: grid; align-items: center;
  gap: clamp(28px, 4vw, 56px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 520px);
}

.jointop__photo { margin: 0; width: 100%; max-width: 520px; }
.jointop__photo img {
  width: 100%; height: auto; display: block;
  border: var(--rule) solid var(--ink-3);
}

/* One column below the point where the copy column stops being a measure. The
   photograph keeps its cap and centres rather than stretching, because the
   only thing stretching buys at this size is blur. */
@media (max-width: 900px) {
  .jointop { grid-template-columns: 1fr; }
  .jointop__photo { margin-inline: auto; }
}

/* --------------------------------------------------------------------------
   13. Route — the four stops to your licence
   -------------------------------------------------------------------------- */
/* The route band. A single cut-out image on a transparent ground, so the
   section's own navy and grid show through it and it reads as part of the
   sheet rather than a picture pasted onto it. */
.route { position: relative; margin-bottom: clamp(24px, 3vw, 36px); }
.route img { width: 100%; height: auto; display: block; }

/* Below the point where the four faces stop being legible, the band is doing
   less work than the space it takes, so it goes. The four numbered steps
   underneath carry the whole meaning on their own. */
@media (max-width: 700px) {
  .route { display: none; }
}

.steps { display: grid; gap: clamp(20px, 3vw, 34px);
         grid-template-columns: repeat(auto-fit, minmax(212px, 1fr)); }
.steps__no { display: block; font-family: var(--f-display); font-weight: 900; font-size: 46px;
             line-height: 1; letter-spacing: -.04em; color: var(--amber); }
.steps h4 { font-size: 19px; text-transform: uppercase; letter-spacing: -.01em; margin: 8px 0 8px; }
.steps p  { font-size: var(--t-small); color: var(--paper-soft); margin: 0; }
.band--paper .steps p { color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   14. Price table
   -------------------------------------------------------------------------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.prices { width: 100%; border-collapse: collapse; min-width: 560px; }
table.prices caption { text-align: left; font-family: var(--f-mono); font-size: 11px;
                       letter-spacing: .06em; color: var(--ink-soft); padding-bottom: 12px; }
table.prices th {
  text-align: left; font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft);
  padding: 0 14px 10px 0; border-bottom: var(--rule) solid var(--ink);
}
table.prices td { padding: 15px 14px 15px 0; border-bottom: 1px solid var(--ink-faint); font-size: var(--t-sm); }
table.prices tbody tr:hover { background: rgba(242, 161, 0, .14); }
table.prices .num { text-align: right; font-family: var(--f-mono); font-weight: 600; font-size: var(--t-sm);
                    white-space: nowrap; padding-right: 0; }

.blocks { display: grid; gap: clamp(16px, 2vw, 22px);
          grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }
.block { border: var(--rule) solid var(--ink); padding: clamp(20px, 2.4vw, 28px); background: var(--paper-2); }
.block--hero { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.block__tag { display: inline-block; font-family: var(--f-narrow); font-weight: 700; font-size: 11px;
              letter-spacing: .16em; text-transform: uppercase; padding: 4px 9px;
              border: 1px solid currentColor; color: var(--red); margin-bottom: 14px; }
.block--hero .block__tag { color: var(--amber); }
.block h3 { font-size: 22px; margin-bottom: 2px; }
.block__price { display: block; font-family: var(--f-display); font-weight: 900; font-size: 50px;
                line-height: 1.06; letter-spacing: -.04em; margin-top: 12px; }
.block--hero .block__price { color: var(--amber); }
.block__note { font-family: var(--f-mono); font-size: 11px; letter-spacing: .03em;
               color: var(--ink-soft); display: block; margin-top: 6px; }
.block--hero .block__note { color: var(--paper-soft); }

/* --------------------------------------------------------------------------
   15. FAQ
   -------------------------------------------------------------------------- */
.faq { border-top: var(--rule) solid var(--ink); }
.faq details { border-bottom: 1px solid var(--ink-faint); }
.faq summary {
  list-style: none; cursor: pointer; padding: 20px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  font-family: var(--f-display); font-weight: 800; font-size: clamp(17px, 2vw, 21px);
  text-transform: uppercase; letter-spacing: -.02em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 15px; height: 15px;
  background: var(--red);
  clip-path: polygon(43% 0, 57% 0, 57% 43%, 100% 43%, 100% 57%, 57% 57%, 57% 100%, 43% 100%, 43% 57%, 0 57%, 0 43%, 43% 43%);
  transition: transform var(--d-element) var(--ease-out);
}
.faq details[open] summary::after { transform: rotate(135deg); }
.faq details p { padding: 0 0 22px; font-size: var(--t-sm); color: var(--ink-soft); }

/* The answer folds out rather than snapping. Needs `interpolate-size` (set on
   html) so block-size can animate to auto; elsewhere it opens instantly, which
   is the correct fallback. Closing is faster than opening, like the drawer. */
.faq details::details-content {
  opacity: 0; block-size: 0; overflow-y: clip;
  transition: content-visibility 200ms allow-discrete,
              opacity 200ms var(--ease-out),
              block-size 200ms var(--ease-out);
}
.faq details[open]::details-content {
  opacity: 1; block-size: auto;
  transition: content-visibility 300ms allow-discrete,
              opacity 300ms var(--ease-out),
              block-size 300ms var(--ease-out);
}

/* --------------------------------------------------------------------------
   16. Forms
   -------------------------------------------------------------------------- */
.form { display: flex; flex-direction: column; gap: 20px; }

.field { display: flex; flex-direction: column; gap: 7px; }
.field > label {
  font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft);
}
.field__hint { font-family: var(--f-mono); font-size: 11px; line-height: 1.55; color: var(--ink-soft); }
.field .req { color: var(--red); }

.input {
  width: 100%; padding: 12px 2px; border: 0;
  border-bottom: var(--rule) solid var(--ink);
  background: transparent; color: var(--ink);
  font-family: var(--f-display); font-size: 16px;
  transition: border-color var(--d-state) var(--ease-out), background-color var(--d-state) var(--ease-out);
}
.input::placeholder { color: var(--ink-mute); }
.input:focus { outline: 0; border-bottom-color: var(--amber); background: rgba(242, 161, 0, .1); }
.input:focus-visible { outline: 0; }
textarea.input { resize: vertical; min-height: 108px; padding-top: 10px; }
select.input { appearance: none; padding-right: 26px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%230a1b3c' stroke-width='2'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 4px center; background-size: 12px; }

.field[data-invalid="true"] .input { border-bottom-color: var(--red); background: rgba(213, 0, 28, .07); }
.field__error {
  display: none; font-family: var(--f-mono); font-size: 11px; line-height: 1.5;
  color: var(--red); padding-left: 18px; position: relative;
}
.field__error::before {
  content: "!"; position: absolute; left: 0; top: 0;
  width: 13px; height: 13px; background: var(--red); color: #fff;
  display: grid; place-items: center; font-size: 9px; font-weight: 600;
}
.field[data-invalid="true"] .field__error { display: block; }

.legend {
  font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft);
  padding: 0; margin-bottom: 8px;
}

.choice { display: flex; flex-wrap: wrap; gap: 8px; }
.choice input { position: absolute; opacity: 0; width: 0; height: 0; }
.choice label {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 11px 15px; border: var(--rule) solid var(--ink-faint);
  font-family: var(--f-narrow); font-weight: 600; font-size: 14px;
  letter-spacing: .06em; text-transform: uppercase; cursor: pointer;
  transition: border-color var(--d-state) var(--ease-out),
              background-color var(--d-state) var(--ease-out);
}
.choice label:hover { border-color: var(--ink); }
.choice input:checked + label { border-color: var(--amber); background: rgba(242, 161, 0, .18); }
.choice input:focus-visible + label { outline: 3px solid var(--amber); outline-offset: 3px; }

/* The consent line is a sentence, not a field label, so it must escape the
   uppercase label styling. `.field > label` is (0,1,1), so this has to be at
   least as specific to win. */
.field > label.consent {
  display: flex; gap: 11px; align-items: flex-start;
  font-family: var(--f-display); font-weight: 400; font-size: var(--t-small);
  letter-spacing: 0; text-transform: none; color: var(--ink-soft);
}
.consent input { width: 20px; height: 20px; flex: none; margin: 2px 0 0; accent-color: var(--red); }
.consent span { font-size: 13px; line-height: 1.55; color: var(--ink-soft); }

.formnote { font-family: var(--f-mono); font-size: var(--t-ref); line-height: 1.65; color: var(--ink-soft); }

.formstatus {
  display: none; position: relative;
  padding: 14px 16px 14px 40px;
  border: var(--rule) solid var(--red);
  background: rgba(213, 0, 28, .07);
  font-size: 14px; line-height: 1.5;
}
.formstatus::before {
  content: "!"; position: absolute; left: 14px; top: 15px;
  width: 15px; height: 15px; background: var(--red); color: #fff;
  display: grid; place-items: center;
  font-family: var(--f-narrow); font-weight: 700; font-size: 11px;
}
.formstatus[data-show="true"] { display: block; }
.formstatus--ok { border-color: var(--green); background: rgba(78, 142, 74, .1); }
.formstatus--ok::before { content: "\2713"; background: var(--green); }

/* Honeypot — must stay reachable in the DOM but never seen or focused */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --------------------------------------------------------------------------
   17. Contact panel
   -------------------------------------------------------------------------- */
.contact-grid { display: grid; gap: clamp(28px, 5vw, 64px);
                grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }

.panel { background: var(--paper-2); border: var(--rule) solid var(--ink);
         padding: clamp(22px, 3vw, 36px); box-shadow: 8px 8px 0 0 var(--ink); }

.contactlist { border-top: var(--rule) solid currentColor; }
.contactlist a, .contactlist div {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 0; border-bottom: 1px solid currentColor; text-decoration: none;
}
.contactlist small { display: block; font-family: var(--f-narrow); font-weight: 700; font-size: 11px;
                     letter-spacing: .16em; text-transform: uppercase; color: var(--amber); }
.contactlist b { display: block; font-family: var(--f-display); font-weight: 800; font-size: clamp(19px, 2.4vw, 26px);
                 letter-spacing: -.02em; margin-top: 3px; overflow-wrap: anywhere; }
.contactlist b.is-email { font-size: clamp(15px, 1.7vw, 19px); letter-spacing: -.005em; line-height: 1.3; }
.contactlist svg { width: 20px; height: 20px; flex: none; opacity: .55; transition: transform var(--d-state) var(--ease-out); }
.contactlist a:hover svg { transform: translateX(4px); opacity: 1; }

/* --------------------------------------------------------------------------
   18. Footer + sticky bar
   -------------------------------------------------------------------------- */
.sitefooter { background: var(--ink); color: var(--paper); border-top: var(--rule) solid var(--amber); }
.sitefooter__grid { display: grid; gap: clamp(24px, 4vw, 40px);
                    grid-template-columns: repeat(auto-fit, minmax(212px, 1fr));
                    padding-block: clamp(40px, 5vw, 64px); }
.sitefooter h4 { font-family: var(--f-narrow); font-weight: 700; font-size: 11px;
                 letter-spacing: .18em; text-transform: uppercase; color: var(--amber); margin: 0 0 14px; }
.sitefooter li { margin-bottom: 8px; }
.sitefooter a { font-size: 14px; text-decoration: none; color: var(--paper-soft); }
.sitefooter a:hover { color: var(--paper-2); text-decoration: underline; }
.sitefooter p { font-size: 13px; color: var(--paper-soft); }
.sitefooter__base { border-top: 1px solid var(--ink-3); }
.sitefooter__base .wrap { display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
                          padding-block: 16px; font-family: var(--f-mono); font-size: 10px;
                          letter-spacing: .04em; color: rgba(232, 233, 226, .45); }
/* Links in the base bar stay at the bar's own size and colour — the general
   footer link rule would set them two sizes larger than their sentence. */
.sitefooter__base a { font-size: inherit; color: inherit; text-decoration: underline; }
.sitefooter__base a:hover { color: var(--paper-2); }

.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
  background: var(--ink); border-top: var(--rule) solid var(--amber);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px clamp(14px, 4vw, 24px);
  transform: translateY(110%);
}
.callbar__txt { font-family: var(--f-narrow); font-weight: 700; font-size: 14px;
                letter-spacing: .1em; text-transform: uppercase; color: var(--paper); }
.callbar__act { display: flex; gap: 8px; flex: none; }
@media (max-width: 560px) { .callbar__txt { display: none; } .callbar { justify-content: stretch; }
                            .callbar__act { flex: 1; } .callbar__act .btn { flex: 1; } }

/* --------------------------------------------------------------------------
   18b. Paper surfaces on a navy band

   A paper-backed component sitting on a navy band would otherwise inherit the
   band's paper text colour and disappear. These rules follow the band rules so
   they win at equal specificity, and they are the single place that decides
   "what colour is text on this surface".
   -------------------------------------------------------------------------- */
.panel, .block, .surface-paper { color: var(--ink); }
.panel :is(h1, h2, h3, h4),
.block :is(h1, h2, h3, h4),
.surface-paper :is(h1, h2, h3, h4) { color: var(--ink); }
.panel p, .block p, .surface-paper p { color: var(--ink-soft); }
.panel a:not(.btn), .surface-paper a:not(.btn) { color: var(--red); }
.panel .eyebrow, .surface-paper .eyebrow { color: var(--red); }
.panel .index__row, .surface-paper .index__row { border-bottom-color: var(--ink-faint); }
.panel .index__dots, .surface-paper .index__dots { border-bottom-color: var(--ink-faint); }
.panel .index__ref, .surface-paper .index__ref { color: var(--ink-soft); }
.panel .ref, .surface-paper .ref { color: var(--ink-soft); }
p.formnote, .panel p.formnote { color: var(--ink-soft); }

.block--hero, .block--hero :is(h1, h2, h3, h4) { color: var(--paper); }
.block--hero p, .block--hero .block__note { color: var(--paper-soft); }
.block--hero .block__price { color: var(--amber); }

.card { color: var(--ink); }
.band--ink .card { color: var(--paper); }
.band--ink .card :is(h1, h2, h3, h4) { color: var(--paper-2); }

/* --------------------------------------------------------------------------
   18b2. The scroll car — the school's own car drives the page

   Built by site.js, and only when motion is allowed, so it never exists as a
   dead static ornament. The branded car rides just above the call bar and its
   position along the bottom edge IS your progress through the page: it sets
   off from the right and arrives at the left as you reach the end — driving
   the way it faces, the same journey the route band draws. Decorative only,
   so it never intercepts a click. Desktop only: on a phone the call bar
   already owns that edge.
   -------------------------------------------------------------------------- */
.scrollcar {
  position: fixed; left: 0; bottom: 60px; z-index: 64;
  width: clamp(92px, 9vw, 132px);
  pointer-events: none;
  opacity: 0; visibility: hidden; /* revealed by GSAP with the call bar */
  filter: drop-shadow(0 6px 5px rgba(10, 27, 60, .28));
}
.scrollcar img { width: 100%; height: auto; display: block; }
@media (max-width: 900px) { .scrollcar { display: none; } }

/* The learner plate: white plate, red L, in the bottom-right corner the car's
   road never reaches. A real link — clicking it opens the enquiry form. */
.lplate {
  position: fixed; right: clamp(14px, 2vw, 28px); bottom: 96px; z-index: 65;
  display: block; text-decoration: none;
  opacity: 0; visibility: hidden; /* revealed by GSAP with the call bar */
}
@media (max-width: 900px) { .lplate { display: none; } }

.lplate__float { display: flex; flex-direction: column; align-items: center; }
.lplate__card {
  display: grid; place-items: center;
  width: 58px; height: 58px;
  background: #fff; border: var(--rule) solid var(--ink);
  box-shadow: 4px 4px 0 0 var(--red);
  font-family: var(--f-display); font-weight: 900; font-size: 36px; line-height: 1;
  color: var(--red);
  transition: transform var(--d-state) var(--ease-out),
              box-shadow var(--d-state) var(--ease-out);
}
.lplate__txt {
  display: block; background: var(--ink); color: var(--paper-2);
  font-family: var(--f-narrow); font-weight: 700; font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 4px 9px 3px; margin-top: 6px;
}
.lplate:hover .lplate__card { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 0 var(--red); }
.lplate:active .lplate__card { transform: translate(2px, 2px); box-shadow: 0 0 0 0 var(--red); }

/* --------------------------------------------------------------------------
   18c. Breadcrumbs

   On a location page these do two jobs: they tell a visitor who landed from a
   search where they are, and they give the crawler an explicit hierarchy that
   matches the BreadcrumbList in the page's structured data.
   -------------------------------------------------------------------------- */
.crumbs { margin-bottom: clamp(20px, 3vw, 32px); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.crumbs li {
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .04em;
  color: var(--ink-soft); display: flex; align-items: center; gap: 8px;
}
.band--ink .crumbs li { color: var(--paper-soft); }
.crumbs li + li::before { content: "/"; opacity: .5; }
.crumbs a { color: inherit; text-decoration: none; border-bottom: 1px solid currentColor; }
.crumbs a:hover { color: var(--red); }
.band--ink .crumbs a:hover { color: var(--amber); }
.crumbs [aria-current="page"] { color: var(--ink); }
.band--ink .crumbs [aria-current="page"] { color: var(--paper-2); }

/* --------------------------------------------------------------------------
   18d. Consent banner

   Sits above the call bar and never covers the primary action for long. The
   two buttons are the same size on purpose: a reject option that is harder to
   find than accept is not a free choice, and the ICO treats it as invalid.
   -------------------------------------------------------------------------- */
.consent {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  background: var(--paper-2); color: var(--ink);
  border-top: var(--rule) solid var(--ink);
  box-shadow: 0 -6px 0 0 var(--amber);
  transform: translateY(110%);
  transition: transform var(--d-section) var(--ease-out);
}
.consent[data-show="true"] { transform: none; }
.consent__in {
  max-width: var(--wide); margin: 0 auto;
  padding: clamp(14px, 2vw, 20px) clamp(20px, 5vw, 56px);
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 24px;
}
.consent__txt { margin: 0; flex: 1 1 min(560px, 100%); font-size: 14px; line-height: 1.55; color: var(--ink-soft); }
.consent__txt b { color: var(--ink); }
.consent__txt a { color: var(--red); }
.consent__act { display: flex; gap: 10px; flex: none; }
@media (max-width: 560px) { .consent__act { flex: 1 1 100%; } .consent__act .btn { flex: 1; } }

/* When both are on screen, the call bar sits above the banner. */
.consent[data-show="true"] ~ .callbar { bottom: 100%; }

/* --------------------------------------------------------------------------
   18e. Proof: pass photos and lesson gallery

   Both are empty until the customer supplies real photographs. Nothing here
   renders a placeholder person or a stock smile — on a site whose entire
   argument is trust, a fake face is worse than a blank space.

   A pass photo is the strongest asset this business can have: a real pupil,
   holding a real licence, named, with the month they passed.
   -------------------------------------------------------------------------- */
.quotes { display: grid; gap: clamp(16px, 2vw, 24px);
          grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr)); }

.quote {
  display: flex; flex-direction: column; margin: 0;
  background: var(--paper-2); border: var(--rule) solid var(--ink);
}
.band--ink .quote { background: var(--ink-2); border-color: var(--ink-3); }

.quote__photo { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--paper); }
.quote__photo img { width: 100%; height: 100%; object-fit: cover; }
/* The pass month sits on the photo like a stamp on a print. */
.quote__stamp {
  position: absolute; left: 0; bottom: 0;
  background: var(--red); color: #fff;
  font-family: var(--f-narrow); font-weight: 700; font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; padding: 6px 12px;
}
.quote__body { padding: clamp(18px, 2.2vw, 24px); display: flex; flex-direction: column; gap: 12px; flex: 1; }
.quote__stars { font-size: 14px; letter-spacing: .18em; color: var(--red); }
.band--ink .quote__stars { color: var(--amber); }
.quote__body p { margin: 0; font-size: var(--t-sm); line-height: 1.65; color: var(--ink); }
.band--ink .quote__body p { color: var(--paper); }
.quote__by {
  margin-top: auto; padding-top: 12px; border-top: 1px solid var(--ink-faint);
  font-family: var(--f-narrow); font-weight: 700; font-size: 12px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-soft);
}
.band--ink .quote__by { border-top-color: var(--ink-3); color: var(--paper-soft); }

/* A row of real moments from lessons. Deliberately uneven: a contact sheet,
   not a stock-photo carousel. */
.gallery { display: grid; gap: var(--rule);
           grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.gallery figure { margin: 0; position: relative; overflow: hidden; background: var(--ink-2); }
.gallery img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 1 / 1; }
.gallery figure:nth-child(4n + 1) img { aspect-ratio: 4 / 5; }
.gallery figure:nth-child(4n + 3) img { aspect-ratio: 4 / 5; }
.gallery figcaption {
  position: absolute; inset: auto 0 0 0;
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  color: var(--paper); padding: 8px 12px;
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .04em;
}

/* --------------------------------------------------------------------------
   19. Utility
   -------------------------------------------------------------------------- */
.lede { font-size: clamp(17px, 1.8vw, 21px); line-height: 1.55; max-width: 52ch; }

/* Page-title step, used by the interior sheets. */
.t-hero { font-size: var(--t-hero); font-weight: 900; letter-spacing: -.045em; line-height: .88; }
/* A quieter heading step for sub-sections inside a column. */
.t-sub  { font-size: var(--t-h3); }
.t-h2s  { font-size: var(--t-h2s); }
.t-h3s  { font-size: var(--t-h3s); }
.t-sm   { font-size: var(--t-sm); }
.t-lede { font-size: var(--t-lede); }

/* The lead line of an index row: a name, not a label, so it drops the
   uppercase treatment the surrounding row carries. */
.index__lead { color: var(--ink); font-size: var(--t-sm);
               letter-spacing: 0; text-transform: none; min-width: 0; }
.band--ink .index__lead { color: var(--paper-2); }
.muted { color: var(--ink-soft); }
.band--ink .muted { color: var(--paper-soft); }
.stack > * + * { margin-top: var(--u); }
.mt-l { margin-top: clamp(28px, 4vw, 48px); }
.mb-l { margin-bottom: clamp(28px, 4vw, 48px); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

.notice {
  border: var(--rule) dashed var(--amber); padding: 16px 18px;
  font-family: var(--f-mono); font-size: 12px; line-height: 1.65;
}

.figure { position: relative; }
.figure img { width: 100%; border: var(--rule) solid var(--ink); }
.figure figcaption { margin-top: 10px; font-family: var(--f-mono); font-size: 11px;
                     letter-spacing: .04em; color: var(--ink-soft); }
.band--ink .figure img { border-color: var(--paper); }
.band--ink .figure figcaption { color: var(--paper-soft); }

/* --------------------------------------------------------------------------
   20. Motion — entry states
   The finished state is the default. JS adds [data-anim-ready] to the root and
   only then are entry states applied, so a JS failure or a reduced-motion
   preference always leaves fully-rendered content.
   -------------------------------------------------------------------------- */
[data-anim-ready] [data-reveal],
[data-anim-ready] [data-hero-item] { opacity: 0; }

[data-anim-ready] .band + .band::before {
  transform: scaleX(0);
  transition: transform 900ms var(--ease-out);
}
[data-anim-ready] .band + .band[data-ruled="true"]::before { transform: scaleX(1); }

[data-anim-ready] .eyebrow::before {
  transform: scaleX(0); transform-origin: left center;
  transition: transform 520ms var(--ease-out);
}
[data-anim-ready] .eyebrow[data-drawn="true"]::before { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  [data-reveal], [data-hero-item] { opacity: 1 !important; transform: none !important; }
  .eyebrow::before { transform: none !important; }
  .band + .band::before { transform: none !important; }
  .callbar { transform: none; }
  /* `*` does not reach this pseudo-element, so it is silenced by name. */
  .faq details::details-content { transition-duration: .001ms !important; }
  .drawer nav a, .drawer__foot { opacity: 1 !important; transform: none !important; }
}

@media print {
  .siteheader, .callbar, .drawer, .ticker { display: none !important; }
  body { background: #fff; color: #000; }
  .band--ink { background: #fff !important; color: #000 !important; }
}
