/* ==========================================================================
   SolutionTee TechHub — page-level styles
   ========================================================================== */

/* ── HERO ───────────────────────────────────────────────────────────── */
.hero {
  position: relative;
  min-height: min(82svh, 880px);
  display: flex; align-items: center;
  padding-block: clamp(1.5rem, 2.8vw, 3rem) clamp(1.75rem, 3.2vw, 3.5rem);
  background: var(--grad-hero);
  overflow: hidden;
  isolation: isolate;
}
.hero__canvas { position: absolute; inset: 0; z-index: 0; opacity: 0.85; }
.hero__grid { z-index: 1; }
.hero__inner {
  position: relative; z-index: 3;
  display: grid; gap: clamp(2.5rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  align-items: center; width: 100%;
}
@media (max-width: 980px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero { min-height: auto; }
}

.hero__badge {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.45rem 0.5rem 0.45rem 0.9rem; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--line);
  font-size: var(--fs-xs); color: var(--text-muted);
  backdrop-filter: var(--blur-glass);
}
.hero__badge b {
  padding: 0.25rem 0.65rem; border-radius: var(--r-pill);
  background: var(--grad-accent); color: var(--brand-900);
  font-family: var(--font-mono); font-size: 0.62rem;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.hero__pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--mint-500); box-shadow: 0 0 0 0 rgba(34,197,139,.6); animation: pulse 2.2s infinite; }
/* The tagline plus the "SaaS + Academy" pill is wider than a phone, so the
   badge wrapped to two lines and stopped reading as a pill at all. The pill
   goes; the tagline is the half that carries meaning, and "SaaS + Academy"
   is said again in the section directly below. */
@media (max-width: 620px) {
  .hero__badge { padding-inline-end: 0.9rem; }
  .hero__badge b { display: none; }
}

@keyframes pulse { 70% { box-shadow: 0 0 0 9px rgba(34,197,139,0); } 100% { box-shadow: 0 0 0 0 rgba(34,197,139,0); } }

.hero h1 {
  font-size: var(--fs-hero);
  line-height: 1.1;          /* 1.06 is too tight once it wraps on a phone */
  margin-block: var(--sp-4);
  max-width: 22ch;           /* keeps the headline to two lines as it scales */
}
.hero__lede {
  font-size: var(--fs-lg); color: var(--text-muted);
  /* A lede sets tighter than body copy: 1.65 is paragraph rhythm and it reads
     loose at this size. 1.5 is the floor for comfortable multi-line reading. */
  line-height: 1.5;
  max-width: 66ch;           /* inside the 60-75ch measure */
  text-wrap: pretty;         /* no single word stranded on the last line */
}
.hero__ticker { margin-block-end: var(--sp-4); }
.hero__where {
  margin-top: var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 0.85rem; margin-top: var(--sp-5); }

/* Rotating word */
.rotator { display: inline-grid; vertical-align: bottom; overflow: hidden; height: 1.05em; }
.rotator > span {
  grid-area: 1 / 1;
  background: var(--grad-accent);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  opacity: 0; transform: translateY(105%);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.rotator > span.is-current { opacity: 1; transform: none; }
.rotator > span.is-leaving { opacity: 0; transform: translateY(-105%); }

/* Hero stat strip */
.hero__stats {
  display: flex; flex-wrap: wrap; gap: clamp(1rem, 2.4vw, 2.25rem);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}
/* Four tiles wrapping freely at 375px produced two ragged rows and 133px of
   hero. A two-column grid puts them on an even pair of rows in half the
   space, and the labels stop hanging under the wrong number. */
/* Phone hero, remaining bits. The two buttons cannot sit side by side at this
   width, and left-aligned at their natural 236px and 232px they stacked into
   a ragged pair; full width makes them read as a deliberate stack and gives
   the primary action a proper tap target. The lede drops one step so the
   opening paragraph is five lines instead of six - still well above the 16px
   floor for body text. */
@media (max-width: 620px) {
  .hero__cta { gap: 0.6rem; }
  .hero__cta .btn { width: 100%; }
  .hero__lede { font-size: 1.0625rem; }
}

@media (max-width: 620px) {
  .hero__stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4) var(--sp-3);
  }
  .hero__stat b { font-size: 1.5rem; }
  .hero__stat span { font-size: 0.7rem; letter-spacing: 0.04em; }
}
.hero__stat b {
  display: block; font-family: var(--font-display);
  font-size: clamp(1.35rem, 2vw, 1.85rem); line-height: 1.1;
  /* These count up on load; proportional digits reflow the row each frame. */
  font-variant-numeric: tabular-nums;
  background: var(--grad-brand); -webkit-background-clip: text; background-clip: text; color: transparent;
}

.hero__stat span { font-size: var(--fs-xs); color: var(--text-dim); font-family: var(--font-mono); letter-spacing: 0.06em; }

/* Short desktop viewports: 720p laptops, and anything in landscape. Same type
   sizes, tighter vertical rhythm, so the hero still ends within one screen. */
@media (min-width: 981px) and (max-height: 820px) {
  .hero { padding-block: 1.25rem 1.5rem; }
  .hero h1 { margin-block: 0.75rem; }
  .hero__ticker { margin-block-end: var(--sp-3); }
  .hero__cta { margin-top: var(--sp-4); }
  .hero__stats { margin-top: var(--sp-4); padding-top: var(--sp-3); }
}

/* Narrow columns: from a small laptop down, the headline wraps to three lines
   or more, and 1.1 leading crowds the ascenders against the descenders above
   them. Display type does not want full body leading, but it wants more than
   this - so it opens up exactly where the wrapping starts. */
@media (max-width: 1100px) {
  .hero h1 { line-height: 1.16; }
}

/* Small laptops still get two columns, but an even split leaves the copy about
   477px wide - narrow enough that the headline wraps a third time, the lede a
   fifth, and the two large buttons onto separate rows. Weighting the split
   toward the copy fixes all three at once; the scene is aspect-ratio driven,
   so it simply gets shorter along with it. */
@media (min-width: 981px) and (max-width: 1100px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr);
    gap: clamp(1.5rem, 3vw, 2.5rem);
  }
}


/* ── The 3D workspace scene ─────────────────────────────────────────── */
.scene {
  position: relative;
  aspect-ratio: 1 / 0.98;
  perspective: 1400px;
  perspective-origin: 55% 40%;
  transform-style: preserve-3d;
}
.scene__stage {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 12deg)) rotateY(var(--ry, -16deg));
  transition: transform 900ms var(--ease-out);
  will-change: transform;
}
.scene__halo {
  position: absolute; left: 50%; top: 46%; translate: -50% -50%;
  width: 78%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, rgba(37,99,179,.42), transparent 66%);
  filter: blur(38px);
}
.scene__ring {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  border: 1px solid var(--line-strong); border-radius: 50%;
  transform-style: preserve-3d;
}
.scene__ring--1 { width: 92%; aspect-ratio: 1; transform: translate(-50%, -50%) rotateX(74deg); animation: ring-spin 22s linear infinite; }
.scene__ring--2 { width: 72%; aspect-ratio: 1; transform: translate(-50%, -50%) rotateX(74deg) rotateZ(40deg); border-color: var(--line-accent); animation: ring-spin 30s linear infinite reverse; }
@keyframes ring-spin { to { transform: translate(-50%, -50%) rotateX(74deg) rotateZ(360deg); } }

/* Desk plane */
.scene__desk {
  position: absolute; left: 50%; bottom: 12%; translate: -50% 0;
  width: 74%; aspect-ratio: 2.4 / 1;
  background: linear-gradient(160deg, rgba(37,99,179,.32), rgba(11,31,68,.85));
  border: 1px solid var(--line-strong);
  border-radius: 18px;
  transform: rotateX(72deg);
  transform-origin: bottom center;
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.85);
}
.scene__desk::after {
  content: ""; position: absolute; inset: 8px;
  border: 1px dashed rgba(255,255,255,.1); border-radius: 12px;
}

/* Floating panels */
.panel {
  position: absolute;
  background: linear-gradient(155deg, rgba(13,34,69,.94), rgba(6,17,36,.96));
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: 0 30px 60px -26px rgba(0,0,0,.9);
  overflow: hidden;
  backdrop-filter: blur(6px);
  animation: float-y 7s var(--ease-in-out) infinite;
}
@keyframes float-y { 50% { translate: 0 -14px; } }

