/* ============================================================================
   Draco K9 Academy — public pages.

   Centred, spacious, very few words. The home page is: a headline, the six
   stages, one statement on black, one action on black. That is all.
   ========================================================================== */

.reveal { transform: translateY(18px); transition: opacity 800ms var(--ease), transform 800ms var(--ease); }
.js .reveal { opacity: 0; }
.js .reveal.is-visible { opacity: 1; transform: none; }
html:not(.js) .reveal { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .js .reveal { opacity: 1; transform: none; } }

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

.info-tip { display: inline-flex; vertical-align: middle; color: var(--ink-faint); cursor: help; margin-left: 0.3rem; }
.info-tip:hover { color: var(--accent-text); }
.info-tip-icon { width: 0.95em; height: 0.95em; }

.img-slot { position: relative; overflow: hidden; background: var(--surface-3); border-radius: var(--r-lg); aspect-ratio: var(--ratio, 4 / 3); }
.img-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.img-slot.pending { display: grid; place-content: center; text-align: center; border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-faint); padding: 1.5rem; }
.img-slot.pending span { font-size: var(--fs-xs); max-width: 30ch; }

/* ------------------------------------------------------------------- hero -- */
/* Full-bleed photograph, not a small inset picture floating in a coloured box.
   The image IS the section: it fills the width, sets its own height, and the
   headline sits over its empty left third. A gradient scrim from the left
   guarantees text contrast whatever the photograph does behind it. */