.panel__bar {
  display: flex; align-items: center; gap: 5px;
  padding: 8px 10px; border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.04);
}
.panel__bar i { width: 7px; height: 7px; border-radius: 50%; background: var(--line-strong); }
.panel__bar i:nth-child(1) { background: #ff5f57; }
.panel__bar i:nth-child(2) { background: #febc2e; }
.panel__bar i:nth-child(3) { background: #28c840; }
.panel__bar span { margin-inline-start: auto; font-family: var(--font-mono); font-size: 0.55rem; color: var(--text-dim); letter-spacing: 0.08em; }

/* Panel A — code editor */
.panel--code {
  left: 2%; top: 6%; width: 58%; aspect-ratio: 1.42 / 1;
  transform: translateZ(70px);
  animation-delay: -0.6s;
}
.code-lines { padding: 12px 14px; font-family: var(--font-mono); font-size: clamp(0.45rem, 0.85vw, 0.66rem); line-height: 1.85; }
.code-lines div { display: flex; gap: 10px; opacity: 0; animation: code-in 460ms var(--ease-out) forwards; }
.code-lines div:nth-child(1) { animation-delay: .5s; }
.code-lines div:nth-child(2) { animation-delay: .68s; }
.code-lines div:nth-child(3) { animation-delay: .86s; }
.code-lines div:nth-child(4) { animation-delay: 1.04s; }
.code-lines div:nth-child(5) { animation-delay: 1.22s; }
.code-lines div:nth-child(6) { animation-delay: 1.4s; }
.code-lines div:nth-child(7) { animation-delay: 1.58s; }
@keyframes code-in { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: none; } }
.code-lines u { color: var(--text-dim); text-decoration: none; user-select: none; min-width: 1.2em; text-align: right; }
.tk-key { color: #c792ea; } .tk-fn { color: #82aaff; } .tk-str { color: #c3e88d; }
.tk-num { color: #f78c6c; } .tk-com { color: #5a6b8c; } .tk-var { color: #ffcb6b; }
.caret { display: inline-block; width: 6px; height: 1em; background: var(--accent-500); vertical-align: -2px; animation: blink 1.05s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* Panel B — analytics */
.panel--chart {
  right: 0%; top: 30%; width: 44%; aspect-ratio: 1.15 / 1;
  transform: translateZ(150px);
  animation-delay: -2.4s;
}
.chart-body { padding: 12px; display: flex; flex-direction: column; height: calc(100% - 33px); }
.chart-kpi { font-family: var(--font-display); font-size: clamp(1.1rem, 2.4vw, 1.7rem); line-height: 1; }
.chart-kpi small { display: block; font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: .12em; color: var(--text-dim); text-transform: uppercase; margin-bottom: 4px; }
.chart-bars { display: flex; align-items: flex-end; gap: 5px; flex: 1; margin-top: 10px; }
.chart-bars i {
  flex: 1; border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--brand-300), var(--brand-500));
  transform-origin: bottom; animation: bar-grow 900ms var(--ease-spring) backwards;
}
.chart-bars i:nth-child(4n) { background: linear-gradient(180deg, var(--accent-400), var(--accent-600)); }
@keyframes bar-grow { from { transform: scaleY(0); } }

/* Panel C — design swatches */
.panel--design {
  left: 12%; bottom: 4%; width: 40%; aspect-ratio: 1.9 / 1;
  transform: translateZ(210px);
  animation-delay: -4.1s;
}
.swatches { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 12px; }
.swatches i { aspect-ratio: 1; border-radius: 7px; box-shadow: inset 0 -8px 14px -8px rgba(0,0,0,.6); }
.type-spec { padding: 0 12px 12px; font-family: var(--font-display); font-size: 0.62rem; color: var(--text-dim); letter-spacing: .06em; }

/* The people */
.scene__people { position: absolute; left: 50%; bottom: 15%; translate: -50% 0; width: 66%; transform: translateZ(30px); }
.scene__people svg { width: 100%; height: auto; }
.person-a { animation: sway 6s var(--ease-in-out) infinite; transform-origin: bottom center; }
.person-b { animation: sway 6s var(--ease-in-out) infinite -3s; transform-origin: bottom center; }
@keyframes sway { 50% { transform: rotate(1.1deg) translateY(-3px); } }

/* Floating tokens */
.token {
  position: absolute; display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.75rem; border-radius: var(--r-pill);
  background: rgba(8, 22, 46, 0.9); border: 1px solid var(--line-strong);
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: .06em;
  color: var(--text-muted); box-shadow: var(--shadow-md);
  animation: float-y 5.5s var(--ease-in-out) infinite;
}
.token i { width: 6px; height: 6px; border-radius: 50%; }
.token--1 { top: 2%; right: 12%; transform: translateZ(260px); animation-delay: -1.2s; }
.token--2 { bottom: 30%; left: -4%; transform: translateZ(240px); animation-delay: -3.3s; }
.token--3 { bottom: 2%; right: 4%; transform: translateZ(200px); animation-delay: -2.1s; }

@media (max-width: 980px) {
  /* Every child of .scene is absolutely positioned, so its content size is
     zero - and the parent's `align-items: center` stops it stretching, which
     left the whole workspace computing to 0x0 the moment the hero stacked
     into one column. It has been invisible on every phone and tablet since it
     was written. A definite inline size is all it needs. */
  .scene { width: 100%; max-width: 560px; margin-inline: auto; }
  .scene__stage { transform: rotateX(8deg) rotateY(-8deg); }
}

/* Phones get a purpose-built version rather than the desktop composition
   shrunk down. At 335px the three overlapping panels, the rings, the desk and
   the floating tokens collapse into mush, and the code sets at 7px. So the
   3D is flattened, the scenery is dropped, and what remains is the part that
   actually says something: the editor, at a readable size, over the people
   the brief asked for. */
@media (max-width: 620px) {
  .scene {
    aspect-ratio: auto;        /* height comes from the content now */
    perspective: none;
    margin-top: var(--sp-6);
  }
  .scene__stage {
    position: static;
    display: grid;
    gap: var(--sp-4);
    transform: none;
  }
  /* Scenery that only reads at desktop scale. */
  .scene__ring, .scene__desk, .token, .panel--chart, .panel--design { display: none; }

  .panel {
    position: static;
    width: auto;
    aspect-ratio: auto;
    transform: none;
    /* Drifting panels make sense floating in space; in a flow layout the same
       animation just jitters the block against the text above it. */
    animation: none;
  }
  .code-lines { font-size: 0.74rem; line-height: 1.75; padding: 14px 16px; }

  .scene__halo { width: 92%; top: 38%; filter: blur(46px); }
  .scene__people { position: static; width: 72%; margin-inline: auto; transform: none; }
}

/* Marquee */
.marquee {
  position: relative; overflow: hidden; padding-block: 1.1rem;
  border-block: 1px solid var(--line); background: var(--bg-alt);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track { display: flex; gap: 3.5rem; width: max-content; animation: marquee 34s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }
.marquee__item {
  display: inline-flex; align-items: center; gap: 0.7rem;
  font-family: var(--font-display); font-size: clamp(0.9rem, 1.5vw, 1.15rem);
  font-weight: 600; color: var(--text-dim); white-space: nowrap;
}
.marquee__item::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-500); }

/* ── Service cards ──────────────────────────────────────────────────── */
.service-card { --card-accent: var(--brand-400); }
.service-card__num {
  position: absolute; top: 1rem; right: 1.35rem;
  font-family: var(--font-display); font-size: 3.4rem; font-weight: 700;
  line-height: 1; color: transparent; -webkit-text-stroke: 1px var(--line-strong);
  transition: -webkit-text-stroke-color var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
  pointer-events: none;
}
.service-card:hover .service-card__num { -webkit-text-stroke-color: var(--card-accent); opacity: .6; }
.service-card ul { display: flex; flex-direction: column; gap: 0.55rem; margin-top: var(--sp-4); }
.service-card li { display: flex; gap: 0.6rem; align-items: flex-start; font-size: var(--fs-sm); color: var(--text-muted); }
.service-card li::before {
  content: ""; flex-shrink: 0; width: 16px; height: 16px; margin-top: 3px; border-radius: 50%;
  background: color-mix(in srgb, var(--card-accent) 25%, transparent);
  box-shadow: inset 0 0 0 1.5px var(--card-accent);
}
.price-tag { font-family: var(--font-display); font-size: var(--fs-lg); font-weight: 700; }
.price-tag small { font-size: var(--fs-xs); color: var(--text-dim); font-weight: 400; font-family: var(--font-body); }

/* ── Course / training cards ────────────────────────────────────────── */
.course-card { --card-accent: var(--brand-400); }
.course-card__meta { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: var(--sp-3); }
.course-card__price { display: flex; align-items: baseline; gap: 0.5rem; }
.course-card__price del { color: var(--text-dim); font-size: var(--fs-sm); }
.course-card__ribbon {
  position: absolute; top: 1rem; left: 1rem; z-index: 2;
  padding: 0.3rem 0.7rem; border-radius: var(--r-pill);
  background: var(--grad-accent); color: var(--brand-900);
  font-family: var(--font-mono); font-size: 0.58rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.progress { height: 6px; border-radius: var(--r-pill); background: var(--line); overflow: hidden; }
/* Constant motion toward a known target reads honestly only at a constant
   rate; an eased progress bar looks like it stalled near the end. */
.progress > i { display: block; height: 100%; border-radius: inherit; background: var(--grad-accent); transition: width var(--dur-slow) linear; }
.progress--brand > i { background: var(--grad-brand); }

.mode-pill { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--fs-xs); color: var(--text-muted); }
.mode-pill svg { width: 14px; height: 14px; color: var(--accent-ink); }

/* ── Value props ────────────────────────────────────────────────────── */
.value-card { --card-accent: var(--accent-500); text-align: left; }
.value-card__metric {
  font-family: var(--font-display); font-size: clamp(2rem, 3.4vw, 2.9rem);
  font-weight: 700; line-height: 1;
  background: var(--grad-accent); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.value-card__metric + span { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }

/* ── Team ───────────────────────────────────────────────────────────── */
/* ── People ──────────────────────────────────────────────────────────
   The old card was the stock "meet the team" component: a circle avatar in
   a glowing double ring, everything centred, four skill pills and a tray of
   social icons. Six of them in a row read as placeholder data rather than
   as six people who work here.

   This is the same editorial card as everywhere else on the site, with a
   photograph doing the work the type does on the others. */
/* Two classes, not one. `.ed` sets the card padding a thousand lines below
   this, and at equal specificity the later rule won — so the photograph was
   being inset by 24px on every side and the frame never reached the card's
   edge. */
.ed.ed--person { padding: 0; overflow: hidden; }

/* The row is capped rather than stretched. With three people and a 230px
   floor, auto-fit gave each card a third of the container — about 375px —
   and a 5:6 portrait of that width is 450px tall before the name. Three
   people should not fill a screen. */
.team-grid {
  display: grid;
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
  /* Wider tracks than the portrait version could take. A stacked card gets
     taller as it gets wider — the photo is square, so width *is* height —
     which is why widening had to come with a change of composition rather
     than a bigger number here. */
  /* 350 is the widest track that still fits three across the 1100px grid
     (3 x 350 + 2 x 19 gap = 1088). At 370 only two fitted and the third
     person sat alone on a second row. */
  grid-template-columns: repeat(auto-fit, minmax(270px, 350px));
  justify-content: center;
}

/* Photo beside the text, not above it.

   Stacked, the card's height was the photo plus the whole body — 464px for
   232px of width, a column so narrow that two-word names wrapped. Side by
   side, the height is only the taller of the two columns, so the card can
   grow wider while getting shorter. */


.person__frame {
  position: relative;
  /* Square, and in the side-by-side layout it stretches to whatever height
     the text column needs — `cover` keeps the face uncropped either way. */
  aspect-ratio: 1 / 1;
  min-height: 100%;
  overflow: hidden;
  background: var(--surface-strong);
  border-block-end: 1px solid var(--line);
}
.person__photo {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Faces sit high in a frame; centring the crop cuts foreheads. */
  object-position: 50% 22%;
  transition: transform 600ms var(--ease-out);
}
/* No greyscale. It was applied at rest and lifted on hover, so on a phone —
   where there is no hover — these were permanently black and white. Real
   people photographed in colour should appear in colour; the set is held
   together by the identical crop and frame, not by draining them. */
@media (hover: hover) and (pointer: fine) {
  .ed--person:hover .person__photo { transform: scale(1.03); }
}
.person__initials {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.2rem, 4vw, 3.2rem);
  color: var(--line-strong);
}

.person__body {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: clamp(0.8rem, 1.2vw, 1rem);
}
/* `.ed--person` prefix, not a bare `.person__name`: the element also
   carries `.ed__title`, whose rule sits ~1000 lines further down this file
   and won on order alone. That left names rendering at 24.8px on a 236px
   card — "Emmanuel Akinbola" wanted 222px in a 180px column, so every
   two-word name wrapped. */
.ed--person .person__name {
  font-size: clamp(1rem, 1.2vw, 1.12rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  /* `.ed__title` sets `text-wrap: balance`, which is right for a headline
     and wrong for a name: "Emmanuel Akinbola" needed 146px of a 180px
     column, and balance split it into two 77-pixel lines *because it
     could*. Names break only when they genuinely do not fit.

     `wrap`, not `normal`: the engine rejects `normal` here and drops the
     declaration silently, which left balance still winning. `wrap` sets the
     mode and resets the style to auto, which is the actual off switch. */
  text-wrap: wrap;
  text-wrap-style: auto;
}
.person__bio {
  max-width: 38ch;
  /* Bios are written to wildly different lengths; three lines keeps a row
     of cards the same height without truncating anyone mid-word. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.person__skills {
  margin: 0.15rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-dim);
  /* One line. In a 232px column a four-skill list wrapped to three, which
     was more of the card than the person's own name. */
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden;
}
.person__skills i { font-style: normal; color: var(--line-strong); }

.person__links {
  display: flex; gap: 0.15rem; margin-top: auto; padding-top: 0.7rem;
}
.person__links a {
  display: grid; place-items: center; width: 28px; height: 28px;
  border-radius: 6px; color: var(--text-dim);
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.person__links a:hover { background: var(--surface); color: var(--accent-ink); }

/* ── Process steps ──────────────────────────────────────────────────── */
.steps { position: relative; display: grid; gap: var(--sp-5); }
.steps::before {
  content: ""; position: absolute; left: 27px; top: 30px; bottom: 30px; width: 2px;
  background: linear-gradient(180deg, var(--accent-500), var(--brand-400), transparent);
  opacity: .35;
}
.step { display: grid; grid-template-columns: 56px 1fr; gap: var(--sp-4); align-items: start; position: relative; }
.step__num {
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: 1.05rem;
  background: var(--bg); color: var(--accent-ink);
  border: 1.5px solid var(--line-accent);
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.step:hover .step__num { background: var(--grad-accent); color: var(--brand-900); border-color: transparent; }
@media (hover: hover) and (pointer: fine) {
  .step:hover .step__num { transform: scale(1.06); }
}
.step h4 { margin-bottom: 0.3rem; }
.step p { color: var(--text-muted); font-size: var(--fs-sm); }

/* ── Testimonials ───────────────────────────────────────────────────── */
.testimonial-rail {
  display: flex; gap: var(--sp-4); overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: var(--sp-4);
  /* Full-bleed track, gutter-aligned contents: the first card shares the
     heading's leading edge and the next one peeks past the trailing edge. */
  margin-inline: calc(-1 * var(--gutter-safe));
  padding-inline: var(--gutter-safe);
  scroll-padding-inline: var(--gutter-safe);
  overscroll-behavior-inline: contain;
  scrollbar-width: none;
}
.testimonial-rail::-webkit-scrollbar { display: none; }
.stars { display: inline-flex; gap: 2px; color: var(--accent-ink); }
.stars svg { width: 14px; height: 14px; }
.rail-nav { display: flex; gap: 0.5rem; }
.rail-nav[hidden] { display: none; }

/* ── FAQ split ──────────────────────────────────────────────────────── */
.faq-layout { display: grid; gap: clamp(2rem, 4vw, 4rem); grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); align-items: start; }
@media (max-width: 900px) { .faq-layout { grid-template-columns: 1fr; } }

/* ── CTA band ───────────────────────────────────────────────────────── */
.cta-band {
  position: relative; overflow: hidden;
  border-radius: var(--r-2xl);
  padding: clamp(2.5rem, 6vw, 5rem);
  background:
    radial-gradient(90% 140% at 12% 0%, rgba(37,99,179,.55), transparent 60%),
    radial-gradient(80% 130% at 92% 100%, rgba(242,178,51,.35), transparent 62%),
    linear-gradient(140deg, var(--brand-800), var(--brand-700));
  border: 1px solid var(--line-strong);
  text-align: center;
}
.cta-band h2 { font-size: var(--fs-3xl); }
.cta-band .row { justify-content: center; margin-top: var(--sp-6); }

/* ── Page hero (inner pages) ────────────────────────────────────────── */
.page-hero {
  position: relative; overflow: hidden; isolation: isolate;
  padding-block: clamp(3rem, 7vw, 6rem) clamp(2.5rem, 5vw, 4rem);
  background: var(--grad-hero);
  border-bottom: 1px solid var(--line);
}
/* Course, training and service pages set --card-accent on this section, and
   used to express it as a blurred 420px circle nudged into the corner with
   per-page magic numbers (-24%/-6%/.3 on one page, -22%/-8%/.25 on the next,
   varied for variety rather than for any reason). --grad-hero already lays
   down two washes; this is the accent one, in the same idiom, taking its
   colour from the value the page already declares. Pages with no accent get
   `transparent` and the rule paints nothing. */
.page-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(
    64% 78% at 88% 0%,
    color-mix(in srgb, var(--card-accent, transparent) 20%, transparent),
    transparent 70%
  );
}
.page-hero h1 { font-size: var(--fs-3xl); }
.page-hero .lede { margin-top: var(--sp-4); }
.breadcrumbs { display: flex; flex-wrap: wrap; gap: 0.5rem; font-size: var(--fs-xs); color: var(--text-dim); margin-bottom: var(--sp-4); }
.breadcrumbs a:hover { color: var(--accent-ink); }
.breadcrumbs span { opacity: .45; }

/* ── Filter bar ─────────────────────────────────────────────────────── */
/* ── Filter bar ──────────────────────────────────────────────────────
   A search field with controls beside it, not a panel of equal inputs.
   The typing is the primary act — it gets the width and the weight; the
   selects are adjustments and read as such. */
.filter-bar {
  display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center;
  padding: 0; border: 0; background: none;
  margin-bottom: var(--sp-5);
}
.filter-bar .select {
  padding: 0.62rem 2rem 0.62rem 0.85rem;
  font-size: var(--fs-xs);
  border-radius: var(--r-sm);
  background-color: var(--surface);
  border-color: var(--line);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.filter-bar .select:hover { border-color: var(--line-strong); }

.search-field {
  position: relative;
  flex: 1 1 280px;
  min-width: 220px;
  isolation: isolate;
}
.search-field::after {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: calc(var(--r-md) + 1px);
  background: linear-gradient(115deg, var(--accent-500), var(--brand-500, var(--accent-500)));
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.search-field:focus-within::after { opacity: 1; }
.search-field svg {
  position: absolute; inset-inline-start: 1rem; top: 50%; translate: 0 -50%;
  width: 18px; height: 18px; color: var(--text-dim); pointer-events: none;
  transition: color var(--dur-fast) var(--ease-out);
}
.search-field:focus-within svg { color: var(--accent-ink); }
.search-field .input {
  width: 100%;
  min-height: 50px;
  padding: 0.78rem 2.8rem 0.78rem 3rem;
  font-size: max(1rem, var(--fs-sm));
  line-height: 1.35;
  border-radius: var(--r-md);
  border-color: var(--line-strong);
  background: var(--surface);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--text) 6%, transparent);
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
.search-field .input::placeholder { color: var(--text-dim); opacity: .82; }
.search-field .input:hover { border-color: var(--line-accent); }
.search-field .input:focus-visible {
  outline: none;
  border-color: transparent;
  background: var(--bg);
  box-shadow: 0 10px 30px color-mix(in srgb, var(--accent-500) 12%, transparent),
              0 0 0 4px color-mix(in srgb, var(--accent-500) 14%, transparent);
}
/* Safari and Chrome paint their own clear button, at their own size and in
   their own grey. The field already has a Clear control. */
.search-field input[type="search"]::-webkit-search-decoration,
.search-field input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }

/* The dedicated site search is one compact control. In a column flex layout
   the generic field's 260px flex-basis became height, creating a huge empty
   container on phones; an explicit grid avoids that axis switch. */
.search-page-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  max-width: 680px;
  padding: .5rem;
  border-radius: calc(var(--r-md) + .35rem);
  box-shadow: 0 18px 45px color-mix(in srgb, var(--text) 8%, transparent);
}
.search-page-form .search-field { width: 100%; min-width: 0; }
.search-page-form .btn { min-width: 104px; }

/* ── Live results ────────────────────────────────────────────────────
   While a request is in flight the old results stay put and fade slightly,
   rather than being cleared to a spinner. Swapping in a loading state makes
   the page jump twice per keystroke; this makes it feel like the same list
   settling. */
[data-results] {
  transition: opacity var(--dur-fast) var(--ease-out);
}
[data-results].is-loading a { pointer-events: none; }

.result-line {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-xs); color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  [data-results] { transition: none; }
}

/* ── Detail layouts ─────────────────────────────────────────────────── */
.detail-layout { display: grid; gap: clamp(1.75rem, 3.5vw, 3rem); grid-template-columns: minmax(0, 1fr) 360px; align-items: start; }
@media (max-width: 980px) { .detail-layout { grid-template-columns: 1fr; } }
.sticky-side { position: sticky; top: calc(var(--nav-h) + 1.5rem); }

.prose { max-width: 72ch; font-size: var(--fs-md); line-height: 1.78; color: var(--text-muted); }
.prose > * + * { margin-top: 1.15em; }
.prose h2 { font-size: var(--fs-xl); color: var(--text); margin-top: 2em; }
.prose h3 { font-size: var(--fs-lg); color: var(--text); margin-top: 1.7em; }
.prose a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
.prose ul, .prose ol { padding-inline-start: 1.35em; }
.prose ul li { list-style: disc; margin-top: 0.5em; }
.prose ol li { list-style: decimal; margin-top: 0.5em; }
.prose blockquote {
  border-inline-start: 3px solid var(--accent-500); padding: 0.35em 0 0.35em 1.35em;
  font-family: var(--font-display); font-size: var(--fs-lg); color: var(--text); font-style: italic;
}
.prose img, .prose figure { border-radius: var(--r-md); overflow: hidden; }
.prose figcaption { font-size: var(--fs-xs); color: var(--text-dim); margin-top: 0.6em; }
.prose code {
  font-family: var(--font-mono); font-size: 0.86em;
  padding: 0.15em 0.42em; border-radius: 5px;
  background: var(--surface-strong); color: var(--accent-400);
}
.prose pre {
  background: #050f22; border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 1.15rem; overflow-x: auto; font-size: var(--fs-sm);
}
.prose pre code { background: none; padding: 0; color: var(--text); }
.prose table { font-size: var(--fs-sm); }
.prose th, .prose td { padding: 0.65rem 0.85rem; border: 1px solid var(--line); }

.curriculum__module { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; margin-bottom: 0.75rem; }
.curriculum__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.15rem; background: var(--surface); cursor: pointer; width: 100%; text-align: left; }
.curriculum__lesson { display: flex; align-items: center; gap: 0.75rem; padding: 0.8rem 1.15rem; border-top: 1px solid var(--line); font-size: var(--fs-sm); color: var(--text-muted); }
.curriculum__lesson svg { width: 16px; height: 16px; color: var(--text-dim); flex-shrink: 0; }
.curriculum__lesson.is-preview { color: var(--text); }
.curriculum__lesson.is-preview svg { color: var(--accent-ink); }

/* ── Auth pages ─────────────────────────────────────────────────────── */
.auth {
  --auth-bar: 4.25rem;          /* the slim header, measured */
  min-height: 100dvh; display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  grid-template-rows: auto 1fr;
  background: var(--bg);
  align-items: start;
}
@media (max-width: 940px) { .auth { grid-template-columns: 1fr; } }

/* A slim bar across both columns. The full site nav would compete with the
   form for attention; this is the few places worth going from here, plus the
   theme switch, which people expect wherever they land. */
.auth__bar {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem);
  padding: 0.85rem clamp(1.25rem, 3vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  position: sticky; top: 0; z-index: 5;
}
.logo--sm .logo__mark { width: 32px; height: 27px; }
.logo--sm .logo__name { font-size: 0.92rem; }
.logo--sm .logo__tag { font-size: 0.48rem; }
.auth__nav { display: flex; gap: clamp(0.9rem, 2vw, 1.6rem); margin-inline-start: auto; }
.auth__nav a {
  font-size: var(--fs-sm); color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease-out);
}
.auth__nav a:hover { color: var(--text); }
.auth__bar-actions { display: flex; align-items: center; gap: 0.6rem; }
.auth__back {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: var(--fs-sm); color: var(--text-muted); white-space: nowrap;
}
.auth__back:hover { color: var(--text); }
.auth__back svg { width: 15px; height: 15px; }
@media (max-width: 720px) {
  .auth__nav { display: none; }
  .auth__back span { display: none; }
}

/* The form side. These five rules were lost when the panel was rewritten:
   the replacement anchored on the first `.auth__aside {` in the file, which
   is the one inside the media query above, and swallowed everything down to
   the next section - so every auth page rendered as unstyled blocks. */
.auth__main {
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1.5rem, 4vw, 3.5rem);
  min-height: calc(100dvh - var(--auth-bar));
}
.auth__card { width: min(100%, 500px); }
.auth__card--wide { width: min(100%, 700px); }
.auth__head { margin-bottom: var(--sp-6); }
.auth__head h1 { font-size: var(--fs-2xl); margin-top: var(--sp-3); }
.auth__foot {
  margin-top: var(--sp-6); padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm); color: var(--text-muted); text-align: center;
}
.auth__foot a { color: var(--accent-ink); font-weight: 600; }

.auth__aside {
  /* Sticky and its own natural height, with a floor of one screen.
     A fixed height forced the body to become a nested scroll area, and a
     268px scroller inside a sticky panel is a trap: the wheel does
     something different there from the rest of the page, with nothing to
     say so, and the last block was reachable only by finding it. The panel
     now grows to fit whatever it holds and the page scrolls normally. */
  align-self: start;
  min-height: calc(100dvh - var(--auth-bar));
  overflow: hidden;
  /* One surface, not three washes. The old panel stacked a blue radial, an
     amber radial and a diagonal gradient - the mesh that every generated
     page has. A single deep field with a ruled overlay reads as a made
     thing, and it is the same texture the rest of the site uses. */
  background: var(--brand-900);
  /* A column, not a three-row grid. The rows put slack above AND below the
     middle block, which read as two voids; a column with the legal strip
     pushed to the bottom leaves one deliberate gap instead. */
  display: flex; flex-direction: column;
  gap: clamp(1.1rem, 2.2vw, 1.8rem);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  border-inline-start: 1px solid var(--line);
  /* This panel paints its own deep navy regardless of theme, so its text
     cannot inherit --text: on the light theme that is navy on navy. */
  color: #eef4ff;
}
/* The ruling, and one warm source low on the left. Static: a sign-in page is
   not the place for something to be moving in the corner of the eye. */
.auth__rules {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px),
    radial-gradient(70% 55% at 12% 88%, rgba(242,178,51,.16), transparent 68%);
  background-size: 46px 46px, 46px 46px, 100% 100%;
  mask-image: radial-gradient(120% 90% at 50% 30%, #000 35%, transparent 88%);
}
.auth__aside > *:not(.auth__rules):not(.auth__watermark) { position: relative; z-index: 1; }

/* The mark, very large and very faint, anchoring the foot of the panel.
   This is what the globe was for — but it is one inline SVG that cannot
   fail to render, rather than a WebGL context that did. */
.auth__watermark {
  position: absolute;
  right: -14%; bottom: -8%;
  width: 78%; height: auto;
  color: #eef4ff;
  opacity: 0.05;
  pointer-events: none;
}

.auth__aside .eyebrow { color: var(--accent-500); }
.auth__aside h2 {
  font-size: clamp(1.5rem, 2.1vw, 2rem);
  line-height: 1.15; max-width: 17ch; color: #eef4ff;
}
.auth__lede {
  margin-top: var(--sp-4); max-width: 40ch;
  font-size: var(--fs-sm); line-height: 1.55;
  color: rgba(238, 244, 255, 0.72);
}
.auth__aside-body {
  /* Spreads the slack between its own blocks when there is slack, and
     simply flows when there is not. No overflow of its own — everything
     here has to be reachable by scrolling the page. */
  flex: 1 1 auto;
  display: grid; gap: clamp(1rem, 2vw, 1.5rem);
  align-content: space-evenly;
}
/* Everything above flows from the top; the legal strip is pinned to the
   bottom, so the slack collects in one place rather than two. */
.auth__aside-foot { margin-top: auto; }

/* Sticky only where the panel actually fits the screen. A sticky element
   taller than its slot pins at the top and its own bottom never comes into
   view however far you scroll — at 640px that left the legal strip
   permanently out of reach. Below this height it scrolls with the page. */
@media (min-height: 860px) {
  .auth__aside { position: sticky; top: var(--auth-bar); }
}

/* ── Numbers ────────────────────────────────────────────────────────────
   Three counts, and only ones that are true - they come out of the tables,
   so an empty install shows nothing rather than an invented figure. */
.auth__stats { display: flex; flex-wrap: wrap; gap: clamp(1.25rem, 3vw, 2.25rem); }
.auth__stat { display: grid; gap: 0.15rem; }
.auth__stat-n {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.5rem, 2.4vw, 2.1rem); line-height: 1;
  color: var(--accent-500); font-variant-numeric: tabular-nums;
}
.auth__stat-l { font-size: var(--fs-2xs); color: rgba(238,244,255,.6); max-width: 14ch; line-height: 1.35; }

/* ── Real records ───────────────────────────────────────────────────── */
.auth__label {
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  letter-spacing: 0.18em; text-transform: uppercase;
  color: rgba(238,244,255,.45); margin-bottom: 0.7rem;
}
.auth__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.6rem; }
.auth__item {
  position: relative; display: grid; gap: 0.15rem;
  padding-inline-end: 1.9rem;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
  padding: 0.75rem 0.95rem;
  border-radius: var(--r-sm);
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.08);
  border-inline-start: 2px solid var(--accent-500);
}
.auth__item:hover, .auth__item:focus-visible {
  background: rgba(255,255,255,.09); border-color: rgba(255,255,255,.16);
}
.auth__item:focus { outline: none; }
.auth__item-title { font-size: var(--fs-sm); font-weight: 600; color: #eef4ff; }
.auth__item-meta { font-size: var(--fs-2xs); color: rgba(238,244,255,.55); }

/* ── The engagement, as numbered steps ──────────────────────────────── */
.auth__steps { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.85rem; }
.auth__steps li {
  display: flex; gap: 0.8rem; align-items: center;
  font-size: var(--fs-sm); color: rgba(238,244,255,.82);
}
.auth__steps span {
  flex-shrink: 0; width: 1.6rem; height: 1.6rem; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(242,178,51,.15); border: 1px solid rgba(242,178,51,.4);
  color: var(--accent-500);
  font-family: var(--font-mono); font-size: 0.62rem; font-weight: 600;
}

/* ── One voice, not a wall ──────────────────────────────────────────── */
/* The quotation marks are escapes, not literal letters. They were written
   as raw characters once and survived an encoding round trip as a stray
   control byte plus "C" and "D" - which is exactly what the panel showed
   around the quote. */
.auth__quote {
  margin: 0; padding-left: 0.9rem;
  border-left: 2px solid rgba(242, 178, 51, 0.5);
}
.auth__quote blockquote {
  margin: 0; font-size: var(--fs-sm); line-height: 1.6;
  color: rgba(238, 244, 255, 0.86); border: 0; padding: 0;
  /* Long testimonials would otherwise push the legal links off the
     panel; four lines is plenty for a sign-in page. */
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}
.auth__quote blockquote::before { content: "\201C"; }
.auth__quote blockquote::after { content: "\201D"; }
.auth__quote figcaption {
  margin-top: 0.55rem; font-size: var(--fs-2xs); letter-spacing: 0.04em;
  color: rgba(238, 244, 255, 0.58);
}
/* ── The globe ──────────────────────────────────────────────────────────
   Half of it, sunk into the foot of the panel. A whole globe floating in
   the middle would be an ornament; a half one anchored to the bottom edge
   reads as the ground the panel stands on, and leaves the copy the top.

   The colours are handed to cobe through these three custom properties, so
   the palette lives with the rest of the stylesheet instead of in the
   script — the globe is drawn in WebGL and cannot inherit anything.
   ──────────────────────────────────────────────────────────────────── */
/* ── Links out ──────────────────────────────────────────────────────── */
.auth__block { display: grid; gap: 0.5rem; }
.auth__more {
  justify-self: start; font-size: var(--fs-2xs); font-weight: 600;
  color: var(--accent-500);
}
.auth__more:hover { text-decoration: underline; text-underline-offset: 3px; }
.auth__item-go {
  position: absolute; inset-inline-end: 0.7rem; top: 50%;
  transform: translateY(-50%) translateX(-4px);
  color: var(--accent-500); opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur) var(--ease-out);
}
.auth__item:hover .auth__item-go,
.auth__item:focus-visible .auth__item-go { opacity: 1; transform: translateY(-50%) translateX(0); }