.hero {
  position: relative; isolation: isolate;
  min-height: clamp(420px, 62vh, 620px);
  display: flex; align-items: center;
  background: var(--indigo-900);
  overflow: hidden;
}
.hero-media { position: absolute; inset: 0; z-index: -2; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: 70% 50%; display: block; }
/* Two scrims: a horizontal one for the text column, and a gentle bottom one so
   the section joins the page below it instead of stopping dead. */
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(90deg, rgba(7,13,32,0.94) 0%, rgba(7,13,32,0.86) 32%, rgba(7,13,32,0.45) 58%, rgba(7,13,32,0.12) 100%),
    linear-gradient(0deg, rgba(7,13,32,0.55) 0%, transparent 45%);
}
.hero .container { position: relative; width: 100%; padding-block: clamp(2.5rem, 2rem + 2vw, 4rem); }
.hero-copy { max-width: 30rem; text-align: left; }
.hero h1 {
  font-size: var(--fs-display); line-height: 1.06; letter-spacing: -0.032em;
  font-weight: 700; color: #ffffff; margin: 0 0 0.75rem;
  text-shadow: 0 1px 24px rgba(0,0,0,0.35);
}
.hero .lead { margin: 0; max-width: 30rem; color: #ccd8ef; }
.hero .btn-row { justify-content: flex-start; margin-top: 1.75rem; }
.hero .btn { --btn-bg: #ffffff; --btn-fg: var(--blue-800); }
.hero .btn:hover { --btn-bg: var(--blue-50); }
.hero .link-action { color: #ffffff; }
.hero .link-action:hover { color: var(--blue-200); }

@media (max-width: 720px) {
  .hero { min-height: 78vh; }
  .hero-media img { object-position: 62% 50%; }
  .hero::before {
    background:
      linear-gradient(180deg, rgba(7,13,32,0.55) 0%, rgba(7,13,32,0.82) 55%, rgba(7,13,32,0.94) 100%);
  }
  .hero-copy { max-width: none; }
}

/* ----------------------------------------------------------------- stages -- */
/* Six cards that have to read as a SEQUENCE, not six unrelated boxes. The
   oversized ghost numeral does that work — it is the loudest thing on the card
   and it counts. Each card also carries its real lesson count, so the grid is
   information rather than decoration. */
.stages { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.1rem; }
@media (max-width: 940px) { .stages { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .stages { grid-template-columns: 1fr; } }

.stage {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column;
  text-decoration: none; color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  min-height: 13.5rem;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
/* The photograph is flush to the card edges; the padding lives on .st-body so
   a card without a photograph still looks right — site_photo() renders nothing
   when the file is missing, and the body simply becomes the whole card. */
.stage-media {
  margin: 0; overflow: hidden; flex: 0 0 auto;
  aspect-ratio: var(--ratio, 16 / 10);
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
}
.stage-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 600ms var(--ease);
}
a.stage:hover .stage-media img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) {
  .stage-media img, a.stage:hover .stage-media img { transition: none; transform: none; }
}
/* The numeral is positioned against the BODY, not the card: anchored to the
   card it sat on top of the photograph. */
.st-body {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; flex: 1 1 auto;
  padding: 1.4rem 1.5rem 1.15rem;
}
/* The ghost numeral sits behind the content, fully inside the card. Bleeding
   it off the edge read as a clipping bug rather than as intent. */
.stage .st-num {
  position: absolute; top: 0.6rem; right: 1.1rem; z-index: -1;
  font-family: var(--font-display); font-weight: 700; font-size: 4.6rem;
  line-height: 0.9; letter-spacing: -0.06em;
  color: var(--blue-600); opacity: 0.09;
  font-variant-numeric: tabular-nums; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.stage .st-for {
  display: inline-flex; align-self: flex-start; align-items: center;
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--blue-600); background: var(--blue-50);
  padding: 0.25rem 0.6rem; border-radius: var(--r-pill);
  margin-bottom: 0.9rem; white-space: nowrap;
}
.stage.is-dog .st-for { color: var(--grey-700); background: var(--grey-100); }
.stage h3 { margin: 0 0 0.4rem; font-size: 1.16rem; letter-spacing: -0.026em; }
.stage p { margin: 0; font-size: var(--fs-sm); color: var(--ink-muted); }

/* A footer rule with the real lesson count and an arrow that moves on hover. */
.stage .st-foot {
  display: flex; align-items: center; gap: 0.5rem;
  margin-top: auto; padding-top: 1rem;
  border-top: 1px solid var(--line-faint);
  font-size: var(--fs-xs); font-weight: 600; color: var(--ink-faint);
  white-space: nowrap;
}
.stage .st-foot .icon {
  margin-left: auto; color: var(--blue-600);
  transition: transform var(--dur) var(--ease);
  width: 0.95em; height: 0.95em; stroke-width: 2.4;
}
a.stage:hover {
  transform: translateY(-4px);
  border-color: var(--blue-300);
  box-shadow: 0 2px 4px rgba(23,60,166,0.05), 0 18px 36px -12px rgba(23,60,166,0.28);
  color: inherit;
}
a.stage:hover .st-num { opacity: 0.13; }
a.stage:hover .st-foot .icon { transform: translateX(4px); }
a.stage:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

/* ------------------------------------------------------------ dark moment -- */
/* Full-bleed black. Used exactly twice on the home page. */
.moment { padding-block: clamp(3rem, 2.2rem + 2.6vw, 5rem); text-align: center; }
.moment h2 {
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.3rem); line-height: 1.14; letter-spacing: -0.028em;
  margin: 0 auto 0.85rem; max-width: 24ch; color: var(--ink);
}
.moment p { color: var(--ink-muted); font-size: var(--fs-lead); max-width: 44ch; margin: 0 auto; }
.moment .btn-row { justify-content: center; margin-top: 1.6rem; }

/* ---------------------------------------------------------------three columns -- */
.trio-band { background: var(--field-soft); }
.trio { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2rem; text-align: center; }
@media (max-width: 760px) { .trio { grid-template-columns: 1fr; gap: 2.5rem; } }
.trio h3 { margin-bottom: 0.5rem; }
.trio p { margin: 0; font-size: var(--fs-sm); color: var(--ink-muted); }

/* --------------------------------------------------------------- page head -- */
/* Inner pages opened on flat white with a black headline, which is why they
   read as empty. Every page now starts on the same deep blue field the home
   hero uses, so colour and depth are consistent across the site instead of
   living only on the front page. */
.page-hero {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--field-deep);
  padding-block: clamp(2.5rem, 2rem + 2.4vw, 4.25rem) clamp(2.25rem, 1.8rem + 2vw, 3.5rem);
  text-align: left;
}
.page-hero::before { content: ''; position: absolute; inset: 0; z-index: -1; background: var(--glow); }
.page-hero::after {
  content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0.45;
  background-image: radial-gradient(rgba(255,255,255,0.10) 1px, transparent 1px);
  background-size: 3px 3px;
  mask-image: radial-gradient(75% 80% at 25% 40%, #000, transparent 82%);
}
.page-hero .eyebrow { color: var(--blue-200); }
.page-hero h1 { color: #ffffff; margin-bottom: 0.5rem; max-width: 30ch; }
.page-hero .lead { margin: 0; max-width: 76ch; color: #c3d3ef; }

/* The headline only ever filled the left half of the band, so on anything wider
   than a laptop the right half was dead blue. .hero-head puts a facts panel
   there — the numbers a visitor would otherwise have to hunt for further down
   the page. It is not decoration: if a page has nothing worth stating, it omits
   the panel and the headline spans the full width on its own. */
.page-hero .hero-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 21rem);
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
  align-items: end;
}
@media (max-width: 900px) {
  .page-hero .hero-head { grid-template-columns: minmax(0, 1fr); }
}

.hero-facts {
  /* A DARK scrim, not a white one. The panel sits on the right of the band and
     --field-deep runs 157deg, so the brightest part of the gradient is exactly
     underneath it: a white wash lightened what was already light and dropped
     the labels to 2.5:1. Darkening instead holds them at 6.2:1 over the
     brightest stop, and the panel still reads as glass. */
  background: rgba(6, 12, 30, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--r-lg);
  padding: 1.15rem 1.3rem;
  backdrop-filter: blur(6px);
  display: grid; gap: 0.55rem;
}
.hero-facts h2 {
  font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.09em; color: #cddcf7; margin: 0 0 0.35rem;
}
.hero-facts dl { display: grid; gap: 0.5rem; margin: 0; }
.hero-facts .row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; padding-bottom: 0.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}
.hero-facts .row:last-child { border-bottom: 0; padding-bottom: 0; }
.hero-facts dt { color: #d3e0f6; font-size: var(--fs-sm); }
.hero-facts dd {
  margin: 0; color: #ffffff; font-weight: 600; font-size: var(--fs-sm);
  text-align: right; font-variant-numeric: tabular-nums;
}
.page-hero .breadcrumb { justify-content: flex-start; margin-bottom: 1.1rem; color: #93a9cd; }
.page-hero .breadcrumb a { color: #b7c8e6; }
.page-hero .breadcrumb a:hover { color: #ffffff; }
.page-hero .breadcrumb .sep { color: #6f83a6; }

/* Links on the blue grounds.
   `a { color: var(--accent-text) }` is set globally, and --accent-text is a
   mid blue tuned for white pages. On the deep-blue hero and the accent rail
   cards that put a blue link on a blue field — the "ask us" link in the FAQ
   hero was all but invisible. These grounds need their own link colour.
   White, not an underline: underlining links is ruled out for this site, so
   weight and brightness carry the affordance instead. */
.page-hero a:not(.btn),
.aside-card.accent a:not(.btn) {
  color: #ffffff;
  font-weight: 600;
}
.page-hero a:not(.btn):hover,
.aside-card.accent a:not(.btn):hover { color: var(--blue-200); }
/* The breadcrumb sets its own, dimmer colours on purpose — don't let the rule
   above shout over them. */
.page-hero .breadcrumb a { color: #b7c8e6; font-weight: 400; }
.page-hero .breadcrumb a:hover { color: #ffffff; }

/* ---------------------------------------------------------- page layout -- */
/* Long-form pages get a reading column PLUS a rail, so a wide screen is used
   rather than left as two empty margins. The measure stays readable; the space
   around it does work. */
.page-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20.5rem;
  gap: clamp(2rem, 1rem + 3vw, 4rem);
  align-items: start;
}
@media (max-width: 1040px) { .page-grid { grid-template-columns: minmax(0, 1fr); } }
/* Enrollment's second column holds the sign-up form, not a rail of links, so it
   needs more room than the 20.5rem the reading layout uses. */
.enroll-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 25rem); }
@media (max-width: 1040px) { .enroll-grid { grid-template-columns: minmax(0, 1fr); } }
/* 74ch keeps running prose at a readable measure. Pages whose main column is
   NOT running prose — accordion rows, cards, tables — opt out with .full, or
   the column stops short and reopens the empty gutter this layout exists to
   close. The measure is then enforced by the inner element instead (e.g.
   .collapse-body), not by the column. */
.page-main { min-width: 0; max-width: 74ch; }
.page-main.full { max-width: none; }

.page-aside { position: sticky; top: calc(var(--header-h) + 1.5rem); display: grid; gap: 1rem; }
@media (max-width: 1040px) { .page-aside { position: static; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } }

.aside-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 1.4rem 1.35rem;
  box-shadow: var(--shadow-sm);
}
.aside-card.accent {
  background: linear-gradient(165deg, var(--blue-700), var(--blue-600));
  border-color: transparent; color: #dbe7fb;
  box-shadow: 0 10px 30px -12px rgba(23, 60, 166, 0.5);
}
.aside-card.accent h3 { color: #ffffff; }
.aside-card.accent p { color: #c3d5f5; }
.aside-card.accent .btn { --btn-bg: #ffffff; --btn-fg: var(--blue-800); }
.aside-card.accent .btn:hover { --btn-bg: var(--blue-50); }
.aside-card h3 { font-size: 1rem; margin-bottom: 0.5rem; }
.aside-card p { font-size: var(--fs-sm); color: var(--ink-muted); margin: 0 0 1rem; }
.aside-card .btn { width: 100%; }
.aside-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; }
.aside-list li { display: flex; gap: 0.6rem; align-items: baseline; font-size: var(--fs-sm); color: var(--ink-muted); }
.aside-list .k { color: var(--ink); font-weight: 600; white-space: nowrap; }

/* Table-of-contents variant: a list of links rather than key/value pairs, so
   the rows are tighter and each one is a full-width hit target. */
.aside-list.toc { gap: 0; }
.aside-list.toc li { display: block; border-top: 1px solid var(--line); }
.aside-list.toc li:first-child { border-top: 0; }
.aside-list.toc a {
  display: block; padding: 0.5rem 0; color: var(--ink-muted);
  font-size: var(--fs-sm); line-height: 1.35;
}
.aside-list.toc a:hover { color: var(--blue-600); }

/* Photographs sit in the reading column like a prose block: same radius, same
   elevation, same rhythm, so a page reads as one stack rather than text with a
   picture dropped into it. The ratio is reserved up front so nothing reflows
   when the lazy image arrives. */
.site-photo {
  margin: 0 0 1.25rem;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  background: var(--surface-2);
  aspect-ratio: var(--ratio, 3 / 2);
}
.site-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Prose sections on inner pages get a tinted surface so a long read is not an
   unbroken white field. */
.prose-block {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  /* A hairline alone left these cards flush with the page. The shadow is what
     separates them from the tint behind, which is where the depth comes from. */
  box-shadow: var(--shadow-sm);
}
.prose-block + .prose-block { margin-top: 1.25rem; }
/* Jumping to a heading from a rail link must not park it under the sticky
   header, which is what an unadjusted #anchor does. */
.prose-block .prose h2 { scroll-margin-top: calc(var(--header-h) + 1.5rem); }
/* The heading is inside .prose, not a direct child of the block, so a
   `> h2:first-child` rule never matched and every card opened with a large
   dead gap above its first line. */
.prose-block > h2:first-child,
.prose-block .prose > :first-child { margin-top: 0; }
.section.tinted { background: linear-gradient(180deg, var(--tint), var(--canvas) 70%); }

/* ------------------------------------------------------------ auth screens -- */
/* Sign-in is a split: the brand half in the deep-blue field, the form half on a
   tinted ground. The old layout put a small white card on a white page, which
   had no depth and left the widest screens almost entirely empty. */
.auth-split {
  display: grid;
  grid-template-columns: 1.02fr 1fr;
  align-items: stretch;
  min-height: calc(100vh - var(--header-h) - 4rem);
}
@media (max-width: 900px) {
  .auth-split { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  /* Stacked, the brand half becomes a 450px wall the user has to scroll past
     to reach the form. On a phone it collapses to a compact header: mark,
     headline, nothing else. */
  .auth-brand { padding-block: 2rem; }
  .auth-brand-inner { margin-inline: auto; }
  .auth-brand .brand { margin-bottom: 1.25rem; }
  .auth-brand h2 { font-size: 1.5rem; }
  .auth-brand > .auth-brand-inner > p,
  .auth-points { display: none; }
}

.auth-brand {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--field-deep);
  display: flex; align-items: center;
  padding: clamp(2.5rem, 2rem + 4vw, 5rem) clamp(1.5rem, 1rem + 4vw, 4.5rem);
}
/* Same glow and dot treatment as the page heroes, so this reads as part of the
   site rather than a one-off screen. */
/* The photograph sits furthest back, then a heavy scrim of the brand field
   over it, then the glow. Without the scrim the white headline would be
   sitting on an unpredictable photograph. */
.auth-brand-media {
  position: absolute; inset: 0; z-index: -3; margin: 0;
  aspect-ratio: auto; overflow: hidden;
}
.auth-brand-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.auth-brand::before {
  content: ''; position: absolute; inset: 0; z-index: -1; background: var(--glow);
}
/* No z-index on the scrim. The figure is itself positioned with z-index:-3,
   which creates a stacking context, so a negative z-index here would be
   clamped INSIDE it and never rise above the photograph — which is exactly
   what happened. Plain paint order puts ::after above the img. */
.auth-brand-media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(157deg, rgba(11,21,51,0.95) 0%, rgba(20,47,125,0.92) 45%, rgba(29,79,208,0.88) 100%);
}
.auth-brand::after {
  content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0.45;
  background-image: radial-gradient(rgba(255,255,255,0.10) 1px, transparent 1px);
  background-size: 3px 3px;
  mask-image: radial-gradient(75% 80% at 30% 45%, #000, transparent 82%);
}
.auth-brand-inner { max-width: 30rem; margin-left: auto; }
.auth-brand .brand { margin-bottom: clamp(1.75rem, 1rem + 3vw, 3rem); }
.auth-brand .brand-name { color: #ffffff; }
.auth-brand .brand-sub { color: var(--blue-300); }
.auth-brand h2 {
  color: #ffffff; margin: 0 0 0.6rem;
  text-shadow: 0 2px 18px rgba(4, 10, 26, 0.5);
  font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem); letter-spacing: -0.03em;
}
/* Over a photograph, pale blue reads as washed out even where it technically
   passes contrast. Near-white plus a soft shadow keeps this legible wherever
   the picture happens to be light. */
.auth-brand > .auth-brand-inner > p {
  color: #f2f6ff; margin: 0 0 2rem; max-width: 46ch;
  text-shadow: 0 1px 12px rgba(4, 10, 26, 0.55);
}

.auth-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.85rem; }
.auth-points li {
  display: flex; align-items: flex-start; gap: 0.7rem;
  color: #f2f6ff; font-size: var(--fs-sm);
  text-shadow: 0 1px 12px rgba(4, 10, 26, 0.55);
}
.auth-points .icon { flex: 0 0 auto; margin-top: 0.15em; color: #8fb6ff; }

.auth-panel {
  display: flex; align-items: center; justify-content: flex-start;
  background: linear-gradient(180deg, var(--tint), var(--canvas) 60%);
  padding: clamp(2.5rem, 2rem + 3vw, 4.5rem) clamp(1.5rem, 1rem + 3vw, 4rem);
}
.auth-wrap { max-width: 400px; margin-inline: auto; padding-block: clamp(3rem, 2rem + 3vw, 5rem); }
.auth-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);
  box-shadow: var(--shadow-lg);
  width: 100%; max-width: 26rem;
}
.auth-card h1 { font-size: var(--fs-h2); margin-bottom: 0.4rem; }
.auth-alt { text-align: center; margin-top: 1.6rem; font-size: var(--fs-sm); color: var(--ink-muted); }

/* -------------------------------------------------------- curriculum outline -- */
/* Each track is a card carrying its own colour on a left rail — blue for the
   handler tracks, graphite for the dog tracks, the same rule the home page
   stage cards use. --track-color is set inline per card. */
.track-card {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--track-color, var(--blue-600));
  box-shadow: var(--shadow-sm);
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
}
/* The title band is deliberately darker than the card body, so each track reads
   as "header, then contents" rather than one flat field.
   It is built from --surface-3 (which IS redefined for dark mode) with a wash
   of the track colour over it, rather than from --track-soft: the tint tokens
   are fixed light values with no dark counterpart, so using them directly
   painted a glaring pale band on the dark theme. */
.track-card-head {
  display: flex; align-items: flex-start; gap: 1.15rem;
  padding: 1.6rem 1.75rem 1.25rem;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--track-color, var(--blue-600)) 14%, transparent),
      color-mix(in srgb, var(--track-color, var(--blue-600)) 6%, transparent)),
    var(--surface-3);
  border-bottom: 1px solid var(--line);
}
/* Browsers without color-mix still get the darker band, just untinted. */
@supports not (color: color-mix(in srgb, red 10%, transparent)) {
  .track-card-head { background: var(--surface-3); }
}
/* A thumbnail in the track header. Fixed width so all seven line up down the
   page regardless of how long each track's summary runs, and flex:0 0 auto so
   it never squeezes the text. It disappears on narrow screens, where the space
   is worth more to the words. */