.auth__legal {
  display: flex; flex-wrap: wrap; gap: 0.9rem;
  padding-top: 0.9rem; border-top: 1px solid rgba(255,255,255,.1);
}
.auth__legal a { font-size: var(--fs-2xs); color: rgba(238,244,255,.55); }
.auth__legal a:hover { color: #eef4ff; text-decoration: underline; text-underline-offset: 3px; }

.auth__aside-foot .tiny { color: rgba(238,244,255,.5); }

/* Below the split the form is the whole page. The hide has to come after the
   block above, not before it: `display: grid` on .auth__aside was declared
   later in the file and won at every width, so the panel was still stacking
   under the form on a phone. */
@media (max-width: 940px) {
  .auth__aside { display: none; }
}

.role-picker { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
.role-card {
  display: flex; flex-direction: column; gap: 0.65rem;
  padding: 1.75rem 1.5rem; border-radius: var(--r-lg);
  border: 1px solid var(--line); background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.role-card:hover { border-color: var(--accent-500); box-shadow: var(--shadow-glow); }
@media (hover: hover) and (pointer: fine) {
  .role-card:hover { transform: translateY(-4px); }
}
.role-card__icon { width: 48px; height: 48px; border-radius: var(--r-sm); display: grid; place-items: center; background: var(--surface-strong); color: var(--accent-ink); }
.role-card__icon svg { width: 24px; height: 24px; }

.turnstile-holder { display: flex; justify-content: center; margin-block: var(--sp-4); min-height: 65px; }

/* ── Contact ────────────────────────────────────────────────────────── */
.contact-layout { display: grid; gap: clamp(2rem, 4vw, 3.5rem); grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); align-items: start; }
@media (max-width: 900px) { .contact-layout { grid-template-columns: 1fr; } }
.contact-item { display: flex; gap: 1rem; align-items: flex-start; padding: 1.1rem 0; border-bottom: 1px solid var(--line); }
.contact-item:last-child { border-bottom: 0; }
.contact-item__icon { flex-shrink: 0; width: 42px; height: 42px; border-radius: var(--r-sm); display: grid; place-items: center; background: var(--surface-strong); color: var(--accent-ink); }
.contact-item__icon svg { width: 19px; height: 19px; }
.contact-item h4 { font-size: var(--fs-sm); margin-bottom: 0.2rem; }
.contact-item p, .contact-item a { font-size: var(--fs-sm); color: var(--text-muted); }
.contact-item a:hover { color: var(--accent-ink); }

.map-embed { border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); aspect-ratio: 16 / 10; background: var(--surface); }
.map-embed iframe { width: 100%; height: 100%; border: 0; filter: grayscale(.25) contrast(1.05); }

/* ── Blog ───────────────────────────────────────────────────────────── */
.post-hero { display: grid; gap: var(--sp-6); }
.post-hero__meta { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; font-size: var(--fs-xs); color: var(--text-dim); }
.post-cover { border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--line); }
.post-cover img { width: 100%; aspect-ratio: 16/8; object-fit: cover; }

.featured-post {
  display: grid; gap: 0; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  background: var(--surface); margin-bottom: var(--sp-7);
}
@media (max-width: 820px) { .featured-post { grid-template-columns: 1fr; } }
.featured-post__media { aspect-ratio: 16/10; background: var(--grad-brand); overflow: hidden; }
.featured-post__media img { width: 100%; height: 100%; object-fit: cover; }
.featured-post__body { padding: clamp(1.5rem, 3vw, 2.75rem); display: flex; flex-direction: column; justify-content: center; }
.featured-post h2 { font-size: var(--fs-2xl); margin-block: 0.6rem 0.9rem; }

/* ── Comments ────────────────────────────────────────────────────────
   Each comment is a panel rather than a row divided by a hairline. A
   conversation has authorship and nesting; a flat list of bordered rows
   gave the eye nothing to attach either to, so a reply three levels down
   looked exactly like a new top-level remark. */
.comment { display: flex; gap: 0.8rem; padding: 0 0 0.9rem; }
.comment__body {
  flex: 1; min-width: 0;
  padding: 0.85rem 1rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.comment:hover > .comment__body { border-color: var(--line-strong); }
.comment__head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.5rem; margin-bottom: 0.3rem;
}
.comment__name { font-weight: 600; font-size: var(--fs-sm); color: var(--text); }
.comment__time { font-size: var(--fs-2xs); color: var(--text-dim); }
.comment__text {
  font-size: var(--fs-sm); line-height: 1.6; color: var(--text-muted);
  overflow-wrap: break-word;
}
.comment__actions {
  display: flex; flex-wrap: wrap; gap: 0.25rem 0.9rem;
  margin-top: 0.5rem; font-size: var(--fs-2xs);
}
.comment__actions button {
  color: var(--text-dim); display: inline-flex; align-items: center;
  gap: 0.3rem; transition: color var(--dur-fast) var(--ease-out);
}
.comment__actions button:hover, .comment__actions button.is-liked { color: var(--accent-ink); }
.comment__actions svg { width: 13px; height: 13px; }

/* A staff answer is the comment a reader scanning the thread is looking
   for, so it is the one that does not look like the others. */
.comment--staff > .comment__body {
  border-color: var(--line-accent);
  background: color-mix(in srgb, var(--accent-500) 5%, var(--surface));
}

/* Nesting hangs off a rule rather than relying on indent alone — at three
   levels the indent by itself had pushed the text off a phone. */
.comment__replies {
  margin-inline-start: 1.35rem;
  border-inline-start: 1px solid var(--line);
  padding-inline-start: 1rem;
  margin-block-start: 0.15rem;
}
@media (max-width: 560px) {
  .comment__replies { margin-inline-start: 0.5rem; padding-inline-start: 0.7rem; }
  .comment__body { padding: 0.75rem 0.85rem 0.7rem; }
}

.share-row { display: flex; gap: 0.5rem; align-items: center; }