.track-thumb {
  flex: 0 0 auto; margin: 0; width: 9.5rem;
  aspect-ratio: var(--ratio, 16 / 10);
  border-radius: var(--r); overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
}
.track-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 640px) { .track-thumb { display: none; } }

.track-card-head h3, .track-card-head h2 { margin: 0 0 0.35rem; }
/* --ink-muted was tuned against the card surface, not against this darker
   band. On the dog tracks (whose graphite wash lightens the band toward the
   text) it measured 4.23:1 — under AA. --ink-body restores the margin without
   making the summary compete with the title. */
.track-card-head .muted { font-size: var(--fs-sm); max-width: 78ch; color: var(--ink-body); }
.track-icon { display: none; }

/* The track number, so seven cards read as an ordered programme rather than a
   pile. Sized and weighted like the home page's stage numerals. */
.track-num {
  flex: 0 0 auto; order: 2; margin-left: auto;
  font-family: var(--font-display); font-weight: 700; font-size: 2.6rem;
  line-height: 1; letter-spacing: -0.05em;
  color: var(--track-color, var(--blue-600)); opacity: 0.22;
  font-variant-numeric: tabular-nums;
}

/* Modules sat one per row across the full card, which at desktop width left a
   title on the left and a lesson count stranded ~900px away. Two-up closes that
   gap and halves the height of a 27-module page. auto-fit rather than a fixed
   count so the same rule works beside the rail, without it, and on a phone. */