/* ── Checkout ───────────────────────────────────────────────────────── */
.pay-option {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1.25rem; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.pay-option:hover { border-color: var(--line-strong); }
.pay-option:has(input:checked) { border-color: var(--accent-500); background: rgba(242,178,51,.07); box-shadow: var(--shadow-glow); }
.pay-option__amount { margin-inline-start: auto; font-family: var(--font-display); font-size: var(--fs-lg); font-weight: 700; }

.receipt { max-width: 640px; margin-inline: auto; }
.receipt__row { display: flex; justify-content: space-between; gap: 1rem; padding: 0.7rem 0; border-bottom: 1px dashed var(--line); font-size: var(--fs-sm); }
.receipt__row b { font-family: var(--font-mono); }

/* ── Public portfolio / case studies ───────────────────────────────── */
.portfolio-hero { padding-block: clamp(2.5rem, 5vw, 4.5rem); }
.portfolio-hero__layout {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(250px, .55fr);
  align-items: end; gap: clamp(2rem, 6vw, 6rem);
}
.portfolio-hero .page-hero__copy { max-width: 760px; margin-inline: 0; text-align: left; }
.portfolio-hero h1 { max-width: 16ch; margin-top: var(--sp-3); }
.portfolio-proof {
  padding: clamp(1.25rem, 2.5vw, 2rem);
  border: 1px solid rgba(255,255,255,.14); border-radius: 2px;
  background: var(--brand-900); color: #eef4ff;
}
.portfolio-proof__label {
  display: block; padding-bottom: .85rem; border-bottom: 1px solid rgba(255,255,255,.14);
  color: rgba(238,244,255,.58); font: 600 var(--fs-2xs)/1.3 var(--font-mono);
  letter-spacing: .14em; text-transform: uppercase;
}
.portfolio-proof > strong { display: block; margin-top: 1rem; color: var(--accent-500); font: 700 clamp(2.8rem, 6vw, 4.7rem)/.9 var(--font-display); }
.portfolio-proof > p { margin-top: .4rem; color: rgba(238,244,255,.7); font-size: var(--fs-sm); }
.portfolio-proof ul { display: grid; gap: .55rem; margin-top: 1.35rem; padding-top: 1rem; border-top: 1px solid rgba(255,255,255,.14); }
.portfolio-proof li { display: flex; align-items: center; gap: .55rem; color: rgba(238,244,255,.78); font-size: var(--fs-xs); }
.portfolio-proof li svg { color: var(--accent-500); }
.projects-intro {
  display: flex; align-items: end; justify-content: space-between; gap: 1.5rem;
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem); padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.projects-intro h2 { margin-top: .35rem; }
.projects-intro > p { max-width: 45ch; color: var(--text-muted); font-size: var(--fs-sm); }
.projects-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch; gap: clamp(.85rem, 1.5vw, 1.25rem);
}
.projects-grid--home { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: clamp(1rem, 1.6vw, 1.5rem); }
.ed--project { min-width: 0; min-height: 100%; }
.ed--project .ed__kicker, .ed--project .ed__title { padding-inline-end: 0; }
.ed--project .ed__title { font-size: clamp(1.15rem, 1.6vw, 1.45rem); line-height: 1.08; }
.ed--project .ed__body { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.ed--project .ed__media { aspect-ratio: 16 / 9; }
.ed--project .ed__flag { background: var(--brand-900); color: #fff; }
.portfolio-tags { display: flex; flex-wrap: wrap; gap: .45rem; }
.portfolio-tags span { padding: .3rem .55rem; border: 1px solid var(--line); border-radius: 999px; color: var(--text-muted); font: 500 var(--fs-2xs)/1.2 var(--font-mono); }
.case-study__hero { padding-block: clamp(2.25rem, 5vw, 4.5rem); }
.case-study__hero-layout { position: relative; z-index: 1; display: grid; grid-template-columns: minmax(0,.9fr) minmax(360px,1.1fr); align-items: center; gap: clamp(2rem,5vw,5rem); }
.case-study__hero-copy h1 { max-width: 13ch; margin-top: var(--sp-3); font-size: clamp(2.5rem, 5.5vw, 5rem); }
.case-study__hero-copy .lede { max-width: 52ch; }
.case-study__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: var(--sp-6); }
.case-study__visual { display: grid; place-items: center; aspect-ratio: 16/10; overflow: hidden; border: 1px solid var(--line-strong); border-radius: 2px; background: var(--surface); box-shadow: 22px 22px 0 color-mix(in srgb, var(--brand-500) 12%, transparent); }
.case-study__visual img { width: 100%; height: 100%; object-fit: cover; }
.case-study__visual > span { color: var(--text-dim); }
.case-study__facts-wrap { border-block: 1px solid var(--line); background: var(--bg-alt); }
.case-study__facts { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); }
.case-study__facts > div { display: grid; gap: .35rem; min-width: 0; padding: 1.25rem clamp(.9rem,2vw,1.5rem); border-inline-start: 1px solid var(--line); }
.case-study__facts > div:last-child { border-inline-end: 1px solid var(--line); }
.case-study__facts small { color: var(--text-dim); font: 600 var(--fs-2xs)/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase; }
.case-study__facts strong { overflow-wrap: anywhere; font-size: var(--fs-sm); }
.case-study__narrative .section-head { max-width: 680px; }
.case-study__story { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); border-top: 1px solid var(--line); }
.case-study__story section { position: relative; display: grid; align-content: start; gap: .85rem; padding: clamp(1.25rem,3vw,2.25rem); border-inline-end: 1px solid var(--line); }
.case-study__story section:first-child { border-inline-start: 1px solid var(--line); }
.case-study__story h3 { font-size: clamp(1.2rem,1.7vw,1.55rem); }
.case-study__story .prose { font-size: var(--fs-sm); line-height: 1.68; }
.case-study__step { color: var(--line-strong); font: 700 clamp(2rem,4vw,3.5rem)/1 var(--font-display); }
.case-study__outcome { background: color-mix(in srgb, var(--accent-500) 7%, var(--bg)); }
.case-study__stack { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; padding-block: var(--sp-5); border-block: 1px solid var(--line); }
.case-study__gallery { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
.case-study__gallery figure { overflow: hidden; border: 1px solid var(--line); border-radius: 2px; background: var(--surface); }
.case-study__gallery img { display: block; width: 100%; height: auto; }
.case-study__gallery figcaption { padding: .75rem 1rem; color: var(--text-muted); font-size: var(--fs-xs); }
.case-study__cta { display: flex; align-items: center; justify-content: space-between; gap: 2rem; padding: clamp(1.5rem,4vw,3rem); border: 1px solid var(--line-strong); border-radius: 2px; background: var(--brand-900); color: #eef4ff; }
.case-study__cta h2 { max-width: 18ch; margin-top: .45rem; color: #fff; }
.case-study__cta p { max-width: 48ch; margin-top: .65rem; color: rgba(238,244,255,.68); }
.case-study__cta .eyebrow { color: var(--accent-500); }

/* Admin projects: compact rows preserve context and keep controls visible. */
.portfolio-admin-stats { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: .75rem; margin-bottom: var(--sp-5); }
.portfolio-admin-stats > div { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 1rem 1.15rem; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.portfolio-admin-stats span { color: var(--text-dim); font: 600 var(--fs-2xs)/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
.portfolio-admin-stats strong { font: 700 1.5rem/1 var(--font-display); }
.portfolio-admin-list__head, .portfolio-admin-row { display: grid; grid-template-columns: minmax(320px,1fr) 130px 120px 150px; gap: 1rem; align-items: center; }
.portfolio-admin-list__head { padding: .75rem 1rem; border-bottom: 1px solid var(--line); color: var(--text-dim); font: 600 var(--fs-2xs)/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
.portfolio-admin-row { padding: .85rem 1rem; border-bottom: 1px solid var(--line); }
.portfolio-admin-row:last-child { border-bottom: 0; }
.portfolio-admin-row__main { display: grid; grid-template-columns: 138px minmax(0,1fr); column-gap: 1rem; align-items: center; min-width: 0; }
.portfolio-admin-row__copy { display: grid; gap: .25rem; min-width: 0; }
.portfolio-admin-row__copy h3 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-md); }
.portfolio-admin-row__copy p { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); font-size: var(--fs-xs); }
.portfolio-admin-card__media { display: grid; place-items: center; width: 138px; aspect-ratio: 16/10; overflow: hidden; background: var(--surface-2); color: var(--text-dim); border: 1px solid var(--line); border-radius: var(--r-xs); }
.portfolio-admin-card__media img { width: 100%; height: 100%; object-fit: cover; }
.portfolio-admin-row__status { display: flex; flex-direction: column; align-items: flex-start; gap: .4rem; }
.portfolio-admin-row__proof { display: grid; gap: .2rem; }
.portfolio-admin-row__proof strong { font: 700 1.25rem/1 var(--font-display); }
.portfolio-admin-row__proof span, .portfolio-admin-row__proof a { color: var(--text-dim); font-size: var(--fs-2xs); }
.portfolio-admin-row__proof a { display: inline-flex; align-items: center; gap: .25rem; color: var(--accent-ink); }
.portfolio-admin-row__actions { display: flex; justify-content: flex-end; gap: .45rem; }
.portfolio-form-section .panel-card__head > div { display: grid; grid-template-columns: auto 1fr; gap: .25rem .65rem; align-items: center; }
.portfolio-form-section .panel-card__head p { grid-column: 2; color: var(--text-dim); font-size: var(--fs-xs); }
.portfolio-form-step { grid-row: 1/3; color: var(--accent-ink); font: 700 1.35rem/1 var(--font-display); }
.portfolio-form-cover-wrap { margin-bottom: 1rem; }
.portfolio-form-cover-wrap > span { display: block; margin-bottom: .5rem; color: var(--text-dim); font: 600 var(--fs-2xs)/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
.portfolio-form-cover { display: block; width: 100%; max-height: 300px; object-fit: cover; border-radius: var(--r-xs); border: 1px solid var(--line); }
.portfolio-gallery-admin { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; padding: 1rem; }
.portfolio-gallery-admin figure { display: grid; gap: .6rem; align-content: start; }
.portfolio-gallery-admin img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--line); }
@media (max-width: 1100px) {
  .projects-grid { grid-template-columns: repeat(2,minmax(0,1fr)); }
  .portfolio-admin-list__head { display: none; }
  .portfolio-admin-row { grid-template-columns: minmax(0,1fr) auto; }
  .portfolio-admin-row__main { grid-column: 1/-1; }
  .portfolio-admin-row__proof { display: none; }
}
@media (max-width: 900px) {
  .portfolio-hero__layout, .case-study__hero-layout { grid-template-columns: 1fr; }
  .portfolio-proof { max-width: 520px; }
  .case-study__visual { max-width: 760px; }
  .case-study__facts { grid-template-columns: repeat(2,minmax(0,1fr)); }
  .case-study__story { grid-template-columns: 1fr; border-bottom: 1px solid var(--line); }
  .case-study__story section, .case-study__story section:first-child { border-inline: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  .case-study__story section:last-child { border-bottom: 0; }
  .portfolio-admin-stats { grid-template-columns: repeat(2,minmax(0,1fr)); }
  .portfolio-gallery-admin { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .projects-intro { display: grid; align-items: start; }
  .projects-grid, .projects-grid--home, .case-study__gallery, .portfolio-gallery-admin { grid-template-columns: 1fr; }
  .portfolio-hero h1 { font-size: clamp(2.15rem,11vw,3.15rem); }
  .portfolio-proof { display: none; }
  .case-study__visual { box-shadow: 10px 10px 0 color-mix(in srgb, var(--brand-500) 12%, transparent); }
  .case-study__facts { grid-template-columns: 1fr 1fr; }
  .case-study__facts > div { border-bottom: 1px solid var(--line); }
  .case-study__cta { align-items: start; flex-direction: column; }
  .case-study__cta .btn { width: 100%; }
  .portfolio-admin-stats { gap: .5rem; }
  .portfolio-admin-stats > div { padding: .8rem; }
  .portfolio-admin-row { grid-template-columns: 1fr; }
  .portfolio-admin-row__main { grid-template-columns: 96px minmax(0,1fr); }
  .portfolio-admin-card__media { width: 96px; }
  .portfolio-admin-row__actions { justify-content: flex-start; }
}

/* ── Error page ─────────────────────────────────────────────────────── */
.error-page { min-height: 78dvh; display: grid; place-items: center; text-align: center; padding: var(--sp-8) 0; }
.error-code {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(6rem, 22vw, 15rem); line-height: 0.85; letter-spacing: -0.05em;
  background: var(--grad-brand); -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ── Empty state ────────────────────────────────────────────────────── */
.empty {
  text-align: center; padding: clamp(2.5rem, 6vw, 4.5rem) 1.5rem;
  border: 1px dashed var(--line-strong); border-radius: var(--r-lg);
  color: var(--text-muted);
}
.empty__icon { width: 56px; height: 56px; margin: 0 auto var(--sp-4); color: var(--text-dim); }

/* ── Content protection (course material) ───────────────────────────── */
.protected {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  position: relative;
}
/* Images only. `pointer-events: none` on the video was the cause of "it is
   playing but it says the video is protected": every click passed straight
   through the player to the protected container, which answered with the
   warning toast. The player needs its own clicks. */
.protected img { pointer-events: none; -webkit-user-drag: none; }
.protected video { -webkit-user-drag: none; }
.protected::after {
  content: attr(data-watermark);
  position: absolute; inset: 0; z-index: 5; pointer-events: none;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 0.85rem; letter-spacing: .2em;
  color: rgba(255, 255, 255, 0.055); text-transform: uppercase;
  background-image: repeating-linear-gradient(-32deg, transparent, transparent 130px, rgba(255,255,255,.014) 130px, rgba(255,255,255,.014) 260px);
}
.video-shell { position: relative; border-radius: var(--r-md); overflow: hidden; background: #000; aspect-ratio: 16/9; }
.video-shell video { width: 100%; height: 100%; }
.video-guard { position: absolute; inset: 0; z-index: 4; pointer-events: none; }


/* An embedded provider supplies its own player, so the shell just holds the
   aspect ratio and the rounded corner. */
.video-shell--embed { position: relative; aspect-ratio: 16 / 9; }
.video-shell--embed iframe {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; border-radius: inherit;
}

/* ══════════════════════════════════════════════════════════════════════
   HERO SCENE
   The inner pages open with copy ranged left and the right half empty.

   The scene is DOM layers in a perspective container, not a flat picture:
   every figure sits at its own translateZ, so turning the stage separates
   them - the front row swings wider than the back and the board holds
   still behind. That is the whole reason it is not a Lottie; a single
   rendered image has no depth to reveal.
   ══════════════════════════════════════════════════════════════════════ */
.page-hero--split > .container {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: center;
}
.page-hero--split { padding-block: clamp(1.25rem, 2.4vw, 2.25rem) clamp(1.75rem, 3.5vw, 3rem); }

.scene3d { display: none; }

@media (min-width: 981px) {
  .page-hero--split > .container {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
    gap: clamp(1.25rem, 3vw, 2.5rem);
  }
  /* Copy at the top, art centred against it. Centring both let the taller
     art push the breadcrumb most of a hundred pixels down the page. */
  .page-hero--split .page-hero__copy { align-self: start; }
  .page-hero--split .scene3d { align-self: center; }

  /* A resting turn, so the scene reads as dimensional before anyone
     touches it. Dead-on, depth is invisible: every layer projects to the
     same place and the whole point of the construction is hidden until the
     pointer arrives. Each scene gets the angle its composition wants. */
  /* --turn-limit is how far a drag may go, per scene. All four sit at 32
     today, but the hook stays: a composition that cannot take the full turn
     should say so here rather than have the limit lowered for everyone. */
  /* The vertical limit is deliberately much tighter. Turning a scene left
     and right is the useful gesture; tipping it up and down mostly finds the
     edges of the frame, and every overflow measured across the drag range
     came from the vertical axis. */
  .scene3d { --rest-x: -3deg; --rest-y: 7deg; --turn-limit: 32; --turn-limit-x: 16; }
  .scene3d--stack { --rest-x: -4deg; --rest-y: 9deg;  --turn-limit: 32; }
  .scene3d--path  { --rest-x: -6deg; --rest-y: -8deg; --turn-limit: 32; }
  .scene3d--book  { --rest-x: -4deg; --rest-y: 12deg; --turn-limit: 32; }

  .scene3d {
    display: block;
    position: relative;
    width: 100%;
    /* Sized to the copy, not to the column. At 620x533 the scene stood
       199px taller than the 335px of text beside it, so the picture — not
       the content — was setting the height of the whole section. A wider,
       shorter frame suits both scenes anyway: an arc of people and a
       cascade of panels are both horizontal arrangements. */
    max-width: 520px;
    aspect-ratio: 1 / 0.68;
    margin-inline-start: auto;
    perspective: 1150px;
    perspective-origin: 50% 42%;
    cursor: grab;
    touch-action: pan-y;          /* let the page still scroll under a drag */
  }
  .scene3d.is-turning { cursor: grabbing; }
  .scene3d__stage {
    position: absolute; inset: 0;
    transform-style: preserve-3d;
    transform: rotateX(var(--rx, var(--rest-x))) rotateY(var(--ry, var(--rest-y)));
    will-change: transform;
  }
  /* The spring back is a transition; the drag itself is not, or it lags
     the cursor by its own duration. */
  .scene3d.is-settling .scene3d__stage {
    transition: transform 620ms var(--ease-out);
  }

  /* ── A thing in the scene ──────────────────────────────────────────
     Positioned by its centre in percentages so it scales with the stage,
     then pushed to its own depth. */
  .s3 {
    position: absolute;
    left: var(--x); top: var(--y);
    transform: translate(-50%, -50%) translateZ(var(--z)) scale(var(--s, 1));
    transform-style: preserve-3d;
    border: 0; padding: 0; background: none;
    -webkit-tap-highlight-color: transparent;
  }
  .s3 svg { display: block; overflow: visible; }
  button.s3 { cursor: pointer; }

  /* Sized as a share of the stage, not in pixels, so every figure keeps its
     proportion when the frame changes. At fixed px they grew relative to the
     scene each time it was made smaller. */
  .s3--seat { width: 10%; }
  .s3--remote { width: 14.5%; }
  .s3--board { width: 60%; }
  .s3--panel { width: 41%; }
  .s3 > svg { width: 100%; height: auto; }

  .s3__shadow { fill: var(--text); opacity: 0.1; }
  .s3__head, .s3__body { fill: var(--mark-navy); }
  .s3--blue .s3__head, .s3--blue .s3__body { fill: var(--mark-blue); }
  .s3--lead .s3__head, .s3--lead .s3__body { fill: var(--accent-500); }
  .s3--remote .s3__card { fill: none; stroke: var(--mark-blue); stroke-width: 3; }
  .s3--remote .s3__head, .s3--remote .s3__body { fill: var(--mark-blue); }
  .s3--remote .s3__live { fill: var(--accent-500); }

  .s3__frame { fill: var(--mark-navy); }
  .s3__panel { fill: var(--surface-solid); }

  /* ── Panels: one discipline per plane ──────────────────────────────
     Head on they overlap into a single composition; turned, they fan out.
     The shadow deepens with depth, which is what stops three flat cards at
     three distances reading as three flat cards. */
  .s3-panel {
    display: block;
    padding: 0.75rem 0.85rem 0.9rem;
    border-radius: var(--r-md, 14px);
    background: var(--surface-solid);
    border: 1px solid var(--line);
    box-shadow: 0 18px 44px rgba(11, 31, 68, 0.16);
    text-align: start;
  }
  .s3--panel[style*="--z:-140px"] .s3-panel { box-shadow: 0 8px 20px rgba(11, 31, 68, 0.10); }
  .s3--panel[style*="--z:140px"] .s3-panel { box-shadow: 0 26px 60px rgba(11, 31, 68, 0.22); }
  .s3-panel__bar {
    display: block; width: 2.2rem; height: 4px; border-radius: 2px;
    background: var(--accent-500); margin-bottom: 0.6rem;
  }
  .s3-panel__art { width: 100%; height: auto; display: block; }
  .s3-panel__label {
    display: block; margin-top: 0.55rem;
    font-family: var(--font-display); font-weight: 600;
    font-size: clamp(0.72rem, 1.1vw, 0.92rem);
    letter-spacing: 0.02em; color: var(--text);
  }

  /* The ground the stack sits over - a faint plane, far back, so the depth
     has something to be measured against. */
  .s3--floor {
    width: 92%; height: 62%;
    border-radius: 50%;
    background: radial-gradient(ellipse at center,
                color-mix(in srgb, var(--mark-blue) 12%, transparent), transparent 68%);
  }

  .c-frame { fill: none; stroke: var(--line-strong); stroke-width: 2; }
  .c-bar { fill: var(--mark-blue); opacity: 0.65; }
  .c-bar--hot { fill: var(--accent-500); opacity: 1; }
  .c-block { fill: var(--mark-blue); opacity: 0.22; }
  .c-swatch rect { fill: var(--mark-blue); opacity: 0.5; }
  .c-swatch rect:nth-child(2) { fill: var(--accent-500); opacity: 0.9; }
  .c-swatch rect:nth-child(3) { fill: var(--mark-navy); opacity: 0.35; }
  .c-axis { stroke: var(--line-strong); stroke-width: 2; }
  .c-col rect { fill: var(--mark-blue); opacity: 0.28; }

  /* ── Stations: the engagement as a path ────────────────────────────
     Four stages at four distances. The ground is a real element laid flat
     with rotateX — without a plane to stand on, four cards at four depths
     read as four cards at four sizes. */
  .s3--ground {
    width: 118%; height: 78%;
    transform: translate(-50%, -50%) rotateX(74deg) translateZ(var(--z));
    background:
      linear-gradient(to bottom,
        color-mix(in srgb, var(--mark-blue) 16%, transparent),
        transparent 72%),
      repeating-linear-gradient(to right,
        color-mix(in srgb, var(--mark-blue) 14%, transparent) 0 1px,
        transparent 1px 46px);
    border-radius: 40% 40% 12% 12% / 26% 26% 8% 8%;
    mask-image: radial-gradient(70% 78% at 50% 42%, #000 40%, transparent 84%);
  }

  .s3--station { width: 22%; }
  .s3-stn {
    display: block; position: relative;
    padding: 0.5rem 0.55rem 0.6rem;
    border-radius: var(--r-sm, 10px);
    background: var(--surface-solid);
    border: 1px solid var(--line);
    box-shadow: 0 14px 32px rgba(11, 31, 68, 0.15);
    text-align: center;
  }
  .s3-stn__num {
    position: absolute; top: -0.55rem; inset-inline-start: -0.45rem;
    width: 1.35rem; height: 1.35rem; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--accent-500); color: #0b1f44;
    font-family: var(--font-mono); font-size: 0.6rem; font-weight: 600;
  }
  .s3-stn__art { width: 100%; height: auto; display: block; }
  .s3-stn__label {
    display: block; margin-top: 0.3rem;
    font-family: var(--font-display); font-weight: 600;
    font-size: clamp(0.56rem, 0.85vw, 0.72rem);
    line-height: 1.2; color: var(--text);
  }

  .t-sheet { fill: none; stroke: var(--line-strong); stroke-width: 2.5; }
  .t-row { fill: var(--mark-blue); opacity: 0.55; }
  .t-row--hot { fill: var(--accent-500); opacity: 1; }
  .t-tick { fill: none; stroke: var(--accent-500); stroke-width: 3.5;
            stroke-linecap: round; stroke-linejoin: round; }
  .t-tick--stamp { stroke: var(--surface-solid); }
  .t-total { fill: var(--mark-navy); opacity: 0.85; }
  .t-stamp { fill: var(--accent-500); }
  .t-bar { fill: var(--mark-blue); opacity: 0.2; }
  .t-bar--fill { fill: var(--accent-500); transform-origin: 20px 0;
                 animation: t-progress 6s var(--ease-in-out) infinite; }
  @keyframes t-progress { 0%, 8% { transform: scaleX(0.1); } 55%, 100% { transform: scaleX(1); } }

  /* ── The book ──────────────────────────────────────────────────────
     Sheets hinged at a spine. Each is two-sided, which nothing else here
     is: the front and back are separate faces, the back pre-rotated 180
     degrees, and both hidden from behind so only one paints at a time.

     They all sit at the same place and are ordered by --n; the spine is
     the transform-origin, so rotateY swings them like real pages. */
  .s3--sheet {
    left: 31%; top: 50%;
    width: 34%;
    /* Depth expressed as --z like every other piece, rather than as its own
       transform. The shared hover rule ends with translateZ(var(--z)), and a
       var() that resolves to nothing is invalid at computed-value time - it
       does not fall back to the previous rule, it unsets the property. With
       no --z here the sheets computed `transform: none` and sat in a heap. */
    --z: calc(var(--n) * -6px);
    transform-style: preserve-3d;
  }
  .pg {
    display: block; position: relative;
    transform-origin: left center;
    transform-style: preserve-3d;
    animation: pg-turn 20s var(--ease-in-out) infinite;
    /* -16s, not -4s. A negative delay runs the cycle FORWARD, so at -4s the
       second sheet fired 4s early - i.e. last - and the book turned its top
       page, then the one at the back. -16s is +4s on a 20s loop, which puts
       them in order. */
    animation-delay: calc(var(--n) * -16s);
  }
  /* The turn, then a reset that happens while the sheet is invisible - a
     book that visibly snapped back to the start would break the illusion
     the whole scene depends on. */
  @keyframes pg-turn {
    0%   { transform: rotateY(0deg);    opacity: 1; }
    11%  { transform: rotateY(-172deg); opacity: 1; }
    15%  { transform: rotateY(-172deg); opacity: 0; }
    16%  { transform: rotateY(0deg);    opacity: 0; }
    21%  { transform: rotateY(0deg);    opacity: 1; }
    100% { transform: rotateY(0deg);    opacity: 1; }
  }
  .pg__face {
    display: block;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }
  .pg__face--front { position: relative; }
  .pg__face--back {
    position: absolute; inset: 0;
    transform: rotateY(180deg);
  }
  .pg__face svg { display: block; width: 100%; height: auto;
                  filter: drop-shadow(0 10px 20px rgba(11, 31, 68, 0.18)); }

  .pg__paper { fill: var(--surface-solid); stroke: var(--line); stroke-width: 1; }
  .pg__paper--back { fill: color-mix(in srgb, var(--surface-solid) 92%, var(--mark-blue)); }
  .pg__rule { fill: var(--mark-navy); opacity: 0.8; }
  .pg__rule--hot { fill: var(--accent-500); opacity: 1; }
  .pg__line { fill: var(--text-dim); opacity: 0.35; }
  .pg__block { fill: var(--mark-blue); opacity: 0.14; }
  .pg__code { fill: var(--mark-navy); opacity: 0.9; }
  .pg__tok { fill: #7fa8e0; }
  .pg__tok--hot { fill: var(--accent-500); }
  .pg__axis { stroke: var(--line-strong); stroke-width: 1.5; }
  .pg__plot { fill: none; stroke: var(--accent-500); stroke-width: 3;
              stroke-linecap: round; stroke-linejoin: round; }
  .pg__sw rect { fill: var(--mark-blue); opacity: 0.45; }
  .pg__sw rect:nth-child(2) { fill: var(--accent-500); opacity: 0.9; }
  .pg__sw rect:nth-child(3) { fill: var(--mark-navy); opacity: 0.3; }

  /* The binding, and the surface it all rests on. */
  .s3--spine {
    width: 1.6%; height: 46%;
    border-radius: 3px;
    background: linear-gradient(to bottom,
      var(--mark-navy), color-mix(in srgb, var(--mark-navy) 60%, transparent));
  }
  .s3--desk {
    width: 96%; height: 46%;
    transform: translate(-50%, -50%) rotateX(76deg) translateZ(var(--z));
    background: radial-gradient(ellipse at center,
                color-mix(in srgb, var(--mark-blue) 15%, transparent), transparent 66%);
  }

  /* Hover, dim and lift all come from the shared .s3 rules now. */
  .s3--sheet { transition: transform var(--dur) var(--ease-out); }
  .scene3d--book.has-spot .s3--sheet:not(.is-active) { opacity: 0.45; }
  .t-trace { fill: none; stroke: var(--mark-navy); stroke-width: 3;
             stroke-linecap: round; stroke-linejoin: round; opacity: 0.5; }

  /* The project travelling its own path: back to front, on the ground. */
  .s3--token {
    width: 3.2%; aspect-ratio: 1; border-radius: 50%;
    background: var(--accent-500);
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent-500) 22%, transparent);
    animation: s3-token 9s var(--ease-in-out) infinite;
  }
  @keyframes s3-token {
    0%   { transform: translate(-50%, -50%) translate3d(-128px, -46px, -190px); opacity: 0; }
    8%   { opacity: 1; }
    92%  { opacity: 1; }
    100% { transform: translate(-50%, -50%) translate3d(122px, 40px, 190px); opacity: 0; }
  }

  /* ── Hover ─────────────────────────────────────────────────────────
     The figure lifts toward the viewer. In a flat scene this would be a
     scale; here it is real distance, so it separates from its neighbours. */
  .s3--seat, .s3--remote, .s3--panel { transition: transform var(--dur) var(--ease-out); }
  .s3--seat:hover, .s3--seat:focus-visible,
  .s3--remote:hover, .s3--remote:focus-visible,
  .s3--panel:hover, .s3--panel:focus-visible,
  .s3--station:hover, .s3--station:focus-visible,
  .s3--sheet:hover, .s3--sheet:focus-visible,
  .s3.is-active {
    transform: translate(-50%, -50%) translateZ(calc(var(--z) + 70px)) scale(var(--s, 1));
  }
  .s3:focus { outline: none; }
  .s3:focus-visible .s3__head { stroke: var(--accent-500); stroke-width: 3; }
  .scene3d.has-spot .s3:not(.is-active) { opacity: 0.5; }
  .s3 { transition: transform var(--dur) var(--ease-out), opacity var(--dur) var(--ease-out); }

  /* ── The lesson deck on the board ──────────────────────────────────
     Three slides, one at a time, on a 15s cycle. Pure keyframes. */
  .s3-deck {
    position: absolute; inset: 12% 8% 14%;
    display: grid; place-items: center;
  }
  .s3-slide {
    grid-area: 1 / 1;
    margin: 0; width: 100%;
    display: grid; gap: 0.4rem; justify-items: center;
    opacity: 0;
    animation: s3-slide 15s linear infinite;
    animation-delay: calc(var(--n) * -5s);
  }
  .s3-slide svg { width: 86%; }
  .s3-slide figcaption {
    font-family: var(--font-display); font-weight: 600;
    font-size: clamp(0.62rem, 1vw, 0.78rem);
    letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--mark-navy);
  }
  /* One third on, two thirds off, with the fades inside its own third so
     no two slides are ever up together. */
  @keyframes s3-slide {
    0%, 2%    { opacity: 0; transform: translateY(6px); }
    5%, 28%   { opacity: 1; transform: none; }
    32%, 100% { opacity: 0; transform: translateY(-6px); }
  }

  .c-line { fill: var(--mark-blue); }
  .c-line--hot { fill: var(--accent-500); }
  .c-caret { fill: var(--mark-blue); opacity: 0.5; }
  .c-plot { fill: none; stroke: var(--accent-500); stroke-width: 5;
            stroke-linecap: round; stroke-linejoin: round; }
  .c-pts circle { fill: var(--accent-500); }
  .c-curve { fill: none; stroke: var(--accent-500); stroke-width: 5;
             stroke-linecap: round; }
  .c-anchor { fill: var(--mark-blue); }

  /* ── The label that follows the pointer ────────────────────────────
     Outside the stage, so it is never turned with it and always faces
     the reader. */
  .s3-card {
    position: absolute;
    transform: translate(-50%, calc(-100% - 1rem));
    min-width: 8.5rem; max-width: 13rem;
    padding: 0.6rem 0.8rem;
    border-radius: var(--r-sm);
    background: var(--surface-solid);
    border: 1px solid var(--line);
    box-shadow: 0 14px 34px rgba(11, 31, 68, 0.18);
    display: grid; gap: 0.15rem;
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity var(--dur-fast) var(--ease-out),
                transform var(--dur) var(--ease-out), visibility var(--dur);
    z-index: 3;
  }
  .s3-card.is-open { opacity: 1; visibility: visible;
                     transform: translate(-50%, calc(-100% - 0.6rem)); }
  .scene3d.is-turning .s3-card { opacity: 0; visibility: hidden; }
  .s3-card__title { font-family: var(--font-display); font-weight: 600;
                    font-size: var(--fs-sm); color: var(--text); }
  .s3-card__note { font-size: var(--fs-2xs); color: var(--text-dim); line-height: 1.35; }

  .s3-hint {
    position: absolute; inset-inline-end: 0; bottom: 0;
    font-family: var(--font-mono); font-size: var(--fs-2xs);
    letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--text-dim); opacity: 0.7;
    transition: opacity var(--dur) var(--ease-out);
  }
  .scene3d.is-turning .s3-hint, .scene3d.has-turned .s3-hint { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .scene3d__stage { transform: none !important; }
  .s3-slide { animation-duration: 45s; }
  .s3 { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   EDITORIAL CARDS
   Replaces the glass-and-glow card on the four listing surfaces.

   What went: 20px radii, backdrop-filter, the radial accent glow that
   followed the pointer, the shadow lift, the pill row, and the "Details →"
   button every card carried. Six of those cards side by side were the same
   rectangle six times — nothing in the composition changed.

   What carries it now: a number, a rule, oversized type, and one link.
   Structure and typography do the work; the only effects are a border that
   darkens and an arrow that moves.
   ══════════════════════════════════════════════════════════════════════ */
.ed {
  position: relative;
  display: flex; flex-direction: column;
  gap: 0.55rem;
  padding: clamp(1.1rem, 1.8vw, 1.5rem) clamp(1.1rem, 1.8vw, 1.5rem) clamp(1rem, 1.6vw, 1.35rem);
  /* A 2px radius, not 24. Sharp enough to read as a printed panel. */
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--bg);
  color: inherit;
  text-decoration: none;
  isolation: isolate;
  transition: border-color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
a.ed:hover, a.ed:focus-visible { border-color: var(--text); background: var(--surface); }
a.ed:focus { outline: none; }
a.ed:focus-visible { outline: 2px solid var(--accent-500); outline-offset: 2px; }

/* ── The kicker: 01 / DEVELOPMENT ─────────────────────────────────────── */
.ed__kicker {
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
}
.ed__kicker i { font-style: normal; color: var(--line-strong); }

/* ── Type does the work ───────────────────────────────────────────────── */
.ed__title {
  margin: 0.15rem 0 0;
  font-family: var(--font-display);
  font-weight: 600;
  /* Large, and tight. The heading is the visual, not a label above one. */
  font-size: clamp(1.35rem, 2.1vw, 1.9rem);
  line-height: 0.98;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.ed__body {
  margin: 0; max-width: 34ch;
  font-size: var(--fs-sm); line-height: 1.5; color: var(--text-muted);
}
.ed__meta {
  margin: 0;
  font-size: var(--fs-2xs); letter-spacing: 0.04em;
  color: var(--text-dim);
}

/* ── The number, sitting half outside its own card ────────────────────── */
/* The number is the only index on the card now — the kicker used to repeat
   it. Sat at 7% it was a texture; as the sole marker it has to be legible,
   and it needs its own space rather than sitting under the kicker. */
.ed__index {
  position: absolute; top: clamp(0.9rem, 1.5vw, 1.25rem);
  inset-inline-end: clamp(1.1rem, 1.8vw, 1.5rem);
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.5rem, 2.4vw, 2.1rem); line-height: 1;
  letter-spacing: -0.04em;
  color: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
}
/* Keep the kicker and title clear of it. */
.ed__kicker, .ed .ed__title { padding-inline-end: 3.2rem; }
/* On a course card the media bleeds to the top edge, so the index sits over
   the photograph and needs its own contrast rather than the page's. */
.ed--course .ed__index {
  top: 0.55rem; inset-inline-end: 0.7rem;
  color: #fff; opacity: 0.95;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
}

/* ── The one action, at the foot, aligned to the baseline ─────────────── */
.ed__go {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-top: auto; padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm);
}
.ed__go em {
  font-style: normal; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.ed__arrow {
  color: var(--accent-ink); font-size: 1rem; line-height: 1;
  transition: transform var(--dur) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  a.ed:hover .ed__arrow { transform: translate(3px, -3px); }
}

/* ── Imagery, cropped rather than framed ──────────────────────────────── */
.ed__media {
  position: relative; display: block;
  /* Bleeds to the card's edges: the image is part of the panel, not a
     rounded thumbnail floating inside it. */
  margin: calc(-1 * clamp(1.1rem, 1.8vw, 1.5rem));
  margin-bottom: 0.35rem;
  aspect-ratio: 16 / 9; overflow: hidden;
  background: var(--surface-strong);
  border-bottom: 1px solid var(--line);
}
.ed__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  a.ed:hover .ed__media img { transform: scale(1.03); }
}
.ed__initials {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700;
  font-size: 2.4rem; color: var(--line-strong);
}
.ed__flag {
  position: absolute; top: 0; inset-inline-start: 0;
  padding: 0.28rem 0.6rem;
  background: var(--accent-500); color: #0b1f44;
  font-family: var(--font-mono); font-size: 0.58rem;
  letter-spacing: 0.14em; text-transform: uppercase;
}

/* ── A class is defined by when it starts, so the date is the anchor ──── */
.ed__date {
  position: absolute; top: -1px; inset-inline-end: -1px;
  display: grid; justify-items: center; gap: 0.05rem;
  padding: 0.5rem 0.7rem 0.45rem;
  border-inline-start: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.ed__date b {
  font-family: var(--font-display); font-size: 1.35rem; line-height: 1;
  font-weight: 700; color: var(--text);
}
.ed__date i {
  font-style: normal; font-family: var(--font-mono);
  font-size: 0.56rem; letter-spacing: 0.14em; color: var(--text-dim);
}
.ed--training .ed__kicker { padding-inline-end: 4rem; }

.ed--value { gap: 0.6rem; }
.ed--value .ed__title { font-size: clamp(1.2rem, 1.7vw, 1.5rem); }

/* ── Controlled asymmetry ───────────────────────────────────────────────
   A grid of identical cells is the other half of the template look: if one
   card can be duplicated six times with nothing changing, the composition
   is doing no work.

   Twelve columns, and a repeating 7/5 · 5/7 rhythm — so the first card is
   wide and the second narrow, then the pair reverses. Deliberate, not
   random: it repeats on a four-card cycle, which reads as a decision.
   ──────────────────────────────────────────────────────────────────── */
@media (min-width: 961px) {
  .grid--ed {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: clamp(1rem, 1.6vw, 1.5rem);
    align-items: stretch;
  }
  .grid--ed > * { grid-column: span 6; }
  .grid--ed > *:nth-child(4n + 1) { grid-column: span 7; }
  .grid--ed > *:nth-child(4n + 2) { grid-column: span 5; }
  .grid--ed > *:nth-child(4n + 3) { grid-column: span 5; }
  .grid--ed > *:nth-child(4n + 4) { grid-column: span 7; }

  /* The wider card gets room to breathe and a larger heading; the narrow
     one stays tight. Same component, two weights. */
  .grid--ed > *:nth-child(4n + 1) .ed__title,
  .grid--ed > *:nth-child(4n + 4) .ed__title { font-size: clamp(1.6rem, 2.6vw, 2.4rem); }
  .grid--ed > *:nth-child(4n + 1) .ed__media,
  .grid--ed > *:nth-child(4n + 4) .ed__media { aspect-ratio: 16 / 8; }
  /* The body stays on every card: hiding it on the narrow ones is what made
     one card in a pair look unfinished next to the other. */
}

/* Three-up surfaces keep a lighter rhythm: one tall card per row of three. */
@media (min-width: 961px) {
  .grid--ed3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(1rem, 1.6vw, 1.5rem);
    /* Every card the same height, sitting on one line. The staggered offset
       that was here made a row of equals look like a mistake. */
    align-items: stretch;
  }
}

/* Expert cards. Stacked on a phone, photo-beside-text from a tablet up.

   These sit last in the file on purpose: every attempt to state this layout
   further up lost to the block that lives here, at identical specificity,
   purely on document order.

   Stacked, the card was 232px wide and 464px tall — a column so narrow that
   two-word names wrapped, and one that could not be widened without also
   getting taller, because a full-width photo makes width and height the
   same control. Side by side, the card's height is just the taller of its
   two columns, so it grows wider and shorter at the same time.

   Written against the markup as it really is: `team_card` is flat. The
   frame *is* the `.ed__media`, and the kicker, name, bio, skills and links
   are its siblings — there is no wrapper around the text. So the frame is
   pinned to column one and everything that is not the frame goes to column
   two, where it stacks in source order. */
.ed.ed--person {
  display: flex; min-width: 0;
  padding: clamp(1.1rem, 1.8vw, 1.5rem)
           clamp(1.1rem, 1.8vw, 1.5rem)
           clamp(1rem, 1.6vw, 1.35rem);
  overflow: hidden;
}
.ed.ed--person .person__frame {
  height: auto; min-height: 0; aspect-ratio: 16 / 9;
  border-inline-end: 0; border-block-end: 1px solid var(--line);
}
.ed--person .person__name {
  font-size: clamp(1.3rem, 2vw, 1.8rem); line-height: 1.05;
}

.person__bio { -webkit-line-clamp: 3; }
.person__links { align-items: center; gap: 1rem; padding-top: 0.9rem; }
.person__socials { display: flex; align-items: center; gap: 0.2rem; }
.person__links a {
  display: grid; place-items: center; width: 30px; height: 30px;
  border: 1px solid var(--line); border-radius: 50%; color: var(--text-dim);
}
.person__links a:hover {
  border-color: var(--text); background: var(--surface); color: var(--accent-ink);
}

/* ══════════════════════════════════════════════════════════════════════
   BLOG
   Three weights instead of one: a feature, a few cards, then a list.
   Radii are 2px, there are no shadows and no gradients — the border, the
   spacing and the type carry it.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Shared: the metadata line and the arrow ─────────────────────────── */
.pc__kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
}
.pc__kicker i { font-style: normal; color: var(--line-strong); margin-inline: 0.15rem; }
.pc__arrow {
  color: var(--accent-ink); font-size: 1rem; line-height: 1;
  transition: transform 400ms var(--ease-out);
}

/* ── The feature: image beside the copy ──────────────────────────────── */
.pf {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  border: 1px solid var(--line); border-radius: 2px;
  background: var(--bg); color: inherit; text-decoration: none;
  overflow: hidden;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.pf:hover, .pf:focus-visible { border-color: var(--text); }
.pf:focus { outline: none; }
.pf:focus-visible { outline: 2px solid var(--accent-500); outline-offset: 2px; }
.pf__media {
  position: relative; display: block;
  /* 4/3 beside a 1.05fr column made the feature nearly 500px tall on a
     laptop and pushed everything under it off the screen. */
  aspect-ratio: 16 / 10; overflow: hidden; background: var(--surface-strong);
}
.pf__media img { width: 100%; height: 100%; object-fit: cover; display: block;
                 transition: transform 500ms var(--ease-out); }
.pf__body {
  display: flex; flex-direction: column; gap: 0.7rem;
  padding: clamp(1.1rem, 2vw, 1.75rem);
}
.pf__title {
  margin: 0;
  font-family: var(--font-display); font-weight: 600;
  /* Still the largest headline in the list, but 2.7rem was billboard
     scale — it set the whole page's sense of size and everything below it
     had to be big to match. */
  font-size: clamp(1.3rem, 2.1vw, 1.85rem);
  line-height: 1.06; letter-spacing: -0.022em; text-wrap: balance;
}
.pf__stand {
  margin: 0; max-width: 46ch;
  font-size: var(--fs-sm); line-height: 1.55; color: var(--text-muted);
}
.pf__foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-top: auto; padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-2xs); color: var(--text-dim);
}
@media (max-width: 820px) {
  .pf { grid-template-columns: 1fr; }
  .pf__media { aspect-ratio: 16 / 9; }
}

/* ── The cards: three across, with the first given more image ────────── */
.pc-grid {
  display: grid; gap: clamp(0.85rem, 1.2vw, 1.15rem);
  /* 260px floors the row at three cards on a 1200px container and each one
     came out ~380px wide. 220px lets a wide screen fit four, which is what
     a news index looks like. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  align-items: stretch;
}
.pc {
  display: flex; flex-direction: column; gap: 0.55rem;
  border: 1px solid var(--line); border-radius: 2px;
  background: var(--bg); color: inherit; text-decoration: none;
  overflow: hidden;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.pc:hover, .pc:focus-visible { border-color: var(--text); }
.pc:focus { outline: none; }
.pc:focus-visible { outline: 2px solid var(--accent-500); outline-offset: 2px; }
.pc__media {
  position: relative; display: block;
  aspect-ratio: 16 / 10; overflow: hidden;
  background: var(--surface-strong);
  border-bottom: 1px solid var(--line);
}
.pc__media img { width: 100%; height: 100%; object-fit: cover; display: block;
                 transition: transform 500ms var(--ease-out); }
.pc__initials {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700;
  font-size: 2.2rem; color: var(--line-strong);
}
.pc .pc__kicker { padding: 0.7rem clamp(0.75rem, 1.1vw, 0.95rem) 0; }
.pc__title {
  margin: 0; padding: 0 clamp(0.75rem, 1.1vw, 0.95rem);
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 1.15vw, 1.12rem);
  /* 1.05 is a display leading. At card size it collided the descenders of
     one line with the ascenders of the next. */
  line-height: 1.25; letter-spacing: -0.012em; text-wrap: balance;
}
.pc__foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-top: auto;
  padding: 0.7rem clamp(0.75rem, 1.1vw, 0.95rem) 0.75rem;
  font-size: var(--fs-2xs); color: var(--text-dim);
}
/* The first card takes a taller crop, so the row is not three identical
   rectangles. */
@media (min-width: 861px) {
  /* A nudge, not a promotion. At 4/3 plus 1.7rem the first card was half
     again as tall as its neighbours and the row stopped reading as a row. */
  .pc-grid > .pc:first-child .pc__media { aspect-ratio: 16 / 10; }
  .pc-grid > .pc:first-child .pc__title { font-size: clamp(1.08rem, 1.3vw, 1.25rem); }
}

/* ── The list: everything past the first few ─────────────────────────── */
.pr-list { border-top: 1px solid var(--line); }
.pr {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr) auto auto 1.2rem;
  align-items: baseline; gap: clamp(0.75rem, 2vw, 1.5rem);
  padding: clamp(0.9rem, 1.6vw, 1.25rem) 0.25rem;
  border-bottom: 1px solid var(--line);
  color: inherit; text-decoration: none;
  transition: background var(--dur-fast) var(--ease-out),
              padding-inline-start var(--dur) var(--ease-out);
}
.pr:hover, .pr:focus-visible { background: var(--surface); padding-inline-start: 0.9rem; }
.pr:focus { outline: none; }
.pr:focus-visible { outline: 2px solid var(--accent-500); outline-offset: -2px; }
.pr__num {
  font-family: var(--font-mono); font-size: 0.72rem;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}
.pr__title {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 1.5vw, 1.25rem); line-height: 1.2;
  letter-spacing: -0.01em;
}
.pr__meta, .pr__date {
  font-size: var(--fs-2xs); color: var(--text-dim); white-space: nowrap;
}
@media (max-width: 720px) {
  .pr { grid-template-columns: 2.2rem minmax(0, 1fr) 1.2rem; }
  .pr__meta, .pr__date { display: none; }
}

/* ── Interaction: quiet and physical ─────────────────────────────────── */
@media (hover: hover) and (pointer: fine) {
  .pf:hover .pf__media img,
  .pc:hover .pc__media img { transform: scale(1.03); }
  .pf:hover .pc__arrow,
  .pc:hover .pc__arrow,
  .pr:hover .pc__arrow { transform: translate(4px, -4px); }
}

/* ── Profile picture control ─────────────────────────────────────────── */
.avatar-edit { display: flex; align-items: center; gap: clamp(1rem, 2vw, 1.5rem); }
.avatar-edit__actions { display: grid; gap: 0.45rem; justify-items: start; }
/* The file input is hidden but still focusable through its label, so the
   control stays reachable by keyboard rather than being a decorative button
   over an input nobody can reach. */
.avatar-edit input[type="file"].sr-only:focus-visible + label,
.avatar-edit label:focus-within { outline: 2px solid var(--accent-500); outline-offset: 2px; }
.avatar-edit label.btn { cursor: pointer; }
.btn-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--text-dim); text-decoration: underline; text-underline-offset: 3px;
}
.btn-link:hover { color: var(--text); }

/* ── Picture preview ────────────────────────────────────────────────────
   Choosing a file and saving it are two steps now, so the page has to say
   which one you are in. `.is-enhanced` is set by avatar.js: without it the
   buttons stay visible and the form is a plain upload. */
.avatar-edit__row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.avatar-edit__note {
  margin: 0.4rem 0 0;
  min-height: 1.15em;          /* holds its line so nothing jumps */
  color: var(--text-muted);
}
.avatar-edit.is-invalid .avatar-edit__note { color: var(--danger); }

.avatar-edit.is-enhanced [data-avatar-save],
.avatar-edit.is-enhanced [data-avatar-cancel] { display: none; }
.avatar-edit.is-enhanced.is-picked [data-avatar-save] { display: inline-flex; }
.avatar-edit.is-enhanced.is-picked [data-avatar-cancel] { display: inline; }

/* A ring marks the picture as chosen-but-not-saved. */
.avatar-edit.is-picked .avatar-edit__face {
  box-shadow: 0 0 0 2px var(--accent-500);
}
.avatar-edit.is-picked .avatar-edit__face img {
  animation: avatar-in 200ms cubic-bezier(0.23, 1, 0.32, 1) both;
}
.avatar-edit.is-saving .avatar-edit__face { opacity: 0.62; }

@keyframes avatar-in {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  @keyframes avatar-in { from { opacity: 0; } to { opacity: 1; } }
}

/* ══════════════════════════════════════════════════════════════════════
   BLOG DISCOVERY — search, category row, tags
   Shared by the index, the category pages and the tag pages.
   ══════════════════════════════════════════════════════════════════════ */

.blog-search {
  display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap;
  max-width: 620px; margin-bottom: var(--sp-6);
}
.blog-search .search-field { flex: 1; min-width: 200px; }

/* The category row. Counts sit inside the chip so the row stays one line
   of objects rather than a label and a number that can wrap apart. */
.topic-row {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  margin-top: var(--sp-6);
}
.chip__count {
  margin-inline-start: 0.45rem;
  font-family: var(--font-mono); font-size: 0.68em;
  color: var(--text-dim); font-variant-numeric: tabular-nums;
}
.chip.is-active .chip__count { color: inherit; opacity: 0.7; }

/* What the search returned. Deliberately plain text, not a banner: it is a
   sentence answering a question the reader just asked. */
.result-line {
  margin: -0.5rem 0 var(--sp-6);
  font-size: var(--fs-sm); color: var(--text-muted);
}
.result-line strong { color: var(--text); font-variant-numeric: tabular-nums; }
.result-line em { font-style: normal; color: var(--accent-ink); }

/* ── Tags ────────────────────────────────────────────────────────────
   A quiet block at the end of a listing rather than a header of pills.
   Weight tracks usage, so the tags that carry the most writing read
   first without needing to be sorted into a separate list. */
.tag-cloud {
  margin-top: var(--sp-9);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
}
.tag-cloud__head {
  font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase;
  font-family: var(--font-mono); color: var(--text-dim);
  margin-bottom: var(--sp-4);
}
.tag-cloud__items { display: flex; flex-wrap: wrap; gap: 0.45rem 0.6rem; }