.module-list {
  list-style: none; margin: 0; padding: 0 0.9rem 0.9rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 0.55rem; align-items: start;
}
.module-list > li {
  background: var(--surface-2); border: 1px solid var(--line-faint);
  border-radius: var(--r); overflow: hidden;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.module-list > li:hover { border-color: var(--track-color, var(--blue-300)); }
/* An open module needs the full width: its lesson list is a long ordered run,
   and half a column would wrap every title. */
.module-list > li.is-open { grid-column: 1 / -1; background: var(--surface); }
.module-row { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.9rem 1rem; font-size: var(--fs-sm); }
.module-row .icon { flex: 0 0 auto; margin-top: 0.15em; color: var(--ink-faint); transition: transform var(--dur) var(--ease); }
/* Written to match the FAQ chevron rule above so both collapse widgets share
   one shape. (If you ever measure this as "not rotating" from an automated
   browser: a hidden or backgrounded tab does not advance CSS transitions, so a
   transitioned transform reads as its start frame forever. Open the tab.) */
.collapse.is-open .module-row .icon { transform: rotate(180deg); }
.module-row .module-title { color: var(--ink); font-weight: 600; }
.module-row .module-meta {
  margin-left: auto; color: var(--ink-faint); font-size: var(--fs-xs);
  white-space: nowrap; padding-top: 0.1em;
}

/* Track index rail: number, title, lesson count on one row. */
.aside-list.toc a { display: flex; align-items: baseline; gap: 0.6rem; }
.aside-list.toc .toc-n {
  color: var(--ink-faint); font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.aside-list.toc .toc-c {
  margin-left: auto; color: var(--ink-faint); font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums; flex: 0 0 auto;
}

/* Callouts live HERE, not in platform.css, even though they are mostly a
   lesson-page component. platform.css is only loaded for signed-in app pages,
   so a callout on a public page (safety.php uses two, one of them the "call a
   vet" warning) rendered as bare text with a loose icon — the exact styling
   that carries the urgency was the part that never loaded. site.css is loaded
   on every page including the app ones, so this covers both.
*/
/* Callouts: do / don't / key point / safety / vet. Each carries an icon and a
   colour, because in a training manual these are read out of order. */
.callout {
  display: flex; gap: 0.9rem; align-items: flex-start;
  border: 1px solid var(--line); border-left-width: 3px;
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: 1rem 1.2rem; margin-block: 1.1rem;
  background: var(--surface-2); font-size: var(--fs-sm);
}
.callout > .icon { flex: 0 0 auto; margin-top: 0.15em; }
.callout h4 { margin: 0 0 0.3rem; font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: var(--track-caps); }
.callout p:last-child { margin-bottom: 0; }
.callout.do    { border-left-color: var(--ok);   background: var(--ok-soft); }
.callout.do    h4, .callout.do    > .icon { color: var(--ok-text); }
.callout.dont  { border-left-color: var(--bad);  background: var(--bad-soft); }
.callout.dont  h4, .callout.dont  > .icon { color: var(--bad-text); }
.callout.key   { border-left-color: var(--steel-400); background: var(--warn-soft); }
.callout.key   h4, .callout.key   > .icon { color: var(--warn-text); }
.callout.safety{ border-left-color: var(--bad);  background: var(--bad-soft); }
.callout.safety h4, .callout.safety > .icon { color: var(--bad-text); }
.callout.vet   { border-left-color: var(--info); background: var(--info-soft); }
.callout.vet   h4, .callout.vet   > .icon { color: var(--info-text); }


/* ---------------------------------------------------------------------- FAQ -- */
.faq-group + .faq-group { margin-top: clamp(2rem, 1.5rem + 2vw, 3.25rem); }
.faq-group .section-head { margin-bottom: 1.1rem; max-width: none; }
.faq-group .section-head h2 { font-size: var(--fs-h3); }

/* Rows inside a card: the card already supplies the padding, so the first row
   must not add a top rule and the last must not add a bottom one, or the card
   looks double-bordered. */
.collapse-set .collapse:last-child { border-bottom: 0; }
.collapse-set .collapse:last-child .collapse-body { padding-bottom: 0; }
.collapse-set .collapse:first-child .collapse-head { padding-top: 0; }

/* The hero's jump panel. */
.jump-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.15rem; }
.jump-list li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 0.42rem 0; border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}
.jump-list li:last-child { border-bottom: 0; }
.jump-list a { color: #ffffff; font-size: var(--fs-sm); font-weight: 600; }
.jump-list a:hover { color: var(--blue-200); }
.jump-list .n {
  color: #b7c8e6; font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
}

.collapse { border-bottom: 1px solid var(--line); }
.collapse-head {
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding: 1.5rem 0; color: var(--ink);
  font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; letter-spacing: -0.024em;
}
.collapse-head .icon { color: var(--ink-faint); transition: transform var(--dur) var(--ease); flex: 0 0 auto; }
.collapse.is-open .collapse-head .icon { transform: rotate(180deg); }
.collapse-body { display: none; padding-bottom: 1.6rem; color: var(--ink-muted); max-width: 68ch; }
.collapse.is-open .collapse-body { display: block; }

/* ------------------------------------------------------------------ pricing -- */
.price-card { border-radius: var(--r-lg); padding: 2.25rem; background: var(--canvas-alt); text-align: center; }
.price-amount { font-family: var(--font-display); font-size: 3.25rem; font-weight: 700; letter-spacing: -0.04em; color: var(--ink); line-height: 1; white-space: nowrap; }
.price-term { color: var(--ink-faint); font-size: var(--fs-sm); white-space: nowrap; }
.price-list { list-style: none; padding: 0; margin: 2rem 0; display: grid; gap: 0.85rem; text-align: left; }
.price-list li { display: flex; gap: 0.7rem; align-items: flex-start; font-size: var(--fs-sm); }
.price-list .icon { color: var(--ok); margin-top: 0.2em; }

/* ---------------------------------------------------------------- notices -- */
.scope-note { border-radius: var(--r); background: var(--canvas-alt); padding: 1.35rem 1.5rem; font-size: var(--fs-sm); }

/* Legacy class names, kept so older pages keep a sensible box. */
.feature, .point { text-align: center; }
.feature h3, .point h3 { margin-bottom: 0.5rem; }
.feature p, .point p { margin: 0; color: var(--ink-muted); font-size: var(--fs-sm); }
.feature-icon { display: none; }
.points { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 3rem 2.5rem; }
.cta { padding-block: var(--sec-y-sm); text-align: center; }