.tag {
  display: inline-flex; align-items: baseline; gap: 0.2rem;
  padding: 0.3rem 0.7rem; border-radius: var(--r-pill);
  border: 1px solid var(--line);
  font-size: var(--fs-sm); color: var(--text-muted);
  /* 1 to 4 uses maps to 400-600. Beyond that the difference stops being
     information and starts being noise. */
  font-weight: calc(380 + var(--tag-weight, 1) * 55);
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
.tag:hover { border-color: var(--line-strong); color: var(--text); }
.tag.is-active {
  background: var(--accent-500); border-color: var(--accent-500); color: var(--brand-900);
}
.tag__hash { color: var(--text-dim); }
.tag.is-active .tag__hash { color: inherit; opacity: 0.6; }
.tag__count {
  font-family: var(--font-mono); font-size: 0.7em; color: var(--text-dim);
  font-variant-numeric: tabular-nums; font-weight: 400;
}
.tag.is-active .tag__count { color: inherit; opacity: 0.7; }

/* The hash on a tag page's heading is punctuation, not a word. */
.tag-title__hash { color: var(--text-dim); font-weight: 400; }

@media (max-width: 640px) {
  .blog-search { gap: 0.5rem; }
  .blog-search .btn { flex: 1; }
}

/* ══════════════════════════════════════════════════════════════════════
   READER-SIDE COMMENT STATES
   ══════════════════════════════════════════════════════════════════════ */

/* A comment kept only because replies hang off it. */
.comment--gone .comment__gone {
  margin: 0; font-size: var(--fs-sm); font-style: italic;
  color: var(--text-dim);
}
.comment--pinned > .comment__body > .comment__head { align-items: center; }

/* "edited" is a fact about the comment, not a decoration. */
.comment__edited {
  font-size: var(--fs-xs); color: var(--text-dim);
  border-bottom: 1px dotted currentColor; cursor: help;
}

/* The action row holds buttons, links and a one-button form; they have to
   sit on the same line as though they were all the same thing. */
.comment__inline { display: inline; }
.comment__actions a,
.comment__actions button {
  font-size: var(--fs-xs); color: var(--text-dim);
  display: inline-flex; align-items: center; gap: 0.3rem;
}
.comment__actions a:hover,
.comment__actions button:hover { color: var(--text); }
.comment__report:hover { color: var(--danger); }

/* The comment being reported, quoted back on the report page so nobody
   flags the wrong one. */
.quoted-comment {
  margin: 0; padding: 1rem 1.15rem;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface);
}
.quoted-comment__head { display: flex; align-items: center; gap: 0.6rem; }
.quoted-comment__head span { display: grid; }
.quoted-comment__body {
  margin: 0.75rem 0 0; padding: 0; border: 0;
  font-size: var(--fs-sm); line-height: 1.6; color: var(--text-muted);
  font-style: normal; font-family: inherit;
}

/* ── Study path cards ────────────────────────────────────────────────
   The comparison pair on /academy. Both carry identical spec labels in
   identical order, so the rows line up across the two cards and the
   differences read without prose. That alignment is the whole design;
   everything else here just stays out of its way. */
.ed--path { gap: 0.5rem; }
.ed--path .ed__body { max-width: 42ch; }

.spec {
  margin: 0.9rem 0 0;
  display: grid;
  /* A rule between rows, not around them — a bordered box inside a bordered
     card is two frames doing one job. */
  border-block-start: 1px solid var(--line);
}
.spec__row {
  display: grid;
  grid-template-columns: minmax(6.5rem, 8rem) minmax(0, 1fr);
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-block-end: 1px solid var(--line);
}
.spec dt {
  font-family: var(--font-mono);
  font-size: 0.64rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-dim);
  /* Nudged down so the label's cap-height aligns with the value's x-height
     rather than floating above it. */
  padding-block-start: 0.15rem;
}
.spec dd {
  margin: 0; font-size: var(--fs-sm); line-height: 1.45; color: var(--text);
}

.ed--path .ed__foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-top: auto; padding-top: 0.9rem;
}
.ed__go {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-size: var(--fs-sm); font-weight: 600; color: var(--accent-ink);
  white-space: nowrap;
}
.ed__go svg { transition: transform var(--dur-fast) var(--ease-out); }
.ed__go:hover svg { transform: translateX(3px); }

/* Two columns of spec rows on a phone would set the values two words wide. */
@media (max-width: 520px) {
  .spec__row { grid-template-columns: 1fr; gap: 0.1rem; }
  .spec dt { padding-block-start: 0; }
}

/* ── Contact details ─────────────────────────────────────────────────
   Was four rows of icon-in-a-tinted-circle beside a heading and a value.
   The icons said nothing the labels did not, and the circles gave four
   plain facts the visual weight of four features. Same aligned label/value
   grid as the spec rows elsewhere, so the site has one way of presenting
   a list of facts rather than three. */
.reach {
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--bg);
  padding: clamp(1.1rem, 1.8vw, 1.5rem);
}
.reach__head {
  margin: 0 0 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-dim);
}
.reach__row {
  display: grid;
  grid-template-columns: minmax(4.5rem, 5.5rem) minmax(0, 1fr);
  gap: 0.9rem;
  padding: 0.85rem 0;
  border-block-start: 1px solid var(--line);
}
.reach__row:first-of-type { border-block-start: 0; padding-block-start: 0.5rem; }
.reach__label {
  margin: 0; padding-block-start: 0.12rem;
  font-family: var(--font-mono);
  font-size: 0.64rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-dim);
}
.reach__value { min-width: 0; }
.reach__value p { margin: 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--text); }
.reach__strong {
  display: block; font-size: var(--fs-sm); font-weight: 550; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.reach__strong:hover { color: var(--accent-ink); }
.reach__note { color: var(--text-dim) !important; font-size: var(--fs-xs) !important; margin-top: 0.2rem !important; }
.reach__link {
  display: inline-flex; align-items: center; gap: 0.3rem; margin-top: 0.4rem;
  font-size: var(--fs-xs); font-weight: 600; color: var(--accent-ink);
}

@media (max-width: 520px) {
  .reach__row { grid-template-columns: 1fr; gap: 0.15rem; }
  .reach__label { padding-block-start: 0; }
}

/* Contact is intentionally flat: the two information panels use one visual
   language, without glass gradients, hover glow or a decorative hero wash. */
.page-contact .contact-hero { background: var(--bg); }
.page-contact .contact-hero::after { display: none; }
.page-contact .card {
  background: var(--bg); backdrop-filter: none;
}
.page-contact .card::before { display: none; }
@media (hover: hover) and (pointer: fine) {
  .page-contact .card:hover {
    transform: none; border-color: var(--line-strong); box-shadow: none;
  }
}
.contact-panel h2,
.contact-panel .reach__head {
  margin: 0; font-family: var(--font-display); font-size: var(--fs-xl);
  line-height: 1.15; letter-spacing: -0.02em; text-transform: none;
  color: var(--text);
}
.contact-panel.reach {
  padding: clamp(1.75rem, 3vw, 2.75rem);
  border-radius: var(--r-lg); background: var(--bg);
}
.contact-panel .reach__row:first-of-type { padding-block-start: 1.25rem; }
.page-contact .contact-submit { --btn-bg: var(--accent-500); }
.page-contact .contact-submit::after { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   THE BLOG FRONT

   An asymmetric grid rather than equal columns: the lead takes 1.62 of the
   width to the seconds' 1, which is far enough from 2:1 that the two
   columns read as different jobs rather than as a wide one and a narrow
   one. Uniform columns are what make an index look like a template.
   ══════════════════════════════════════════════════════════════════════ */
.front { padding-block: clamp(1.5rem, 3vw, 2.5rem) clamp(3rem, 6vw, 5rem); }

/* ── Masthead ─────────────────────────────────────────────────────── */
.masthead { margin-bottom: clamp(1.75rem, 3.5vw, 3rem); }
.masthead__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem;
  padding-block-end: clamp(1rem, 2vw, 1.5rem);
}
.masthead__title {
  margin: 0;
  font-family: var(--font-display); font-weight: 700;
  /* Scale dissonance: the masthead is four times the body size, and that
     difference is what carries the hierarchy instead of a colour. */
  font-size: clamp(2.1rem, 5.5vw, 3.6rem);
  line-height: 0.98; letter-spacing: -0.035em;
}
.masthead__sub {
  margin: 0; max-width: 52ch;
  font-size: var(--fs-sm); line-height: 1.55; color: var(--text-muted);
}
.masthead__bar {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 0.75rem 1.5rem;
  padding-block: 0.7rem;
  border-block: 1px solid var(--text);
}
.masthead__bar .filter-bar,
.masthead__bar form { margin: 0; }
.masthead__bar .search-field { flex: 0 1 260px; min-width: 180px; }

@media (min-width: 900px) {
  .masthead__row { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); align-items: end; }
  .masthead__sub { padding-block-end: 0.35rem; }
}

/* ── The front grid ───────────────────────────────────────────────── */
.front__grid { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }

@media (min-width: 900px) {
  .front__grid {
    grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
    align-items: start;
  }
}

/* ── The lead ─────────────────────────────────────────────────────── */
.lead { display: block; color: inherit; text-decoration: none; }
.lead__media {
  display: block; position: relative; overflow: hidden;
  aspect-ratio: 16 / 9; background: var(--surface-strong);
  border: 1px solid var(--line);
}
.lead__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 700ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .lead:hover .lead__media img { transform: scale(1.025); }
}
.lead__initials {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(3rem, 7vw, 5rem); color: var(--line-strong);
}
.lead__copy { display: block; padding-block-start: clamp(0.85rem, 1.6vw, 1.15rem); }
.lead__title {
  margin: 0.3rem 0 0;
  font-family: var(--font-display); font-weight: 600;
  /* The largest headline on the page after the masthead. This is the one
     article the front is arguing for. */
  font-size: clamp(1.6rem, 3.4vw, 2.7rem);
  line-height: 1.04; letter-spacing: -0.028em; text-wrap: balance;
}
.lead:hover .lead__title { text-decoration: underline; text-underline-offset: 4px; }
.lead__stand {
  margin: 0.6rem 0 0; max-width: 56ch;
  font-size: var(--fs-base); line-height: 1.55; color: var(--text-muted);
  text-wrap: pretty;
}
.lead__foot {
  display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.75rem;
  font-size: var(--fs-2xs); color: var(--text-dim);
}
.lead__foot i { font-style: normal; color: var(--line-strong); }

/* ── The seconds ──────────────────────────────────────────────────── */
.front__seconds {
  display: grid;
  /* A rule above each, so the column reads as a stack of stories rather
     than as two more cards. */
  border-block-start: 1px solid var(--text);
}
.second {
  display: block; color: inherit; text-decoration: none;
  padding-block: clamp(0.9rem, 1.8vw, 1.25rem);
  border-block-end: 1px solid var(--line);
  transition: background var(--dur-fast) var(--ease-out);
}
.second:hover { background: var(--surface); }
.second__title {
  margin: 0.3rem 0 0;
  font-family: var(--font-display); font-weight: 600;
  /* Deliberately about half the lead. Close in size and the hierarchy
     collapses; the gap is what makes the lead a lead. */
  font-size: clamp(1.05rem, 1.5vw, 1.28rem);
  line-height: 1.22; letter-spacing: -0.012em;
}
.second:hover .second__title { text-decoration: underline; text-underline-offset: 3px; }
.second__stand {
  margin: 0.35rem 0 0;
  font-size: var(--fs-xs); line-height: 1.5; color: var(--text-muted);
}
.second__date {
  display: block; margin-top: 0.5rem;
  font-family: var(--font-mono); font-size: 0.64rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim);
}

/* ── The tail ─────────────────────────────────────────────────────── */
.front__more { margin-top: clamp(2.5rem, 5vw, 4rem); }
.rule-head {
  display: flex; align-items: center; gap: 1rem;
  margin: 0 0 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-dim); font-weight: 500;
}
.rule-head::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}

/* ── Blog search ─────────────────────────────────────────────────────
   The field is the control; Enter submits it. The button stays for anyone
   who looks for one and for keyboard users, but it is taken out of the
   flow — laid out inline it wrapped beneath the field and left a lone
   yellow rectangle sitting under the masthead rule. */
.blog-search { display: flex; align-items: center; gap: 0.5rem; margin: 0; }
.blog-search__go { min-height: 50px; border-radius: var(--r-md); white-space: nowrap; }
.blog-search__clear {
  font-size: var(--fs-xs); color: var(--text-dim); white-space: nowrap;
}
.blog-search__clear:hover { color: var(--accent-ink); }

/* ── Card facts and notes ────────────────────────────────────────────────
   The editorial cards carried a title, a category and a price. Everything
   a reader actually weighs — how many lessons, how long, whether there is
   room, whether they can pay in parts — was on the detail page, one click
   past the decision. These are those numbers, set as data rather than as
   badges: no pills, no colour, just figures the eye can compare down a row
   of cards. */
.ed__facts {
  display: flex; flex-wrap: wrap; gap: 0.25rem 1rem;
  margin: 0.55rem 0 0; padding: 0; list-style: none;
  font-size: var(--fs-2xs); color: var(--text-dim);
}
.ed__facts b {
  font-weight: 650; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.ed__facts .is-tight b { color: var(--accent-ink); }

/* When a class runs. Sits directly under the title because it is the second
   thing anyone asks about a live cohort, after what it is. */
.ed__when {
  display: flex; align-items: flex-start; gap: 0.35rem;
  margin: 0.5rem 0 0;
  font-size: var(--fs-2xs); line-height: 1.45; color: var(--text-muted);
}
/* The icon holds its size; the text takes the rest and wraps inside itself
   as ordinary prose. `min-width: 0` because a flex item will not shrink
   below its content width without it. */
.ed__when svg { flex-shrink: 0; margin-top: 0.1rem; color: var(--text-dim); }
.ed__when > span { min-width: 0; }
.ed__when .local-time { margin-inline-start: 0.25rem; }

/* A qualifier on the price: "or 3 parts", "2 places left", "Closed".
   Deliberately quiet — the moment scarcity is styled loudly it reads as a
   sales tactic and stops being believed. */
.ed__note {
  font-size: var(--fs-2xs); color: var(--text-dim); font-weight: 500;
  margin-inline-start: 0.5rem;
}
.ed__note--tight { color: var(--accent-ink); }
.ed__note--closed { color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; }

/* The price row can now hold three things, so it wraps rather than pushing
   the arrow off the card. */
.ed__go { flex-wrap: wrap; row-gap: 0.2rem; }
.ed__go .ed__arrow { margin-inline-start: auto; }

/* ── The filter bar, as one instrument ───────────────────────────────────
   It was four controls sitting loose on the page with nothing holding them
   together, so it read as a row of unrelated widgets rather than as a
   search. Grouping them on a surface says they act together, and gives the
   filtered state somewhere to show. */
.filter-bar {
  padding: 0.55rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease-out);
}
/* Something is actually applied. A quiet accent edge, not a coloured
   panel — the state is worth noticing, not worth shouting. */
.filter-bar.is-filtered { border-color: var(--line-accent); }

.filter-bar .select {
  background-color: var(--bg);
  border-color: var(--line);
  /* `.select` is `width: 100%` globally, which is right for a form column
     and wrong inside a flex row — every select claimed a full line, so the
     filter bar had always rendered as a vertical stack on desktop. */
  width: auto;
  flex: 0 1 auto;
  min-width: 8.5rem;
}
.filter-bar .search-field .input {
  background-color: var(--bg);
  /* Room for the icon on the left and the clear button on the right. */
  padding-inline: 2.5rem 2.25rem;
}
.filter-bar .search-field .input:focus-visible {
  border-color: var(--accent-500);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-500) 18%, transparent);
}

/* The inline clear. Absent until there is something to clear, so it is
   never a control that does nothing when pressed. */
.search-field__clear {
  position: absolute; inset-inline-end: 0.45rem; top: 50%; translate: 0 -50%;
  display: none; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  color: var(--text-dim);
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.search-field.has-value .search-field__clear { display: grid; }
.search-field__clear:hover { background: var(--surface-strong); color: var(--text); }
.search-field__clear:focus-visible {
  display: grid;
  outline: 2px solid var(--accent-500);
  outline-offset: 2px;
}
.search-field__clear svg {
  position: static;
  translate: none;
  width: 15px;
  height: 15px;
  color: currentColor;
}
.search-submit { min-height: 50px; border-radius: var(--r-md); }

/* Results being replaced. The old 45% dip made the whole set look broken
   for a moment; this keeps them legible and says "working" instead. */
[data-results] {
  transition: opacity var(--dur-fast) var(--ease-out);
}
[data-results].is-loading { opacity: 0.6; }

/* The count line is the one thing that confirms a keystroke did something,
   so it should not be the quietest text on the page. */
.result-line {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-xs); color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  /* Stacked, with the search full width — three selects abreast on a phone
     leaves each about eighty pixels of label. */
  .filter-bar { flex-direction: column; align-items: stretch; }
  .filter-bar .select, .filter-bar .btn { width: 100%; }
  .search-page-form { display: grid; grid-template-columns: 1fr; gap: .5rem; padding: .45rem; }
  .search-page-form .search-field { flex: none; width: 100%; min-width: 0; }
  .search-page-form .search-field .input { width: 100%; min-height: 48px; }
  .search-page-form .btn { width: 100%; min-height: 46px; }
  .search-field { min-width: 0; width: 100%; flex-basis: auto; }
  .search-field .input { min-height: 52px; }
  .blog-search { width: 100%; }
  .blog-search .search-field { flex: 1 1 auto; }
  .blog-search__go { width: 52px; min-width: 52px; padding-inline: 0; }
  .blog-search__go span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
}

/* ── Service and course detail pages ───────────────────────────────────
   Both product families use one visual grammar: editorial copy on the left,
   useful proof on the right, and a compact decision rail beside the detail. */
.offering-hero,
.course-detail-hero {
  position: relative;
  overflow: clip;
  padding-block: clamp(1.25rem, 2.8vw, 2.25rem) 0;
  border-bottom: 1px solid var(--line);
  background:
    radial-gradient(circle at 82% 10%, color-mix(in srgb, var(--detail-accent) 12%, transparent), transparent 30%),
    var(--bg);
}
.offering-hero > .container,
.course-detail-hero > .container { position: relative; z-index: 1; }
.offering-hero__grid,
.course-detail-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(340px, .78fr);
  gap: clamp(2.25rem, 6vw, 5.5rem);
  align-items: center;
  padding-block: clamp(2.5rem, 6vw, 5.75rem);
}
.offering-hero__copy,
.course-detail-hero__copy { max-width: 760px; }
.offering-hero h1,
.course-detail-hero h1 {
  max-width: 12ch;
  margin-top: 1rem;
  font-size: clamp(2.75rem, 6vw, 5.8rem);
  line-height: .94;
  letter-spacing: -.055em;
}
.detail-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.detail-eyebrow__icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid color-mix(in srgb, var(--detail-accent) 35%, var(--line));
  border-radius: 50%;
  color: var(--detail-accent);
  background: color-mix(in srgb, var(--detail-accent) 8%, var(--surface));
}
.offering-hero__tagline,
.course-detail-hero__subtitle {
  max-width: 28ch;
  margin-top: 1.35rem;
  font-size: clamp(1.2rem, 2.3vw, 1.65rem);
  line-height: 1.35;
  color: var(--text);
}
.offering-hero__summary,
.course-detail-hero__summary {
  max-width: 64ch;
  margin-top: 1rem;
  color: var(--text-muted);
  line-height: 1.75;
}
.detail-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.75rem; }
.detail-tech { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; margin-top: 1.6rem; }
.detail-tech > span:not(.detail-tech__label) {
  padding: .38rem .65rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  font-size: .72rem;
  font-weight: 650;
}
.detail-tech__label { margin-right: .2rem; color: var(--text-dim); font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; }

.offering-hero__visual,
.course-detail-hero__media {
  position: relative;
  aspect-ratio: 4 / 3;
  min-height: 360px;
  border: 1px solid color-mix(in srgb, var(--detail-accent) 24%, var(--line));
  border-radius: clamp(1.1rem, 2vw, 1.8rem);
  background: var(--surface);
  box-shadow: 0 24px 70px color-mix(in srgb, var(--detail-accent) 9%, transparent);
}
.offering-hero__visual > img,
.course-detail-hero__media > img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.offering-hero__fallback,
.course-detail-hero__fallback {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: grid;
  place-items: center;
  border-radius: inherit;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--detail-accent) 16%, var(--surface)), var(--surface) 62%),
    var(--surface);
}
.offering-hero__fallback::before,
.course-detail-hero__fallback::before {
  content: "";
  position: absolute;
  width: 70%; height: 70%;
  border: 1px solid color-mix(in srgb, var(--detail-accent) 22%, transparent);
  border-radius: 50%;
  box-shadow: 0 0 0 42px color-mix(in srgb, var(--detail-accent) 5%, transparent), 0 0 0 84px color-mix(in srgb, var(--detail-accent) 4%, transparent);
}
.offering-hero__orb { position: relative; z-index: 1; display: grid; place-items: center; width: 126px; height: 126px; border-radius: 50%; color: var(--detail-accent); background: var(--bg); box-shadow: var(--shadow-lg); }
.offering-hero__tile { position: absolute; z-index: 2; padding: .55rem .85rem; border: 1px solid var(--line); border-radius: 999px; background: var(--bg); font-size: .72rem; font-weight: 700; box-shadow: var(--shadow-sm); }
.offering-hero__tile--one { top: 14%; left: 8%; }
.offering-hero__tile--two { top: 22%; right: 7%; }
.offering-hero__tile--three { bottom: 15%; right: 12%; }
.offering-hero__stamp,
.course-detail-hero__media-label {
  position: absolute;
  right: -1rem;
  bottom: 1.25rem;
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .75rem .9rem;
  border: 1px solid var(--line);
  border-radius: .8rem;
  color: var(--text);
  background: var(--bg);
  box-shadow: var(--shadow-md);
}
.offering-hero__stamp svg { color: var(--detail-accent); }
.offering-hero__stamp span { display: grid; }
.offering-hero__stamp strong { font-size: .78rem; }
.offering-hero__stamp small { color: var(--text-dim); font-size: .65rem; }
.course-detail-hero__media-label { left: 1rem; right: auto; bottom: 1rem; border-radius: 999px; font-size: .72rem; font-weight: 700; }
.course-detail-hero__fallback { padding: 2rem; text-align: center; color: var(--detail-accent); }
.course-detail-hero__fallback span { position: relative; z-index: 1; }
.course-detail-hero__fallback strong { position: absolute; z-index: 1; bottom: 2rem; left: 2rem; right: 2rem; color: var(--text); font-size: var(--fs-lg); }

.detail-facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 1rem 1rem 0 0;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
}
.detail-facts > div { display: grid; gap: .3rem; padding: 1.15rem clamp(1rem, 2.5vw, 1.6rem); }
.detail-facts > div + div { border-left: 1px solid var(--line); }
.detail-facts span { color: var(--text-dim); font-size: .66rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.detail-facts strong { font-size: var(--fs-sm); }
.course-facts { grid-template-columns: repeat(4, 1fr); }
.course-instructor { display: flex; align-items: center; gap: .7rem; margin-top: 1.6rem; }
.course-instructor > span:last-child { display: grid; }
.course-instructor small { color: var(--text-dim); font-size: .68rem; }
.course-instructor strong { font-size: var(--fs-sm); }

.detail-body { padding-top: clamp(3.5rem, 7vw, 6.5rem); }
.offering-layout,
.course-detail-layout { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: clamp(2.5rem, 6vw, 5.75rem); align-items: start; }
.offering-content,
.course-detail-content { min-width: 0; }
.detail-section + .detail-section { margin-top: clamp(3.75rem, 8vw, 7rem); }
.detail-section > h2,
.detail-deliverables h2 { max-width: 19ch; margin-top: .65rem; font-size: clamp(1.65rem, 3vw, 2.5rem); line-height: 1.12; letter-spacing: -.035em; }
.section-kicker { color: var(--detail-accent, var(--accent-ink)); font-size: .7rem; font-weight: 750; letter-spacing: .11em; text-transform: uppercase; }
.detail-prose { max-width: 760px; margin-top: 1.5rem; color: var(--text-muted); }
.detail-feature-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; margin-top: 1.75rem; }
.detail-feature { position: relative; display: grid; grid-template-columns: auto 1fr; align-items: center; gap: .8rem; min-height: 116px; padding: 1.15rem; overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.detail-feature::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--detail-accent); transform: scaleY(0); transform-origin: bottom; transition: transform var(--dur-fast) var(--ease-out); }
.detail-feature:hover { border-color: color-mix(in srgb, var(--detail-accent) 30%, var(--line)); transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.detail-feature:hover::before { transform: scaleY(1); }
.detail-feature__number { position: absolute; right: .8rem; bottom: -.15rem; color: color-mix(in srgb, var(--text) 5%, transparent); font-size: 3.4rem; font-weight: 800; line-height: 1; }
.detail-feature__check { position: relative; z-index: 1; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 10%, var(--surface)); }
.detail-feature p { position: relative; z-index: 1; align-self: center; margin: 0; padding-right: 1rem; font-size: var(--fs-sm); font-weight: 600; line-height: 1.55; }
.detail-process { margin-top: 1.8rem; border-top: 1px solid var(--line); }
.detail-process article { display: grid; grid-template-columns: 48px 1fr; gap: 1rem; padding: 1.35rem 0; border-bottom: 1px solid var(--line); }
.detail-process article > span { color: var(--detail-accent); font: 700 .7rem/1 var(--font-mono, monospace); }
.detail-process h3 { font-size: var(--fs-md); }
.detail-process p { margin-top: .35rem; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.65; }
.detail-deliverables { display: grid; grid-template-columns: .8fr 1.2fr; gap: 2rem; margin-top: clamp(3.75rem, 8vw, 7rem); padding: clamp(1.5rem, 4vw, 2.5rem); border: 1px solid color-mix(in srgb, var(--detail-accent) 25%, var(--line)); border-radius: var(--r-lg); background: color-mix(in srgb, var(--detail-accent) 5%, var(--surface)); }
.detail-deliverables ul { display: grid; grid-template-columns: repeat(2, 1fr); gap: .7rem; }
.detail-deliverables li { display: flex; gap: .55rem; align-items: center; padding: .7rem; border-radius: var(--r-sm); background: var(--bg); font-size: var(--fs-sm); }
.detail-deliverables li svg { color: var(--detail-accent); flex-shrink: 0; }
.detail-rail,
.course-enrol { position: sticky; top: calc(var(--nav-h) + 1.25rem); }
.detail-cta,
.course-enrol__card { padding: 1.5rem; border: 1px solid color-mix(in srgb, var(--detail-accent) 30%, var(--line)); border-radius: var(--r-lg); background: var(--surface); box-shadow: 0 22px 55px rgba(0,0,0,.07); }
.detail-cta h2 { margin-top: .6rem; font-size: var(--fs-xl); line-height: 1.2; }
.detail-cta > p { margin: .85rem 0 1.35rem; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.65; }
.detail-cta__facts { margin-top: 1.4rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.detail-cta__facts > div { display: flex; justify-content: space-between; gap: 1rem; padding: .45rem 0; font-size: .74rem; }
.detail-cta__facts dt { color: var(--text-dim); }
.detail-cta__facts dd { color: var(--text); font-weight: 650; text-align: right; }
.detail-contact { display: grid; gap: .45rem; margin-top: .9rem; padding: 1.15rem; border: 1px solid var(--line); border-radius: var(--r-md); }
.detail-contact strong { font-size: var(--fs-sm); }
.detail-contact p { margin-bottom: .3rem; color: var(--text-dim); font-size: .73rem; line-height: 1.5; }
.detail-contact a { display: flex; align-items: center; gap: .45rem; color: var(--text-muted); font-size: .74rem; }
.detail-contact a:hover { color: var(--detail-accent, var(--accent-ink)); }
.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 1rem; margin-bottom: 1.6rem; }
.section-heading h2 { margin-top: .35rem; }

/* Course-specific detail components. */
.course-outcomes { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; margin-top: 1.75rem; }
.course-outcomes article { display: flex; align-items: center; gap: .85rem; min-height: 100px; padding: 1.1rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.course-outcomes article > span { display: grid; place-items: center; flex: 0 0 28px; height: 28px; border-radius: 50%; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 10%, var(--surface)); }
.course-outcomes p { margin: 0; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.55; }
.curriculum-heading { display: flex; align-items: end; justify-content: space-between; gap: 1rem; margin-bottom: 1.35rem; }
.curriculum-heading > span { color: var(--text-dim); font-size: .72rem; }
.curriculum--detail .curriculum__module { border-radius: .85rem; margin-bottom: .65rem; }
.curriculum--detail .curriculum__head { display: grid; grid-template-columns: 38px minmax(0, 1fr) auto 22px; padding: 1.1rem; }
.curriculum__index { display: grid; place-items: center; width: 34px; height: 34px; border-radius: .55rem; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 9%, var(--surface)); font-size: .72rem; font-weight: 750; }
.curriculum__title { display: grid; }
.curriculum__title small { color: var(--text-dim); font-size: .62rem; text-transform: uppercase; letter-spacing: .08em; }
.curriculum__title strong { overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-sm); }
.curriculum__count { color: var(--text-dim); font-size: .68rem; white-space: nowrap; }
.curriculum--detail .curriculum__lesson > span:nth-child(2) { flex: 1; }
.detail-section__intro { max-width: 62ch; margin-top: .9rem; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.65; }
.course-requirements { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; margin-top: 1.5rem; }
.course-requirements article { display: flex; align-items: center; gap: .9rem; min-height: 94px; padding: 1rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.course-requirements__icon { display: grid; place-items: center; flex: 0 0 34px; height: 34px; border-radius: .65rem; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 10%, var(--surface)); }
.course-requirements article > div { display: grid; gap: .22rem; }
.course-requirements small { color: var(--text-dim); font-size: .62rem; font-weight: 750; letter-spacing: .08em; }
.course-requirements strong { color: var(--text); font-size: var(--fs-sm); line-height: 1.4; }
.detail-faq { margin-top: 1.4rem; }
.detail-faq .accordion__item { overflow: hidden; margin-bottom: .7rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
.detail-faq .accordion__item.is-open { border-color: color-mix(in srgb, var(--detail-accent) 35%, var(--line)); box-shadow: 0 10px 32px color-mix(in srgb, var(--detail-accent) 7%, transparent); }
.detail-faq .accordion__trigger { min-height: 68px; padding: 1rem 1.1rem; font-size: var(--fs-sm); font-weight: 700; }
.detail-faq .accordion__trigger > span:first-child { display: flex; align-items: center; gap: .75rem; text-align: left; }
.detail-faq .accordion__trigger small { color: var(--detail-accent); font-size: .62rem; letter-spacing: .08em; }
.detail-faq .accordion__icon { display: grid; place-items: center; flex: 0 0 30px; height: 30px; border: 1px solid var(--line); border-radius: 50%; }
.detail-faq .accordion__panel { visibility: hidden; opacity: 0; transition: grid-template-rows var(--dur) var(--ease-out), opacity var(--dur-fast) var(--ease-out), visibility 0s linear var(--dur); }
.detail-faq .accordion__item.is-open .accordion__panel { visibility: visible; opacity: 1; transition-delay: 0s; }
.detail-faq .accordion__panel > div { padding: 0 3.3rem; }
.detail-faq .accordion__item.is-open .accordion__panel > div { padding-bottom: 1.25rem; }
.detail-faq .accordion__panel .prose { color: var(--text-muted); line-height: 1.7; }
.course-enrol__price { display: flex; align-items: baseline; gap: .6rem; margin-top: .7rem; }
.course-enrol__price strong { font-size: clamp(2rem, 4vw, 2.7rem); letter-spacing: -.04em; }
.course-enrol__price del { color: var(--text-dim); font-size: var(--fs-sm); }
.course-enrol__saving { display: inline-flex; margin-top: .35rem; padding: .28rem .55rem; border-radius: 999px; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 10%, var(--surface)); font-size: .68rem; font-weight: 700; }
.course-enrol__payment { margin-top: .8rem; color: var(--text-muted); font-size: .75rem; line-height: 1.55; }
.course-enrol__actions { margin-top: 1.25rem; }
.course-enrol__includes { margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--line); }
.course-enrol__includes > strong { font-size: .76rem; }
.course-enrol__includes ul { display: grid; gap: .65rem; margin-top: .8rem; }
.course-enrol__includes li { display: flex; gap: .55rem; align-items: center; color: var(--text-muted); font-size: .74rem; }
.course-enrol__includes svg { color: var(--detail-accent); }
.course-enrol a:not(.btn) { color: var(--detail-accent); }

/* Live class detail. */
.training-status-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.training-status-row span { display: inline-flex; align-items: center; gap: .4rem; padding: .42rem .7rem; border: 1px solid color-mix(in srgb, var(--detail-accent) 28%, var(--line)); border-radius: 999px; color: var(--text-muted); background: color-mix(in srgb, var(--detail-accent) 7%, var(--surface)); font-size: .7rem; font-weight: 700; }
.training-status-row .is-closed { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 30%, var(--line)); background: color-mix(in srgb, var(--danger) 7%, var(--surface)); }
.training-logistics { display: grid; grid-template-columns: repeat(2, 1fr); gap: .85rem; margin-top: 1.5rem; }
.training-logistics > article { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: .9rem; min-height: 260px; padding: 1.25rem; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); }
.training-logistics__icon { display: grid; place-items: center; width: 42px; height: 42px; border-radius: .75rem; color: var(--detail-accent); background: color-mix(in srgb, var(--detail-accent) 10%, var(--surface)); }
.training-logistics small { color: var(--detail-accent); font-size: .64rem; font-weight: 750; letter-spacing: .09em; text-transform: uppercase; }
.training-logistics h3 { margin-top: .35rem; font-size: var(--fs-md); }
.training-logistics p { margin-top: .8rem; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.65; }
.training-logistics a { display: inline-flex; align-items: center; gap: .35rem; margin-top: 1rem; color: var(--detail-accent); font-size: .75rem; font-weight: 700; }
.training-logistics dl { display: grid; gap: .1rem; margin-top: .75rem; }
.training-logistics dl > div { display: flex; justify-content: space-between; gap: .8rem; padding: .55rem 0; border-bottom: 1px solid var(--line); font-size: .73rem; }
.training-logistics dt { color: var(--text-dim); }
.training-logistics dd { color: var(--text); font-weight: 650; text-align: right; }
.training-secure-note { display: inline-flex; align-items: center; gap: .4rem; margin-top: 1rem; color: var(--text-dim); font-size: .68rem; }

@media (max-width: 980px) {
  .offering-hero__grid,
  .course-detail-hero__grid { grid-template-columns: 1fr 320px; gap: 2rem; }
  .offering-layout,
  .course-detail-layout { grid-template-columns: 1fr; }
  .detail-rail,
  .course-enrol { position: static; display: grid; grid-template-columns: minmax(0, 1fr) minmax(260px, .7fr); gap: 1rem; }
  .detail-contact { margin-top: 0; align-content: center; }
}
@media (max-width: 760px) {
  .offering-hero__grid,
  .course-detail-hero__grid { grid-template-columns: 1fr; padding-block: 2.2rem; }
  .offering-hero h1,
  .course-detail-hero h1 { font-size: clamp(2.6rem, 13vw, 4rem); }
  .offering-hero__visual,
  .course-detail-hero__media { min-height: 0; aspect-ratio: 16 / 11; }
  .offering-hero__stamp { right: .75rem; }
  .detail-facts,
  .course-facts { grid-template-columns: repeat(2, 1fr); }
  .detail-facts > div:nth-child(n+3) { border-top: 1px solid var(--line); }
  .detail-facts > div:nth-child(odd) { border-left: 0; }
  .detail-feature-grid,
  .course-outcomes,
  .course-requirements,
  .training-logistics { grid-template-columns: 1fr; }
  .detail-deliverables { grid-template-columns: 1fr; }
  .detail-rail,
  .course-enrol { grid-template-columns: 1fr; }
  .detail-contact { margin-top: 0; }
}
@media (max-width: 520px) {
  .detail-actions { display: grid; }
  .detail-actions .btn { width: 100%; }
  .detail-facts > div { padding: .9rem; }
  .detail-facts strong { font-size: .78rem; }
  .detail-deliverables ul { grid-template-columns: 1fr; }
  .curriculum--detail .curriculum__head { grid-template-columns: 34px minmax(0,1fr) 20px; }
  .curriculum__count { display: none; }
  .section-heading { align-items: start; flex-direction: column; }
}

/* ══════════════════════════════════════════════════════════════════════
   BLOG PUBLICATION SYSTEM
   A warmer editorial surface and clearer story hierarchy, shared by the
   front page, category archives and tag archives. */
.blog-front {
  background:
    radial-gradient(circle at 88% 3%, color-mix(in srgb, var(--accent-500) 11%, transparent), transparent 22rem),
    var(--bg);
}
.blog-masthead {
  overflow: hidden;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
  border: 1px solid var(--line);
  border-radius: 2px;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
}
.blog-masthead .masthead__row { position: relative; padding: clamp(1.35rem, 4vw, 3.25rem); }
.blog-masthead .masthead__row::after {
  content: none;
  position: absolute;
  right: clamp(1rem, 4vw, 3rem);
  top: 50%;
  translate: 0 -50%;
  color: color-mix(in srgb, var(--accent-500) 10%, transparent);
  font-family: var(--font-display);
  font-size: clamp(6rem, 15vw, 12rem);
  font-weight: 800;
  letter-spacing: -.08em;
  line-height: .75;
  pointer-events: none;
}
.blog-masthead__issue { display: block; margin-bottom: .85rem; color: var(--accent-ink); font-size: .68rem; font-weight: 750; letter-spacing: .12em; text-transform: uppercase; }
.blog-masthead .masthead__title { position: relative; z-index: 1; max-width: 14ch; font-size: clamp(2.15rem, 5vw, 3.8rem); line-height: .98; letter-spacing: -.045em; }
.blog-masthead__aside { position: relative; z-index: 1; align-self: end; max-width: 42ch; }
.blog-masthead__aside a { display: inline-flex; align-items: center; gap: .4rem; margin-top: 1rem; color: var(--accent-ink); font-size: .72rem; font-weight: 700; }
.blog-masthead .masthead__bar { padding: .75rem; border: 0; border-top: 1px solid var(--line); background: var(--bg); }
.blog-masthead .topic-row { display: flex; flex-wrap: wrap; gap: .4rem; }
.blog-masthead .topic-row .chip { min-height: 34px; padding-inline: .78rem; border-color: transparent; background: var(--surface); }
.blog-masthead .topic-row .chip.is-active { color: var(--brand-900); background: var(--accent-500); }
.blog-masthead .blog-search { flex: 0 1 280px; }
.blog-masthead .search-field .input { border-color: transparent; background: var(--surface); }

.blog-front .front__grid { gap: clamp(1rem, 2vw, 1.5rem); }
.blog-front .lead { overflow: hidden; border: 1px solid var(--line); border-radius: 2px; background: var(--surface); transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out); }
.blog-front .lead:hover { border-color: var(--text); background: var(--bg); }
.blog-front .lead__media { border: 0; border-bottom: 1px solid var(--line); aspect-ratio: 16 / 7.5; }
.blog-front .lead__copy { padding: clamp(.9rem, 1.8vw, 1.25rem); }
.blog-front .lead__title { max-width: 22ch; font-size: clamp(1.55rem, 2.4vw, 2.05rem); line-height: 1.08; letter-spacing: -.025em; }
.blog-front .front__seconds { gap: .75rem; border: 0; }
.blog-front .second { display: flex; flex-direction: column; min-height: 0; padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 2px; background: var(--surface); }
.blog-front .second:hover { border-color: var(--text); background: var(--bg); }
.blog-front .second__media { position: relative; display: block; aspect-ratio: 16 / 6.5; overflow: hidden; border-bottom: 1px solid var(--line); background: var(--surface-strong); }
.blog-front .second__media img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform 500ms var(--ease-out); }
.blog-front .second:hover .second__media img { transform: scale(1.035); }
.blog-front .second__copy { display: flex; flex: 1; flex-direction: column; padding: clamp(.9rem, 1.7vw, 1.2rem); }
.blog-front .second__title { font-size: clamp(1rem, 1.35vw, 1.18rem); line-height: 1.2; }
.blog-front .second__date { margin-top: auto; padding-top: .8rem; }
.blog-front .front__more { padding: 0; border: 0; background: transparent; }
.blog-front .rule-head { margin-bottom: .75rem; }

.blog-archive-hero { padding-block: clamp(1.25rem, 3vw, 2rem) clamp(2rem, 4vw, 3.25rem); }
.blog-archive-hero__label { display: block; margin-bottom: .65rem; color: var(--accent-ink); font-size: .68rem; font-weight: 750; letter-spacing: .12em; text-transform: uppercase; }
.blog-archive-hero h1 { max-width: 16ch; margin: 0; font-size: clamp(2.25rem, 5vw, 4rem); line-height: 1; letter-spacing: -.045em; }
.blog-archive-hero .lede { max-width: 58ch; }
.blog-archive-hero__topics { margin-top: 1.75rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.blog-archive-hero__topics .topic-row { display: flex; flex-wrap: wrap; gap: .45rem; }
.blog-archive-body > .container > .blog-search { max-width: 420px; margin-bottom: 1.5rem; }
.blog-archive-body { padding-block: clamp(2rem, 4vw, 3.5rem); }
.blog-archive-body .pc-grid { margin-top: 1rem; }
.comment-action-page { background: var(--surface); }
.comment-action-page__shell { max-width: 680px; }
.comment-action-page__shell > h1 { max-width: 14ch; font-size: clamp(2.25rem, 6vw, 4rem); line-height: 1; letter-spacing: -.045em; }
.comment-action-page__form { padding: clamp(1.1rem, 3vw, 1.6rem); border: 1px solid var(--line); border-radius: 2px; background: var(--bg); box-shadow: none; }
.comment-action-page .quoted-comment { border-radius: 2px; background: var(--bg); }

/* Article cards across search, archives and related reading. */
.blog-archive-body .pc,
.article-related .pc,
.blog-front .pc-grid .pc { padding: 0; border: 1px solid var(--line); border-radius: 2px; background: var(--surface); transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out); }
.blog-archive-body .pc:hover,
.article-related .pc:hover,
.blog-front .pc-grid .pc:hover { border-color: var(--text); background: var(--bg); }
.blog-archive-body .pc__media,
.article-related .pc__media,
.blog-front .pc-grid .pc__media { aspect-ratio: 16 / 7.5; border-radius: 0; }
.blog-archive-body .pc__kicker,
.blog-archive-body .pc__title,
.blog-archive-body .pc__foot,
.article-related .pc__kicker,
.article-related .pc__title,
.article-related .pc__foot { margin-inline: 0; }
.blog-archive-body .pc__title,
.article-related .pc__title,
.blog-front .pc-grid .pc__title { font-size: clamp(.98rem, 1.15vw, 1.1rem); line-height: 1.25; }
.blog-archive-body .pc-grid,
.article-related .grid,
.blog-front .front__more .pc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (min-width: 900px) {
  .blog-masthead .masthead__row { grid-template-columns: minmax(0, 1.25fr) minmax(280px, .65fr); min-height: 220px; }
  .blog-front .front__seconds { grid-template-rows: repeat(2, 1fr); align-self: stretch; }
}
@media (min-width: 721px) and (max-width: 1000px) {
  .blog-archive-body .pc-grid,
  .article-related .grid,
  .blog-front .front__more .pc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .blog-masthead { border-radius: 2px; }
  .blog-masthead__aside { max-width: 32ch; }
  .blog-masthead .masthead__bar { align-items: stretch; }
  .blog-masthead .topic-row { flex-wrap: nowrap; width: 100%; padding-bottom: .2rem; overflow-x: auto; scrollbar-width: none; }
  .blog-masthead .topic-row::-webkit-scrollbar { display: none; }
  .blog-masthead .topic-row .chip { flex: 0 0 auto; }
  .blog-masthead .blog-search { flex: 0 0 auto; width: 100%; }
  .blog-masthead .blog-search .search-field { width: 100%; min-width: 0; flex: none; }
  .blog-front .lead__title { font-size: clamp(1.45rem, 6.8vw, 1.9rem); line-height: 1.08; }
  .blog-front .lead__media { aspect-ratio: 16 / 6.5; }
  .blog-front .second__media,
  .blog-archive-body .pc__media,
  .article-related .pc__media,
  .blog-front .pc-grid .pc__media { aspect-ratio: 16 / 6; }
  .blog-archive-hero__topics .topic-row { flex-wrap: wrap; overflow: visible; }
  .blog-archive-body .pc-grid,
  .article-related .grid,
  .blog-front .front__more .pc-grid { grid-template-columns: 1fr; }
}

/* One half of a student + parent verification that has already matched. */
.otp-done {
  display: inline-flex; align-items: center; gap: 0.45rem;
  margin: 0.35rem 0 0; padding: 0.55rem 0.8rem;
  border-radius: var(--r-sm); background: var(--success-bg);
  color: var(--success); font-weight: 600; font-size: var(--fs-sm);
}

/* ===========================================================================
   Service plans — read like a printed price list, not a SaaS pricing table.
   The price sits above a tear line; add-ons are a menu with dotted leaders.
   =========================================================================== */
.plans { border-top: 1px solid var(--line); background: var(--bg-alt); }
.plans__head {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(1rem, 4vw, 3.5rem); align-items: end; margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}
.plans__head h2 { margin-top: .5rem; font-size: var(--fs-3xl); line-height: var(--lh-snug); text-wrap: balance; }
.plans__how { margin: 0; max-width: 52ch; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.65; text-wrap: pretty; }

.plans__grid {
  display: grid; gap: 1rem; align-items: stretch;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
}
.plan {
  position: relative; display: flex; flex-direction: column;
  padding: 1.5rem 1.35rem 1.35rem; border: 1px solid var(--line-strong);
  border-radius: var(--r-md); background: var(--surface-solid);
}
.plan--featured {
  border-color: var(--detail-accent, var(--accent-500));
  box-shadow: 0 0 0 1px var(--detail-accent, var(--accent-500)), var(--shadow-md);
}
.plan__flag {
  position: absolute; top: -.7rem; left: 1.35rem; padding: .2rem .6rem;
  border-radius: var(--r-xs); background: var(--detail-accent, var(--accent-500)); color: #fff;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  white-space: nowrap;
}
.plan__name { font-family: var(--font-display); font-size: var(--fs-lg); letter-spacing: var(--tracking-tight); }
.plan__tagline { margin: .35rem 0 0; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.5; text-wrap: pretty; }

.plan__price {
  display: grid; gap: .15rem; margin: 1.1rem 0 0; padding-bottom: 1.1rem;
  border-bottom: 1px dashed var(--line-strong);
}
.plan__price strong {
  font-family: var(--font-display); font-size: var(--fs-2xl); line-height: 1.05;
  letter-spacing: var(--tracking-tight); font-variant-numeric: tabular-nums;
}
.plan__price span { color: var(--text-dim); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }

.plan__terms { display: grid; gap: .4rem; margin: 1rem 0 0; }
.plan__terms > div { display: flex; justify-content: space-between; gap: 1rem; font-size: var(--fs-sm); }
.plan__terms dt { color: var(--text-dim); }
.plan__terms dd { margin: 0; font-weight: 600; text-align: right; }

.plan__features { display: grid; gap: .55rem; margin: 1.1rem 0 1.4rem; padding: 0; list-style: none; }
.plan__features li { display: grid; grid-template-columns: 15px 1fr; gap: .6rem; font-size: var(--fs-sm); line-height: 1.5; }
.plan__features svg { margin-top: .2rem; color: var(--detail-accent, var(--accent-600)); }
.plan__included { color: var(--text-muted); }
.plan__cta { margin-top: auto; }

.addons {
  display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.6fr);
  gap: clamp(1rem, 4vw, 3rem); margin-top: clamp(2rem, 5vw, 3.25rem);
  padding-top: clamp(1.5rem, 4vw, 2.25rem); border-top: 1px solid var(--line);
}
.addons__head h3 { font-family: var(--font-display); font-size: var(--fs-xl); }
.addons__head p { margin: .5rem 0 0; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.6; max-width: 36ch; }
.addons__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 2rem; margin: 0; padding: 0; list-style: none; }
.addon {
  display: flex; align-items: baseline; gap: .75rem; padding: .85rem 0;
  border-bottom: 1px solid var(--line);
}
.addon__text { display: grid; gap: .15rem; min-width: 0; flex: 0 1 auto; }
.addon__text strong { font-size: var(--fs-sm); }
.addon__text span { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; }
/* The dotted leader: the gap between name and price, drawn. Baseline
   alignment puts it on the name's line even when a description wraps below. */
.addon__leader { flex: 1 1 1.5rem; min-width: 1.5rem; border-bottom: 2px dotted var(--line-strong); }
.addon__price {
  flex: 0 0 auto; font-family: var(--font-display); font-weight: 600;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.addon__price small { color: var(--text-dim); font-family: var(--font-body); font-weight: 400; font-size: var(--fs-2xs); }

.plans__custom {
  display: grid; grid-template-columns: auto 1fr auto; gap: 1.1rem 1.25rem; align-items: center;
  margin-top: clamp(2rem, 5vw, 3rem); padding: 1.35rem 1.5rem;
  border: 1px dashed var(--line-strong); border-radius: var(--r-md);
}
.plans__custom-icon {
  display: grid; place-items: center; width: 46px; height: 46px; border-radius: var(--r-sm);
  background: var(--surface-strong); color: var(--detail-accent, var(--accent-600));
}
.plans__custom h3 { font-size: var(--fs-md); }
.plans__custom p { margin: .3rem 0 0; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.6; max-width: 62ch; }

@media (max-width: 860px) {
  .plans__head, .addons { grid-template-columns: 1fr; }
  .addons__list { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  .plans__custom { grid-template-columns: 1fr; }
  .plans__custom-icon { display: none; }
  .plans__custom .btn { width: 100%; }
}

/* ── Plan order: choices on the left, a running estimate on the right ──── */
.order { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); gap: 1.25rem; align-items: start; }
.order__side { position: sticky; top: calc(var(--console-top, 72px) + 1rem); display: grid; gap: 1rem; }
.order__step {
  display: inline-grid; place-items: center; width: 1.5rem; height: 1.5rem; margin-right: .4rem;
  border-radius: 50%; background: var(--surface-strong); font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
}
.order-addon {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1rem 1.25rem; border-top: 1px solid var(--line);
}
.order-addon:first-child { border-top: 0; }
.order-addon__text { display: grid; gap: .2rem; min-width: 0; }
.order-addon__text strong { font-size: var(--fs-sm); }
.order-addon__text span { color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.5; }
.order-addon__pick, .order-addon__qty { display: flex; align-items: center; gap: .65rem; flex: 0 0 auto; cursor: pointer; }
.order-addon__pick input { width: 20px; height: 20px; accent-color: var(--accent-600); }
.order-addon__qty .input { width: 4.5rem; text-align: center; font-variant-numeric: tabular-nums; }
.order-addon__price { font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.order-addon__price small { color: var(--text-dim); font-weight: 400; }
.order-addon:has(input:checked), .order-addon:has(input[type="number"]:not([value="0"])) { background: var(--surface); }
.order-addon.is-included { opacity: .85; }

.order-summary__lines { display: grid; gap: .6rem; margin: 0; }
.order-summary__lines > div { display: flex; justify-content: space-between; gap: 1rem; font-size: var(--fs-sm); }
.order-summary__lines dt { color: var(--text-muted); }
.order-summary__lines dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.order-summary__total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--line-strong);
}
.order-summary__total span { font-size: var(--fs-sm); font-weight: 600; }
.order-summary__total strong { font-family: var(--font-display); font-size: var(--fs-xl); text-align: right; font-variant-numeric: tabular-nums; }
.order-summary__note { margin: .75rem 0 1.25rem; color: var(--text-dim); font-size: var(--fs-xs); line-height: 1.6; }

.order-next { display: grid; gap: 0; margin: 0; padding: 0 0 0 .25rem; list-style: none; counter-reset: next; }
.order-next li {
  position: relative; display: grid; gap: .1rem; padding: 0 0 1rem 1.6rem; counter-increment: next;
  border-left: 1px solid var(--line-strong); margin-left: .45rem;
}
.order-next li:last-child { border-left-color: transparent; padding-bottom: 0; }
.order-next li::before {
  content: ""; position: absolute; left: -.4rem; top: .2rem; width: .75rem; height: .75rem;
  border-radius: 50%; border: 2px solid var(--line-strong); background: var(--bg);
}
.order-next li:first-child::before { border-color: var(--accent-500); background: var(--accent-500); }
.order-next strong { font-size: var(--fs-sm); }
.order-next span { color: var(--text-dim); font-size: var(--fs-xs); }

/* ── The agreement: a document first, a form second ─────────────────────── */
.agreement-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); gap: 1.25rem; align-items: start; }
.agreement-side { position: sticky; top: calc(var(--console-top, 72px) + 1rem); display: grid; gap: 1rem; }
.agreement {
  padding: clamp(1.35rem, 4vw, 2.75rem); border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--surface-solid); box-shadow: var(--shadow-sm);
}
.agreement__head { padding-bottom: 1.35rem; margin-bottom: .5rem; border-bottom: 2px solid var(--text); }
.agreement__kicker { color: var(--accent-ink); font-size: var(--fs-2xs); font-weight: 700; letter-spacing: var(--tracking-wide); text-transform: uppercase; }
.agreement__head h2 { margin-top: .4rem; font-size: var(--fs-2xl); line-height: var(--lh-snug); text-wrap: balance; }
.agreement__money { display: flex; flex-wrap: wrap; gap: .75rem 2.5rem; margin: 1.1rem 0 0; }
.agreement__money dt { color: var(--text-dim); font-size: var(--fs-xs); }
.agreement__money dd { margin: .1rem 0 0; font-family: var(--font-display); font-size: var(--fs-lg); font-weight: 600; font-variant-numeric: tabular-nums; }
.agreement__money small { color: var(--text-dim); font-family: var(--font-body); font-size: var(--fs-xs); font-weight: 400; }
.agreement__section { max-width: 68ch; padding-top: 1.35rem; }
.agreement__section h3 { font-size: var(--fs-md); margin-bottom: .5rem; }
.agreement__section p { margin: 0 0 .6rem; color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.7; text-wrap: pretty; }

.sign-card__consent { align-items: flex-start; margin-top: .5rem; font-size: var(--fs-xs); line-height: 1.6; }
.sign-card__consent input { margin-top: .2rem; flex: 0 0 auto; }
.sign-card__name {
  margin: 0; font-family: var(--font-display); font-size: var(--fs-xl); font-style: italic;
  padding-bottom: .4rem; border-bottom: 1px solid var(--line-strong);
}
.sign-card__hash { display: flex; align-items: center; gap: .4rem; margin: 1rem 0 0; color: var(--text-dim); font-size: var(--fs-2xs); }
.sign-card.is-signed { border-color: var(--success); }

@media (max-width: 980px) {
  .order, .agreement-layout { grid-template-columns: 1fr; }
  .order__side, .agreement-side { position: static; }
}
@media (max-width: 560px) {
  .order-addon { flex-wrap: wrap; }
  .order-addon__pick, .order-addon__qty { width: 100%; justify-content: space-between; }
}

/* ── Expert cards, final word ───────────────────────────────────────────
   Skills wrap as tags so none are hidden, and a person without a photo
   gets their own accent rather than a flat grey slab. */
.ed--person .person__skills {
  display: flex; flex-wrap: wrap; gap: .35rem; margin: .55rem 0 0; padding: 0; list-style: none;
  -webkit-line-clamp: unset; overflow: visible;
}
.ed--person .person__skills li {
  padding: .2rem .5rem; border: 1px solid var(--line); border-radius: var(--r-xs);
  font-family: var(--font-mono); font-size: .64rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted); white-space: nowrap; background: var(--surface-solid);
}
.ed--person .person__bio { -webkit-line-clamp: 4; max-width: 44ch; }
.ed--person .person__frame:has(.person__initials) {
  background:
    radial-gradient(120% 90% at 20% 10%, color-mix(in srgb, var(--card-accent, var(--brand-400)) 22%, transparent), transparent 70%),
    color-mix(in srgb, var(--card-accent, var(--brand-400)) 8%, var(--surface-solid));
}
.ed--person .person__initials {
  color: color-mix(in srgb, var(--card-accent, var(--brand-400)) 70%, var(--text));
  font-size: clamp(2.6rem, 5vw, 3.6rem); letter-spacing: -.02em;
}

/* ── Testimonials: "In their words" ─────────────────────────────────────
   Typeset like a pull-quote: a hanging quotation mark in the margin, the
   source as a label, the person underneath. One or two voices fill the row
   rather than leaving a lone card beside an empty rail. */
.voice {
  flex: 0 0 min(420px, calc(100vw - var(--gutter-safe) * 2 - var(--sp-6)));
  scroll-snap-align: start;
  display: flex; flex-direction: column; margin: 0;
  padding: clamp(1.25rem, 2.4vw, 1.75rem);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-solid);
}
.voice__top { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.voice__tag {
  font-family: var(--font-mono); font-size: .64rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent-ink); padding: .2rem .5rem; border: 1px solid var(--line-accent); border-radius: var(--r-xs);
}
.voice__top .stars { margin-left: auto; }
.voice__quote { position: relative; flex: 1; margin: 1.1rem 0 0; padding-left: 1.35rem; }
.voice__quote::before {
  content: "\201C"; position: absolute; left: -.1rem; top: -.35rem;
  font-family: var(--font-display); font-size: 2.6rem; line-height: 1; color: var(--accent-500);
}
.voice__quote p { margin: 0; font-size: var(--fs-md); line-height: 1.62; color: var(--text); text-wrap: pretty; }
.voice__by {
  display: flex; align-items: center; gap: .85rem;
  margin-top: 1.35rem; padding-top: 1rem; border-top: 1px dashed var(--line-strong);
}
.voice__avatar {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center; background: var(--surface-strong);
  font-family: var(--font-display); font-weight: 700; font-size: .85rem; color: var(--text-muted);
  box-shadow: 0 0 0 2px var(--surface-solid), 0 0 0 3px var(--line-accent);
}
.voice__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.voice__who { display: grid; gap: .1rem; min-width: 0; }
.voice__who strong { font-size: var(--fs-sm); }
.voice__who span { color: var(--text-dim); font-size: var(--fs-xs); }
.voice__who em { font-style: normal; color: var(--accent-ink); font-size: var(--fs-xs); font-weight: 600; }

.testimonial-rail.is-few, .testimonial-rail.is-single {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  overflow: visible; margin-inline: 0; padding-inline: 0;
}
.testimonial-rail.is-few .voice, .testimonial-rail.is-single .voice { flex: none; }
/* One voice: a pull-quote across the width, the person beside it. */
@media (min-width: 860px) {
  .testimonial-rail.is-single .voice {
    display: grid; grid-template-columns: minmax(0, 1fr) 240px; grid-template-rows: auto 1fr;
    column-gap: clamp(2rem, 5vw, 4rem); padding: clamp(1.75rem, 3.5vw, 2.75rem);
  }
  .testimonial-rail.is-single .voice__top { grid-column: 1 / -1; }
  .testimonial-rail.is-single .voice__quote p {
    font-family: var(--font-display); font-size: var(--fs-xl); line-height: 1.4; letter-spacing: -.01em;
  }
  .testimonial-rail.is-single .voice__quote { padding-left: 2.1rem; }
  .testimonial-rail.is-single .voice__quote::before { font-size: 3.4rem; top: -.55rem; }
  .testimonial-rail.is-single .voice__by {
    flex-direction: column; align-items: flex-start; align-self: end;
    margin: 0; padding: 0 0 0 1.5rem; border-top: 0; border-left: 1px dashed var(--line-strong);
  }
  .testimonial-rail.is-single .voice__avatar { flex-basis: 56px; width: 56px; height: 56px; }
}

/* ── Compact post cards (landing page) ──────────────────────────────────
   Thumbnail beside the headline: about a third of the full card's height. */
.pc-compact-row {
  display: grid; gap: clamp(.75rem, 1.2vw, 1rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
}
.pc.pc--compact {
  display: grid; grid-template-columns: 96px minmax(0, 1fr); grid-template-rows: auto 1fr auto;
  column-gap: .9rem; row-gap: .3rem; padding: .7rem; align-items: start;
}
.pc--compact .pc__media {
  grid-row: 1 / -1; aspect-ratio: 1 / 1; border: 0; border-radius: 2px; align-self: stretch; height: 100%; max-height: 110px;
}
.pc--compact .pc__initials { font-size: 1.3rem; }
.pc--compact .pc__kicker { padding: 0; }
.pc--compact .pc__title { padding: 0; font-size: var(--fs-sm); line-height: 1.3; text-wrap: pretty;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.pc--compact .pc__foot { padding: 0; margin-top: .2rem; }
