/* Well Made Plays · services site
   Editorial system: warm paper, ink, letterpress vermilion, type-led.
   No external requests. Fonts are self-hosted latin subsets (SIL OFL,
   licenses in /assets/fonts/). */

/* ---------------------------------------------------------------- fonts */

@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-normal-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-italic-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/inter-normal-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------- tokens */

:root {
  --paper: #F6F1E6;
  --paper-deep: #EDE5D2;
  --ink: #211C15;
  --ink-soft: #4A4238;
  --muted: #675E50;
  --line: #D8CDB6;
  --line-strong: #B9AC90;
  --vermilion: #A03A16;
  --vermilion-text: #8F3413;
  --blue: #244A55;
  --blue-soft: #E2E9E6;

  --serif: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, sans-serif;

  --step--1: 0.82rem;
  --step-0: 1.0625rem;   /* 17px */
  --step-1: 1.28rem;
  --step-2: 1.7rem;
  --step-3: 2.26rem;
  --step-4: 3.2rem;

  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.75rem;
  --space-4: 3rem;
  --space-5: 5rem;

  --wrap: 1120px;
  --radius: 4px;

  /* Editorial / letterpress refinements. Additive only: the five linted
     color roles above are unchanged, so AA contrast still holds. */
  --step-5: 3.5rem;
  --press: 8px 8px 0 rgba(33, 28, 21, 0.08);
  /* Interactive control borders carry meaning (they show the field exists),
     so WCAG 1.4.11 needs 3:1 against the field fill. --line-strong is 2.17:1
     and is used site-wide for decorative hairlines; these are separate. */
  --field-bg: #FDFBF5;
  --field-line: #8E8067;
  --select: color-mix(in srgb, var(--vermilion) 20%, var(--paper));
}

/* ----------------------------------------------------------------- base */

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  color: var(--ink);
  background-color: var(--paper);
  /* Static grain: small tile, background-repeat, never fixed attachment. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.13 0 0 0 0 0.11 0 0 0 0 0.08 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
  font-family: var(--sans);
  font-size: var(--step-0);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-optical-sizing: auto;
}

::selection { background: var(--select); color: var(--ink); }

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 560;
  line-height: 1.08;
  letter-spacing: 0;
  margin: 0 0 var(--space-2);
  color: var(--ink);
  font-optical-sizing: auto;
}
h1 { font-size: clamp(2.55rem, 5.2vw, var(--step-5)); max-width: 19ch; text-wrap: balance; letter-spacing: -0.012em; }
h2 { font-size: var(--step-3); max-width: 26ch; text-wrap: balance; }
h3 { font-size: var(--step-1); line-height: 1.2; }
@media (max-width: 700px) {
  h1 { font-size: 2.48rem; }
  h2 { font-size: 1.9rem; }
}

p { margin: 0 0 var(--space-2); max-width: 65ch; }
a { color: inherit; text-underline-offset: 3px; }
ul, ol { padding-left: 1.2rem; }
img { max-width: 100%; display: block; }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding-inline: clamp(1.25rem, 5vw, 3rem);
}

.kicker {
  font-size: var(--step--1);
  font-weight: 620;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  margin-bottom: var(--space-2);
  max-width: 44ch;
  text-wrap: balance;
}

.hero-card-kicker { margin-bottom: var(--space-1); }

.lede { font-size: var(--step-1); line-height: 1.5; color: var(--ink-soft); max-width: 46ch; text-wrap: pretty; }
.fine { font-size: var(--step--1); color: var(--muted); }

/* Line breaking. Headings are short enough to balance, so their lines come out
   even instead of leaving one word stranded. Body copy uses pretty, which only
   reflows the last couple of lines to avoid an orphan and leaves long
   paragraphs alone. An audit at 1280 and 375 found stranded words on the home,
   pricing and examples pages; both properties fall back to normal wrapping
   where they are not supported. */
h1, h2, h3, .bundle-tag, .pl-group h3 { text-wrap: balance; }
p, li, dd, figcaption, summary { text-wrap: pretty; }


/* Prices and figures align on tabular lining numerals so columns read clean. */
.hero-card-price,
.proof-grid b,
.menu-price b,
.bundle-figure b,
.ala-price,
.stat-item strong { font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------- focus + skip */

:focus-visible {
  outline: 2.5px solid var(--vermilion);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 100;
  background: var(--ink);
  color: var(--paper);
  padding: 0.6rem 1rem;
}
.skip:focus { left: 0; }

/* -------------------------------------------------------------- buttons */

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.96rem;
  text-decoration: none;
  text-align: center;
  padding: 0.85rem 1.5rem;
  border: 1.5px solid var(--ink);
  border-radius: var(--radius);
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  cursor: pointer;
}
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--vermilion); border-color: var(--vermilion); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { border-color: var(--vermilion); color: var(--vermilion-text); }
.btn-sm { padding: 0.55rem 1rem; font-size: 0.88rem; }
.btn-block { display: block; width: 100%; }
.btn:active { transform: translateY(1px); }

/* ------------------------------------------------------------------ nav */

.nav {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.nav-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 64px;
}
.wordmark {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
}
.wordmark .mark { color: var(--ink); flex: none; }
.wordmark-text {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.14rem;
  letter-spacing: 0;
  line-height: 1;
}
.wordmark-text small {
  display: block;
  font-family: var(--sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.3rem;
}
.nav-links { display: flex; align-items: center; gap: 1.4rem; margin-left: auto; }
.nav-links a { text-decoration: none; font-size: 0.94rem; font-weight: 550; color: var(--ink-soft); }
.nav-links a:hover { color: var(--vermilion-text); }
.nav-book { flex: none; }
.nav-cta-extra { display: none; }
@media (min-width: 640px) {
  .nav-cta-extra { display: inline; }
}
/* Under 900px the nav wraps to two rows: wordmark and Book on top, the
   tabs on their own full-width row below. Nothing is hidden. */
@media (max-width: 899px) {
  .nav-in { flex-wrap: wrap; min-height: 0; padding-block: 0.6rem 0.5rem; row-gap: 0.1rem; }
  .wordmark { order: 1; }
  .nav-book { order: 2; margin-left: auto; }
  .nav-links {
    order: 3;
    flex-basis: 100%;
    margin-left: 0;
    flex-wrap: wrap;
    gap: 0.15rem 1.15rem;
  }
  .nav-links a { font-size: 0.9rem; padding-block: 0.3rem; }
}
@media (max-width: 480px) {
  .nav-in { gap: 0.75rem; }
  .wordmark-text { font-size: 1rem; }
  .wordmark-text small { display: none; }
  .nav-book { padding-inline: 0.85rem; }
}
/* Anchor jumps must land clear of the sticky nav. */
html { scroll-padding-top: 84px; }
@media (max-width: 899px) {
  html { scroll-padding-top: 104px; }
}
@media (max-width: 460px) {
  html { scroll-padding-top: 148px; }
}

/* ----------------------------------------------------------------- hero */

.hero { padding-block: clamp(3rem, 8vw, 6rem) clamp(2.5rem, 6vw, 4.5rem); }
.hero-grid { display: grid; gap: var(--space-4); align-items: start; }
@media (min-width: 900px) {
  .hero-grid { grid-template-columns: 1.2fr 0.8fr; gap: var(--space-5); }
}
.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin-top: var(--space-3); }

.hero-card {
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--paper-deep);
  padding: var(--space-3);
  box-shadow: var(--press);
  max-width: 26rem;
}
/* Route B hero: poster-scale headline + tipped-in duotone plate.
   The plate is a real img (preloaded via fetchpriority) so LCP improves;
   text never sits on the photo, so AA stays a token question only. */
.hero h1 {
  font-size: clamp(2.7rem, 6vw, 4.4rem);
  line-height: 1.04;
  letter-spacing: -0.015em;
  max-width: 15ch;
}
.h1-accent { color: var(--vermilion-text); }
.hero-right { position: relative; }
.hero-plate { display: none; }
@media (min-width: 900px) {
  .hero-plate {
    display: block;
    position: absolute;
    top: -1.25rem;
    right: -1rem;
    bottom: -1.25rem;
    left: 1.75rem;
    border: 2px solid var(--ink);
    border-radius: var(--radius);
    box-shadow: var(--press);
    overflow: hidden;
  }
  .hero-plate img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .hero-right .hero-card { position: relative; z-index: 1; margin: 2.25rem 2.5rem 1.25rem 0; }
}

.hero-card-name { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); margin-bottom: 0.2rem; }
.hero-card-price { font-family: var(--serif); font-weight: 600; font-size: var(--step-3); margin: 0 0 var(--space-1); }
.hero-card-note { font-size: 0.94rem; color: var(--ink-soft); margin-bottom: var(--space-2); }
.hero-card-free { font-size: var(--step--1); color: var(--muted); margin: var(--space-2) 0 0; }

/* ----------------------------------------------------------- proof strip */

.proof-strip {
  padding-block: 0 var(--space-3);
}
.proof-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-block: 1px solid var(--line);
  background: color-mix(in srgb, var(--blue-soft) 45%, transparent);
}
.proof-grid p {
  margin: 0;
  padding: var(--space-2);
  border-right: 1px solid var(--line);
}
.proof-grid p:last-child { border-right: 0; }
.proof-grid b {
  display: block;
  font-family: var(--serif);
  font-size: var(--step-2);
  font-weight: 650;
  line-height: 1;
  color: var(--blue);
  margin-bottom: 0.45rem;
}
.proof-grid span {
  display: block;
  color: var(--ink-soft);
  font-size: 0.92rem;
  line-height: 1.42;
}
@media (max-width: 760px) {
  .proof-grid { grid-template-columns: 1fr 1fr; }
  .proof-grid p:nth-child(2) { border-right: 0; }
  .proof-grid p:nth-child(-n + 2) { border-bottom: 1px solid var(--line); }
  /* Odd tile counts: the last tile takes the full row instead of leaving
     an empty cell beside it. */
  .proof-grid p:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: 0; }
}
@media (max-width: 420px) {
  .proof-grid { grid-template-columns: 1fr; }
  .proof-grid p,
  .proof-grid p:nth-child(2) { border-right: 0; }
  .proof-grid p:not(:last-child) { border-bottom: 1px solid var(--line); }
}

/* --------------------------------------------------- section grid + rail */

section { padding-block: clamp(2.5rem, 6vw, 4.5rem); }

.sec-grid { display: grid; gap: var(--space-2); }
@media (min-width: 960px) {
  .sec-grid { grid-template-columns: 10rem minmax(0, 1fr); gap: var(--space-4); }
  .sec-label { position: sticky; top: 88px; }
}
.sec-label {
  font-size: var(--step--1);
  font-weight: 620;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  border-top: 2px solid var(--vermilion);
  padding-top: 0.6rem;
  margin: 0;
  height: fit-content;
}
.sec-intro { color: var(--ink-soft); max-width: 56ch; }
/* Price anchor above the menu: sets the cost comparison before the first
   figure is read, so it carries slightly more weight than a section intro. */
.menu-anchor {
  font-family: var(--serif);
  font-size: var(--step-1);
  line-height: 1.4;
  max-width: 52ch;
  margin-bottom: var(--space-2);
}
.sec-body > h2 { margin-bottom: var(--space-2); }

/* ------------------------------------------------------------- practice */

.positioning { font-size: var(--step-1); line-height: 1.55; color: var(--ink-soft); max-width: 58ch; }

.promises {
  display: grid;
  gap: var(--space-2) var(--space-3);
  margin: var(--space-3) 0 0;
}
@media (min-width: 700px) { .promises { grid-template-columns: 1fr 1fr; } }
.promise { border-top: 1px solid var(--line); padding-top: var(--space-2); }
.promise dt {
  font-family: var(--serif);
  font-weight: 600;
  font-size: var(--step-1);
  margin-bottom: 0.3rem;
}
.promise dd { margin: 0; color: var(--ink-soft); font-size: 0.97rem; }

/* --------------------------------------------------------------- path */

/* Three entry points across, then the flagship on its own full-width row.
   A two-column grid leaves an empty cell beside the third card, and the
   flagship has to out-weigh its neighbours anyway: it is three to six times
   their price. */
.path-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  margin-top: var(--space-3);
}
@media (min-width: 1000px) {
  .path-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.path-card {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--paper-deep) 70%, transparent);
  padding: var(--space-2);
}
.path-card:nth-child(2):not(.tile-photo),
.path-card:nth-child(3):not(.tile-photo) {
  background: color-mix(in srgb, var(--blue-soft) 68%, transparent);
}
.path-card h3 {
  margin-bottom: 0.55rem;
  max-width: 24ch;
}
.path-card p {
  color: var(--ink-soft);
  font-size: 0.95rem;
}
/* The tiles carry the price ladder, so they have to carry enough substance to
   justify it. The flagship spans the row: at three to six times the price of
   its neighbours it cannot sit in an identical box, or the page reads as four
   interchangeable options and the most valuable one looks overpriced. */
.path-points {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-2);
  font-size: 0.92rem;
}
.path-points li {
  position: relative;
  padding-left: 1.1rem;
  margin-bottom: 0.3rem;
  color: var(--ink-soft);
}
.path-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.42rem;
  height: 1px;
  background: currentColor;
  opacity: 0.75;
}
.path-card-flagship { grid-column: 1 / -1; }
.path-anchor {
  border-top: 1px solid color-mix(in srgb, currentColor 26%, transparent);
  padding-top: var(--space-2);
  margin-top: var(--space-2);
  font-size: 0.92rem;
  max-width: 60ch;
}
@media (min-width: 860px) {
  .path-card-flagship { padding: var(--space-3); }
  .path-card-flagship h3 { font-size: var(--step-2); max-width: 28ch; }
  .path-card-flagship .path-points { columns: 2; column-gap: var(--space-3); }
  .path-card-flagship .path-points li { break-inside: avoid; }
}
.path-card a {
  color: var(--blue);
  font-weight: 700;
  font-size: 0.94rem;
  text-decoration-thickness: 1px;
}

/* -------------------------------------------------------- photo tiles */
/* Path and bundle cards over dark stock photography. CSP forbids inline
   styles; every background lives here as a class. The scrim (::before)
   sits above the photo, below the text, and doubles as the fallback
   surface while the image loads, so cream text is always on dark ink. */

.tile-photo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background-color: var(--ink);
  background-size: cover;
  background-position: center;
  border-color: color-mix(in srgb, var(--ink) 80%, transparent);
}
.tile-photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(33, 28, 21, 0.70), rgba(33, 28, 21, 0.88));
}

/* JPEG first, then the WebP upgrade via image-set. Doubled class keeps
   these above the earlier card-background shorthands in the cascade. */
.tile-photo.tile-direction { background-image: url("/assets/img/tiles/path-direction.jpg"); }
.tile-photo.tile-identity { background-image: url("/assets/img/tiles/path-identity.jpg"); }
.tile-photo.tile-money { background-image: url("/assets/img/tiles/path-money.jpg"); }
.tile-photo.tile-control { background-image: url("/assets/img/tiles/path-control.jpg"); }
.tile-photo.tile-bundle-launch { background-image: url("/assets/img/tiles/bundle-launch.jpg"); }
.tile-photo.tile-bundle-full { background-image: url("/assets/img/tiles/bundle-full.jpg"); }
.tile-photo.tile-direction { background-image: image-set(
  url("/assets/img/tiles/path-direction.webp") type("image/webp"),
  url("/assets/img/tiles/path-direction.jpg") type("image/jpeg")); }
.tile-photo.tile-identity { background-image: image-set(
  url("/assets/img/tiles/path-identity.webp") type("image/webp"),
  url("/assets/img/tiles/path-identity.jpg") type("image/jpeg")); }
.tile-photo.tile-money { background-image: image-set(
  url("/assets/img/tiles/path-money.webp") type("image/webp"),
  url("/assets/img/tiles/path-money.jpg") type("image/jpeg")); }
.tile-photo.tile-control { background-image: image-set(
  url("/assets/img/tiles/path-control.webp") type("image/webp"),
  url("/assets/img/tiles/path-control.jpg") type("image/jpeg")); }
.tile-photo.tile-bundle-launch { background-image: image-set(
  url("/assets/img/tiles/bundle-launch.webp") type("image/webp"),
  url("/assets/img/tiles/bundle-launch.jpg") type("image/jpeg")); }
.tile-photo.tile-bundle-full { background-image: image-set(
  url("/assets/img/tiles/bundle-full.webp") type("image/webp"),
  url("/assets/img/tiles/bundle-full.jpg") type("image/jpeg")); }

/* Roster cards on the about page share the treatment, but the photo is
   the point: cards run taller, text sits at the bottom, and the scrim is
   a bottom-weighted gradient so the artist stays visible up top while the
   text zone (bottom ~30%) is as dark as the standard tiles. */
.roster-card.tile-photo {
  min-height: 360px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Re-assert over .roster-card's background shorthand, which comes later
     in the file than the .tile-photo base and would reset these to auto. */
  background-color: var(--ink);
  background-size: cover;
  background-repeat: no-repeat;
}
.roster-card.tile-photo::before {
  /* Stops measured per-pixel against every crop at both breakpoints:
     text zones clear AA 4.5 while the top third stays photo-clear. */
  background: linear-gradient(180deg,
    rgba(33, 28, 21, 0.14) 0%,
    rgba(33, 28, 21, 0.36) 32%,
    rgba(33, 28, 21, 0.90) 56%,
    rgba(33, 28, 21, 0.94) 100%);
}
.roster-card.tile-photo > :first-child { margin-top: auto; }
.roster-links {
  display: flex;
  gap: 1.1rem;
  margin: 0.55rem 0 0;
  font-size: var(--step--1);
  font-weight: 640;
}
.roster-card.tile-photo .roster-links a {
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.roster-card.tile-photo .roster-links a:hover { color: color-mix(in srgb, var(--paper) 72%, var(--vermilion)); }
/* Sources are pre-cropped around each subject; bias slightly above center
   so faces sit in the clear zone above the text scrim. */
.roster-card.tile-photo { background-position: 50% 30%; }
/* The band shot is landscape: on multi-column layouts its tile spans two
   tracks so all four members stay in frame. Card order (Terra Cognita
   last) keeps every row filled at two and three columns. */
@media (min-width: 760px) {
  .roster-card.tile-photo.tile-roster-tc { grid-column: span 2; background-position: 50% 35%; }
}
.tile-photo.tile-roster-emma { background-image: url("/assets/img/roster/emma.jpg"); }
.tile-photo.tile-roster-greyson { background-image: url("/assets/img/roster/greyson.jpg"); }
.tile-photo.tile-roster-adi { background-image: url("/assets/img/roster/adi-02.jpg"); }
.tile-photo.tile-roster-tc { background-image: url("/assets/img/roster/terra-cognita-wide.jpg"); }
.tile-photo.tile-roster-swim { background-image: url("/assets/img/roster/swim.jpg"); }
.tile-photo.tile-roster-emma { background-image: image-set(
  url("/assets/img/roster/emma.webp") type("image/webp"),
  url("/assets/img/roster/emma.jpg") type("image/jpeg")); }
.tile-photo.tile-roster-greyson { background-image: image-set(
  url("/assets/img/roster/greyson.webp") type("image/webp"),
  url("/assets/img/roster/greyson.jpg") type("image/jpeg")); }
.tile-photo.tile-roster-adi { background-image: image-set(
  url("/assets/img/roster/adi-02.webp") type("image/webp"),
  url("/assets/img/roster/adi-02.jpg") type("image/jpeg")); }
.tile-photo.tile-roster-tc { background-image: image-set(
  url("/assets/img/roster/terra-cognita-wide.webp") type("image/webp"),
  url("/assets/img/roster/terra-cognita-wide.jpg") type("image/jpeg")); }
.tile-photo.tile-roster-swim { background-image: image-set(
  url("/assets/img/roster/swim.webp") type("image/webp"),
  url("/assets/img/roster/swim.jpg") type("image/jpeg")); }

/* Text on photo tiles: everything reads in paper or paper-mixes. */
.tile-photo h3,
.tile-photo .bundle-figure b { color: var(--paper); }
.tile-photo p { color: color-mix(in srgb, var(--paper) 88%, transparent); }
.tile-photo .path-points li { color: color-mix(in srgb, var(--paper) 88%, transparent); }
/* Outranks .roster-card p:last-child, which sets ink-soft later in the file. */
.roster-card.tile-photo p:last-child { color: color-mix(in srgb, var(--paper) 88%, transparent); }
/* 82/18 paper-vermilion clears AA 4.5 over the worst pixel of every crop
   (measured per-pixel under the 0.70 scrim stop; richer mixes fail on the
   Full Setup tag). */
.tile-photo .roster-role,
.tile-photo .bundle-tag { color: color-mix(in srgb, var(--paper) 82%, var(--vermilion)); }
.tile-photo .bundle-figure span { color: color-mix(in srgb, var(--paper) 82%, var(--vermilion)); }
.path-card.tile-photo a {
  color: var(--paper);
  text-decoration: underline;
  text-decoration-thickness: 1px;
}
.path-card.tile-photo a:hover { color: color-mix(in srgb, var(--paper) 72%, var(--vermilion)); }

/* Ghost buttons and focus rings need their dark-context variants. */
.tile-photo .btn-ghost { border-color: var(--paper); color: var(--paper); }
.tile-photo .btn-ghost:hover {
  border-color: color-mix(in srgb, var(--paper) 72%, var(--vermilion));
  color: color-mix(in srgb, var(--paper) 72%, var(--vermilion));
}
.tile-photo :focus-visible,
.tile-photo:focus-visible { outline-color: var(--paper); }

/* ----------------------------------------------------------------- menu */

.menu { border-top: 2px solid var(--ink); margin-top: var(--space-2); }
.menu-entry { border-bottom: 1px solid var(--line); }

.menu-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-2) 0.25rem;
}
.menu-name h3 { margin: 0 0 0.25rem; }
.menu-name p { margin: 0; color: var(--muted); font-size: 0.95rem; max-width: 48ch; }
/* What it is and what it isn't now live in the summary, not behind the
   disclosure: they are the two things a buyer needs to decide, and the
   comparison page carries the depth that used to justify hiding them. */
.menu-is, .menu-isnt {
  font-size: 0.94rem;
  margin-bottom: 0.35rem;
  max-width: 58ch;
}
.menu-is { color: var(--ink-soft); }
.menu-isnt { color: var(--muted); }
.menu-is b, .menu-isnt b {
  font-weight: 640;
  color: var(--ink);
}
.menu-isnt b { color: var(--muted); }

.menu-price { text-align: right; flex: none; margin: 0; }
.menu-price b { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); display: block; }
.menu-price span { font-size: var(--step--1); color: var(--muted); display: block; margin-top: 0.15rem; max-width: 18ch; margin-left: auto; }

/* Flat rows. The homepage lists what is for sale and what it costs; the
   detail lives on the pricing page, so a row is a link, not a disclosure. */
.menu-entry-flat {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: background-color 0.15s ease;
  position: relative;
}
.menu-entry-flat .menu-row { padding-right: 2rem; }
.menu-entry-flat::after {
  content: "\203A";
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--step-2);
  line-height: 1;
  color: var(--muted);
  transition: color 0.15s ease, transform 0.15s ease;
}
.menu-entry-flat:hover { background: var(--paper-deep); }
.menu-entry-flat:hover h3 { color: var(--vermilion); }
.menu-entry-flat:hover::after { color: var(--vermilion); transform: translateY(-50%) translateX(3px); }
.menu-entry-flat:focus-visible { outline: 2px solid var(--vermilion); outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) {
  .menu-entry-flat, .menu-entry-flat::after { transition: none; }
  .menu-entry-flat:hover::after { transform: translateY(-50%); }
}

.menu-entry summary { list-style: none; cursor: pointer; position: relative; transition: background-color 0.15s ease; }
.menu-entry summary::-webkit-details-marker { display: none; }
.menu-entry summary:hover { background: var(--paper-deep); }
/* Every expandable row says so: an explicit control label under the
   one-liner, swapping via the open state. */
.menu-more {
  display: inline-block;
  margin-top: 0.45rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  border-bottom: 1px solid color-mix(in srgb, var(--vermilion) 40%, transparent);
  padding-bottom: 0.1rem;
}
.menu-more::after { content: "Learn more +"; }
.menu-entry[open] .menu-more::after { content: "Show less \2212"; }
.menu-entry summary:hover .menu-more { color: var(--vermilion); border-bottom-color: var(--vermilion); }
.menu-entry summary::after {
  content: "+";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--serif);
  font-size: 1.35rem;
  color: var(--vermilion);
}
.menu-entry[open] summary::after { content: "\2212"; }
.menu-entry[open] summary { background: var(--paper-deep); }
.menu-entry summary .menu-row { padding-right: 2rem; }

.menu-detail {
  padding: var(--space-2) var(--space-2) var(--space-3);
  border-left: 3px solid var(--vermilion);
  margin: 0 0 var(--space-2) 0.25rem;
  background: color-mix(in srgb, var(--paper-deep) 55%, transparent);
}
.menu-detail p { font-size: 0.97rem; color: var(--ink-soft); }
/* Lead-in labels (Format, You leave with, Best for, What it isn't) read as
   spec-sheet field labels. */
.menu-detail p > strong:first-child,
.example-copy p > strong:first-child {
  font-variant: all-small-caps;
  letter-spacing: 0.055em;
  font-weight: 640;
  color: var(--ink);
}
.menu-detail .btn { margin-top: var(--space-1); }
.menu-route { font-size: var(--step--1); color: var(--muted); }

.menu-entry-featured {
  background: color-mix(in srgb, var(--paper-deep) 65%, transparent);
  border-left: 3px solid var(--vermilion);
  padding-inline: var(--space-2);
}

@media (max-width: 480px) {
  .menu-row { flex-direction: column; gap: 0.4rem; }
  .menu-price { text-align: left; display: flex; gap: 0.5rem; align-items: baseline; }
  .menu-price b { font-size: var(--step-0); }
  .menu-price span { margin-top: 0; max-width: none; }
  .menu-entry summary::after { top: 1.05rem; transform: none; }
  .menu-entry summary .menu-row { padding-right: 1.6rem; }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.menu-entry-featured .menu-name h3::after {
  content: "start here";
  font-family: var(--sans);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--vermilion);
  border-radius: 2px;
  padding: 0.2rem 0.45rem;
  margin-left: 0.6rem;
  position: relative;
  top: -0.18rem;
  white-space: nowrap;
}
.menu-featured-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: 0 0.25rem var(--space-2);
}
.menu-featured-cta p { margin: 0; font-size: var(--step--1); color: var(--muted); max-width: 40ch; }

.alacarte { list-style: none; padding: 0; margin: 0 0 var(--space-2); }
.alacarte li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "name price" "desc price";
  column-gap: var(--space-3);
  padding: 0.7rem 0;
  border-bottom: 1px dashed var(--line);
}
.alacarte li:last-child { border-bottom: 0; }
.ala-name { grid-area: name; font-weight: 600; font-size: 0.97rem; }
.ala-desc { grid-area: desc; color: var(--muted); font-size: 0.9rem; max-width: 52ch; }
.ala-price { grid-area: price; font-family: var(--serif); font-weight: 600; align-self: start; }

.bundles { margin-top: var(--space-4); border-top: 1px solid var(--line); padding-top: var(--space-3); }
.bundles-head { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); margin: 0 0 var(--space-1); }
.bundles-lead { color: var(--ink-soft); font-size: 0.95rem; margin: 0 0 var(--space-2); max-width: 64ch; }
.bundle-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
@media (max-width: 620px) { .bundle-grid { grid-template-columns: 1fr; } }
.bundle-card { border: 1px solid var(--line-strong); border-radius: var(--radius); background: color-mix(in srgb, var(--paper-deep) 70%, transparent); padding: var(--space-2); display: flex; flex-direction: column; gap: 0.45rem; }
.bundle-card-feature { border: 2px solid var(--ink); background: color-mix(in srgb, var(--blue-soft) 55%, transparent); }
.bundle-tag { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); margin: 0; color: var(--ink); }
.bundle-what { margin: 0; color: var(--ink-soft); font-size: 0.95rem; }
.bundle-figure { margin: 0.3rem 0 0.7rem; }
.bundle-figure b { font-family: var(--serif); font-weight: 600; font-size: var(--step-2); color: var(--ink); display: inline-block; margin-right: 0.5rem; }
.bundle-figure span { font-size: var(--step--1); color: var(--vermilion-text); font-weight: 650; }
.bundle-card .btn { margin-top: auto; align-self: start; }
.menu-entry-pick .menu-name h3::after { content: "recommended"; font-family: var(--sans); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--vermilion-text); border: 1px solid var(--line-strong); border-radius: 2px; padding: 0.18rem 0.42rem; margin-left: 0.6rem; position: relative; top: -0.18rem; white-space: nowrap; }

.access-note { font-size: var(--step--1); color: var(--muted); margin-top: var(--space-2); }

.retainer {
  margin-top: var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  background: var(--paper-deep);
}
.retainer h3 { margin-bottom: 0.4rem; }
.retainer p { margin: 0; font-size: 0.97rem; color: var(--ink-soft); max-width: 52ch; }

/* --------------------------------------------------------------- voices */

/* The proof band, between Selected work and the price menu on purpose:
   evidence should arrive before the number.

   Geometry contract, restated from build.js because breaking it is silent:
   .voices-track holds exactly TWO .voices-run children and animates to -50%.
   That seam is only invisible while one run is exactly half the track width,
   so cards are spaced with margin-inline-end on the card, NEVER with a gap
   on the track. A track-level gap adds one extra gap at the wrap point and
   the strip visibly jumps once per loop. */

.voices {
  padding-block: clamp(2.5rem, 6vw, 4.5rem);
  border-top: 1px solid var(--line);
  background: var(--paper-deep);
  overflow: hidden;
}
.voices-head h2 { margin-bottom: var(--space-1); }
.voices-lead { color: var(--muted); font-size: var(--step--1); margin-bottom: 0; }

.voices-viewport {
  overflow: hidden;
  margin-top: var(--space-3);
}
/* The region is focusable so keyboard users can reach it, and because it
   carries the same tabindex/role/aria-label contract .compare-scroll is held
   to by the lint suite. */
.voices-viewport:focus-visible { outline: 2px solid var(--vermilion); outline-offset: 4px; }

/* No will-change: a running composited transform animation promotes its own
   layer, and the declaration would survive into the reduced-motion and print
   branches where the animation is switched off, holding a multi-megabyte
   layer for a strip that is standing still. */
.voices-track {
  display: flex;
  width: max-content;
  animation: voices-marquee 150s linear infinite;
}
/* Cards hug their own content instead of stretching to the tallest. Real
   approved quotes run 50 to 110 words, and forcing every card to the longest
   one leaves 250px of empty paper inside the short ones. Top-aligned, the
   slack sits outside the cards rather than as a hole inside them. Top
   aligned, not centred: a shared top line is what keeps a row of uneven
   cards reading as a row. */
.voices-run { display: flex; align-items: flex-start; }

/* Slow is the whole point: at 150s a card holds the eye for roughly fifteen
   seconds, which is long enough to read a fifty-word quote in passing. Pause
   covers everyone that is not true for. */
@keyframes voices-marquee {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

.voices-viewport:hover .voices-track,
.voices-viewport:focus-within .voices-track,
.voices.is-manual .voices-track {
  animation-play-state: paused;
}

/* Stopping the strip must not strand the quotes that are off screen. The
   viewport is overflow:hidden while moving, so paused it becomes a real
   scroller: otherwise Pause leaves three of four quotes unreachable by any
   input, which is a worse outcome than the motion it fixes. */
.voices.is-manual .voices-viewport {
  overflow-x: auto;
  scroll-snap-type: x proximity;
}
.voices.is-manual .voice-card { scroll-snap-align: center; }

/* The checkbox is the state; the label is the control. Visually hidden, not
   display:none, so it keeps its place in the tab order with no JavaScript. */
/* Manual stepping. The band drifts on its own; the arrows hand control over
   and stop the drift, which is also the pause mechanism moving content needs.
   They are gated on js because scrolling a container by a card takes script;
   without it the viewport is still focusable and scrollable by hand. */
.voices-control { margin: var(--space-2) 0 0; display: none; gap: 0.5rem; }
html.js .voices-control { display: flex; }
.voices-step {
  width: 2.6rem;
  height: 2.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  font-size: var(--step-0);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.voices-step:hover { border-color: var(--ink); color: var(--ink); }
.voices-step:focus-visible { outline: 2px solid var(--vermilion); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .voices-step { transition: none; } }

.voice-card {
  flex: 0 0 auto;
  width: min(23rem, 80vw);
  margin: 0 var(--space-3) 0 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper);
  padding: var(--space-2);
  box-shadow: var(--press);
}
.voice-photo {
  display: block;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  overflow: hidden;
  margin: 0 0 var(--space-2);
  background: var(--paper-deep);
  border: 1px solid var(--line);
}
.voice-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; display: block; }
/* No photo on file: an initial plate in the brand's own type, never a
   borrowed or placeholder face. */
.voice-plate {
  font-family: var(--serif);
  font-size: var(--step-2);
  line-height: 4.4rem;
  text-align: center;
  color: var(--vermilion-text);
}
.voice-card .testimonial {
  margin: 0;
  border-left: 0;
  padding-left: 0;
  font-size: var(--step-0);
  line-height: 1.5;
}
.voice-card .testimonial p { margin: 0; max-width: none; }
.voice-card .testimonial p::before { content: "\201C"; }
.voice-card .testimonial p::after { content: "\201D"; }
.voice-by { margin-bottom: var(--space-2); padding-bottom: var(--space-2); border-bottom: 1px solid var(--line); }
.voice-by cite {
  display: block;
  font-family: var(--sans);
  font-style: normal;
  font-size: var(--step--1);
  font-weight: 620;
  color: var(--ink);
}
.voice-links { margin: 0.35rem 0 0; font-size: var(--step--1); }
.voice-links a {
  display: inline-block;
  color: var(--muted);
  padding-inline-end: 0.75rem;
}
.voice-links a:hover { color: var(--vermilion-text); }

/* Touch has no hover, so nothing pauses the strip before a finger lands on it:
   every profile link becomes a 56px target drifting about 32px a second. On a
   coarse pointer the strip is a swipeable row instead, which is the native
   pattern anyway and makes the links reliably tappable. Desktop keeps the
   motion, where hover pauses it the moment the cursor arrives. */
@media (pointer: coarse) {
  .voices-track { animation: none; transform: none; width: auto; }
  .voices-run[aria-hidden="true"] { display: none; }
  /* Swiping is the native way to move a row on touch, so the arrows are
     redundant here and take up a tap target that does nothing new. */
  .voices-control { display: none; }
  .voices-viewport {
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding-inline: clamp(1.25rem, 5vw, 3rem);
  }
  .voice-card { scroll-snap-align: center; }
}

@media (prefers-reduced-motion: reduce) {
  .voices-track { animation: none; transform: none; width: auto; }
  /* Stepping is navigation, not motion, so the arrows stay. */
  /* Nobody should scroll through repeats of what they have already read. */
  .voices-run[aria-hidden="true"] { display: none; }
  /* Standing still, the strip is a row of cards and wants the same gutter the
     heading has. Moving, it is meant to run off both edges, so this padding
     belongs only here. */
  .voices-viewport {
    overflow-x: auto;
    padding-inline: max(clamp(1.25rem, 5vw, 3rem), calc((100% - var(--wrap)) / 2 + clamp(1.25rem, 5vw, 3rem)));
    scroll-padding-inline-start: clamp(1.25rem, 5vw, 3rem);
  }
  /* End padding on a scroll container is not part of the scrollable overflow
     region, so the trailing gutter has to ride on the last card instead. */
  .voices-run > .voice-card:last-child {
    margin-inline-end: max(clamp(1.25rem, 5vw, 3rem), calc((100vw - var(--wrap)) / 2 + clamp(1.25rem, 5vw, 3rem)));
  }
}

/* A tile links straight to its own menu entry rather than the top of the
   menu, so the visitor lands on the thing they clicked. The row is marked as
   the target; main.js also sets [open] on it, and the CSS below opens it for
   anyone with JS off. The nav is fixed, so the row needs scroll margin or it
   arrives underneath it. */
.menu-entry { scroll-margin-top: 6rem; }
.menu-entry:target { border-color: var(--ink); box-shadow: var(--press); }

/* ------------------------------------------------------------- who home */

.who-home-grid {
  display: grid;
  gap: var(--space-3);
  align-items: start;
}
@media (min-width: 880px) {
  .who-home-grid { grid-template-columns: minmax(0, 1.1fr) minmax(18rem, 0.58fr); }
}
.who-home p {
  color: var(--ink-soft);
}
.who-note {
  border: 1px solid var(--line-strong);
  border-left: 4px solid var(--blue);
  border-radius: var(--radius);
  background: var(--blue-soft);
  padding: var(--space-2);
}
.who-note h3 { margin-bottom: 0.6rem; }
.who-note p {
  font-size: 0.95rem;
  margin-bottom: var(--space-2);
}
.case-link {
  display: inline-block;
  margin: 0 0 var(--space-2);
  color: var(--blue);
  font-weight: 700;
  font-size: 0.95rem;
}

/* --------------------------------------------------------------- case */

.case-hero {
  padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2rem, 5vw, 4rem);
}
.case-hero-grid {
  display: grid;
  gap: var(--space-4);
  align-items: start;
}
@media (min-width: 920px) {
  .case-hero-grid { grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.72fr); }
}
.case-snapshot {
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--paper-deep);
  padding: var(--space-3);
  box-shadow: var(--press);
}
.case-snapshot h2 {
  font-size: var(--step-2);
  margin-bottom: var(--space-2);
}
.case-snapshot dl {
  margin: 0 0 var(--space-2);
}
.case-snapshot div {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: var(--space-2);
  padding: 0.65rem 0;
  border-top: 1px solid var(--line);
}
.case-snapshot dt {
  font-size: var(--step--1);
  font-weight: 750;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--vermilion-text);
}
.case-snapshot dd {
  margin: 0;
  color: var(--ink-soft);
}
.case-snapshot p {
  margin: 0;
  color: var(--muted);
  font-size: var(--step--1);
}
.case-change-grid,
.artifact-grid {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
@media (min-width: 760px) {
  .case-change-grid { grid-template-columns: 1fr 1fr; }
  .artifact-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.case-change-grid article,
.artifact-card {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--paper-deep) 68%, transparent);
  padding: var(--space-2);
}
.case-change-grid article:nth-child(2),
.artifact-card:nth-child(3) {
  background: color-mix(in srgb, var(--blue-soft) 68%, transparent);
}
.case-change-grid p,
.artifact-card p,
.outcome-list p {
  color: var(--ink-soft);
}
.artifact-label {
  font-size: var(--step--1);
  font-weight: 750;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  margin-bottom: 0.55rem;
}
.artifact-before {
  background:
    linear-gradient(90deg, rgba(160, 58, 22, 0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(160, 58, 22, 0.08) 1px, transparent 1px),
    color-mix(in srgb, var(--paper-deep) 72%, transparent);
  background-size: 22px 22px;
}
.artifact-before ul {
  color: var(--ink-soft);
  margin: 0 0 var(--space-2);
  padding-left: 1.05rem;
}
.artifact-before li {
  margin-bottom: 0.45rem;
}
.artifact-note,
.case-disclaimer {
  color: var(--muted);
  font-size: var(--step--1);
}
.artifact-image {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--ink);
  margin-bottom: var(--space-2);
}
.artifact-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top left;
}
.outcome-list {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.outcome-list p {
  border-top: 1px solid var(--line);
  margin: 0;
  padding-top: var(--space-2);
}

/* ---------------------------------------------------------------- steps */

.steps { counter-reset: step; list-style: none; padding: 0; margin: 0; max-width: 62ch; }
.steps li {
  counter-increment: step;
  position: relative;
  padding: var(--space-2) 0 var(--space-2) 3.2rem;
  border-top: 1px solid var(--line);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: var(--space-2);
  font-family: var(--serif);
  font-weight: 600;
  font-size: var(--step-1);
  color: var(--vermilion-text);
}

/* ------------------------------------------------------------------ who */

.who-grid { display: grid; gap: var(--space-4); }
@media (min-width: 900px) { .who-grid { grid-template-columns: 1.25fr 0.75fr; } }
.founder { border-left: 3px solid var(--vermilion); padding-left: var(--space-2); margin-bottom: var(--space-3); }
.founder-name { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); margin-bottom: 0.3rem; }
.founder p { color: var(--ink-soft); font-size: 0.97rem; }
.who-copy > p { color: var(--ink-soft); font-size: 0.99rem; }

.testimonial {
  margin: var(--space-3) 0 0;
  border-left: 3px solid var(--line-strong);
  padding-left: var(--space-2);
  font-family: var(--serif);
  font-size: var(--step-1);
  line-height: 1.4;
}
.testimonial cite { display: block; font-family: var(--sans); font-style: normal; font-size: var(--step--1); color: var(--muted); margin-top: 0.5rem; }

.who-figures { display: grid; gap: var(--space-3); align-content: start; }
.slot-frame {
  aspect-ratio: 4 / 5;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--muted);
  font-size: var(--step--1);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  background: color-mix(in srgb, var(--paper-deep) 60%, transparent);
}
.slot-artifact .slot-frame { aspect-ratio: 3 / 2; }
.slot figcaption { font-size: var(--step--1); color: var(--muted); margin-top: 0.5rem; }

/* ------------------------------------------------------------------ faq */

.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none;
  cursor: pointer;
  font-family: var(--serif);
  font-weight: 600;
  font-size: var(--step-1);
  padding: var(--space-2) 2rem var(--space-2) 0;
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  position: absolute;
  right: 0.25rem;
  top: var(--space-2);
  color: var(--vermilion);
}
.faq details[open] summary::after { content: "\2212"; }
.faq details > div { padding: 0 0 var(--space-2); }
.faq details p { color: var(--ink-soft); max-width: 62ch; }

/* -------------------------------------------------------------- closing */

.closing { text-align: center; }
.closing .wrap { max-width: 46rem; }
.closing-mark { color: var(--ink); margin-bottom: var(--space-2); }
.closing h2 { margin-inline: auto; }
.closing p { margin-inline: auto; color: var(--ink-soft); }
.closing .btn { margin-top: var(--space-2); }
/* The section centres its text, but a flex row does not inherit that, so the
   button pair sat about 100px left of the axis everything above it lined up
   on. The reassurance under it had no top margin and a wider measure than the
   buttons, so it crowded them and broke with one word on its own line. */
.closing .hero-ctas { justify-content: center; }
.closing .hero-ctas + .fine { margin-top: var(--space-2); }
.closing h2, .closing p { text-wrap: balance; }

/* ------------------------------------------------------------------ b2b */

.b2b { padding-block: 0 var(--space-4); }
.b2b-in {
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: center;
  justify-content: space-between;
}
.b2b-in p { margin: 0; color: var(--muted); font-size: 0.95rem; max-width: 52ch; }

/* ----------------------------------------------------------- inner pages */

.page-hero { padding-block: clamp(3rem, 7vw, 5rem) var(--space-2); }
.page-narrow { max-width: 46rem; }
.scan-body { padding-top: var(--space-2); }
.scan-after { margin-top: var(--space-4); border-top: 1px solid var(--line); padding-top: var(--space-3); }

.scan-form { margin-top: var(--space-2); }
.field { margin-bottom: var(--space-2); }
.field label { display: block; font-weight: 600; font-size: 0.94rem; margin-bottom: 0.35rem; }
.field input, .field textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--field-bg);
  border: 1.5px solid var(--field-line);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
}
.field input:focus-visible, .field textarea:focus-visible { outline-offset: 1px; border-color: var(--vermilion); }
.form-note { font-size: var(--step--1); color: var(--muted); margin-top: var(--space-2); }
.hp-field { position: absolute; left: -9999px; }

.terms-text h2 { margin-top: var(--space-4); }
.terms-text ul { color: var(--ink-soft); }
.terms-text li { margin-bottom: 0.5rem; }
.terms-text { overflow-wrap: break-word; }

/* -------------------------------------------------------------- about */

.about-hero {
  padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2rem, 5vw, 4rem);
}
.about-hero-grid {
  display: grid;
  gap: var(--space-4);
  align-items: center;
}
@media (min-width: 920px) {
  .about-hero-grid {
    grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.9fr);
  }
}
.about-hero h1 {
  max-width: 19ch;
}
.about-photo {
  margin: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--paper-deep);
  box-shadow: var(--press);
}
.about-photo img {
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center;
}
.about-stats {
  padding-block: 0 var(--space-4);
}
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  border-block: 1px solid var(--line);
}
.stat-item {
  padding: var(--space-2);
  border-right: 1px solid var(--line);
}
.stat-item:last-child {
  border-right: 0;
}
.stat-item strong {
  display: block;
  font-family: var(--serif);
  font-size: 2rem;
  line-height: 1;
  margin-bottom: 0.45rem;
}
.stat-item span {
  display: block;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.45;
}
.roster-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.roster-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--paper-deep) 68%, transparent);
  padding: var(--space-2);
}
.roster-role {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  margin-bottom: 0.35rem;
}
.roster-card h3 {
  margin-bottom: 0.45rem;
}
.roster-card p:last-child {
  margin-bottom: 0;
  color: var(--ink-soft);
  font-size: 0.95rem;
}
.credit-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin: var(--space-2) 0;
}
.credit-list span {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 0.35rem 0.6rem;
  color: var(--ink-soft);
  background: color-mix(in srgb, var(--paper-deep) 55%, transparent);
  font-size: 0.9rem;
}
.about-note {
  color: var(--muted);
  font-size: var(--step--1);
}
.story-grid {
  display: grid;
  gap: var(--space-3);
  align-items: start;
}
@media (min-width: 860px) {
  .story-grid {
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 0.42fr);
  }
}
.about-panel {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--paper-deep);
  padding: var(--space-2);
}
.about-panel p {
  color: var(--ink-soft);
  font-size: 0.95rem;
}
.about-panel p:last-child {
  margin-bottom: 0;
}
@media (max-width: 700px) {
  .about-hero-grid,
  .about-hero-copy {
    min-width: 0;
  }
  .about-hero h1,
  .about-hero .lede {
    max-width: 100%;
    overflow-wrap: break-word;
  }
  .about-hero .hero-ctas {
    display: grid;
    grid-template-columns: 1fr;
  }
  .about-hero .btn {
    width: 100%;
  }
  .stat-grid {
    grid-template-columns: 1fr;
    border-top: 1px solid var(--line);
  }
  .stat-item {
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }
  .stat-item:last-child {
    border-bottom: 0;
  }
}

/* --------------------------------------------------------------- footer */

.footer { border-top: 1px solid var(--line); padding-block: var(--space-3); color: var(--muted); font-size: 0.9rem; }
.foot-in { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; justify-content: space-between; }
.foot-brand { display: flex; align-items: flex-start; gap: 0.75rem; }
.foot-brand .mark { color: var(--muted); flex: none; margin-top: 0.2rem; }
.foot-brand p { margin: 0; max-width: 44ch; }
.foot-links { display: flex; flex-wrap: wrap; gap: 1.2rem; }
.foot-links a { text-decoration: none; color: var(--ink-soft); }
.foot-links a:hover { color: var(--vermilion-text); }

/* Mailto fallback confirmation, created by main.js on click. */
.copy-note { display: none; font-size: var(--step--1); color: var(--vermilion-text); font-weight: 640; margin-top: 0.6rem; }
.copy-note.is-on { display: block; }

/* B2B strip speaks to a different reader; say so before the pitch.
   Doubled selector outranks the .b2b-in p color, and the kicker takes
   its own full row above the flex pair. */
.b2b-in .b2b-kicker {
  flex-basis: 100%;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  margin: 0;
}

/* ------------------------------------------------------------- book bar */

.book-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 50;
  background: var(--ink);
  color: var(--paper);
  padding: 0.6rem clamp(1rem, 4vw, 2rem);
  padding-bottom: calc(0.6rem + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -6px 20px rgba(33, 28, 21, 0.25);
}
.book-bar[hidden] { display: none; }
/* While the fixed bar is up it must never cover the footer's last row
   of links; the footer follows it as a sibling on pages that carry it. */
.book-bar:not([hidden]) ~ .footer { padding-bottom: 104px; }
.book-bar-in { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); max-width: var(--wrap); margin: 0 auto; }
.book-bar p { margin: 0; font-size: 0.88rem; color: var(--paper); }
.book-bar .btn-primary { background: var(--paper); color: var(--ink); border-color: var(--paper); flex: none; }
.book-bar .btn-primary:hover { background: var(--paper-deep); }
@media (min-width: 900px) { .book-bar { display: none; } }

/* --------------------------------------------------- reveals (js-gated) */

/* Hidden states exist ONLY under html.js: without JavaScript the page
   renders fully visible. */
html.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}
html.js .reveal.is-in { opacity: 1; transform: none; }

/* Staggered card cascade inside revealed sections. Children of a .stagger
   grid hide under the same html.js gate and reveal off the ancestor's
   .is-in toggle -- main.js (observer + safety sweep) needs no changes.
   Reveal runs as a fill-backwards animation on purpose: at rest it leaves
   no transform or transition on the cards -- a transition-based reveal
   would permanently override the card hover lift and hijack its timing. */
html.js .reveal .stagger > * { opacity: 0; }
html.js .reveal.is-in .stagger > * {
  opacity: 1;
  animation: stagger-in 0.5s ease backwards;
}
html.js .reveal.is-in .stagger > *:nth-child(2) { animation-delay: 0.07s; }
html.js .reveal.is-in .stagger > *:nth-child(3) { animation-delay: 0.14s; }
html.js .reveal.is-in .stagger > *:nth-child(4) { animation-delay: 0.21s; }
html.js .reveal.is-in .stagger > *:nth-child(5) { animation-delay: 0.28s; }
html.js .reveal.is-in .stagger > *:nth-child(n + 6) { animation-delay: 0.35s; }
@keyframes stagger-in {
  from { opacity: 0; transform: translateY(16px); }
}

@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  html.js .reveal .stagger > * { opacity: 1; animation: none; }
  .btn { transition: none; }
}

/* --------------------------------------------- modernization (motion) */

/* Card lift on capable pointers. */
@media (hover: hover) {
  .path-card, .work-card, .roster-card, .bundle-card {
    transition: transform 0.18s ease, box-shadow 0.18s ease;
  }
  .path-card:hover, .work-card:hover, .roster-card:hover, .bundle-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(33, 28, 21, 0.10);
  }
}

/* Native disclosure animation where supported. Height-based only: the
   js-gate lint (correctly) rejects opacity-hidden closed states, and
   native details must keep working without JS. */
@supports (interpolate-size: allow-keywords) {
  /* Scoped to the menu on purpose: it inherits into ::details-content,
     the only consumer. A :root opt-in would silently change any future
     height/width transition document-wide. */
  .menu-entry { interpolate-size: allow-keywords; }
  .menu-entry::details-content {
    block-size: 0;
    overflow-y: clip;
    transition: block-size 0.3s ease, content-visibility 0.3s allow-discrete;
  }
  .menu-entry[open]::details-content,
  .menu-entry:target::details-content { block-size: auto; content-visibility: visible; }
}

/* Prose links sharpen underline and warm on hover. */
.menu-detail a:not(.btn), .example-copy a:not(.btn), .faq details a {
  text-decoration-thickness: 1px;
  transition: color 0.15s ease, text-decoration-thickness 0.15s ease;
}
.menu-detail a:not(.btn):hover, .example-copy a:not(.btn):hover, .faq details a:hover {
  color: var(--vermilion-text);
  text-decoration-thickness: 2px;
}

/* Touch targets: text links that act as primary actions get an enlarged
   hit area without moving the visual layout (padding offset by negative
   margin). Keyboard focus outlines still hug the padded box. */
.path-card a,
.roster-links a,
.menu-detail a:not(.btn),
.example-copy a:not(.btn) {
  padding-block: 0.55rem;
  margin-block: -0.55rem;
}
.roster-links a { padding-inline: 0.35rem; margin-inline: -0.35rem; }

/* Nav gains depth once the page scrolls (class from main.js). */
.nav { transition: box-shadow 0.2s ease; }
.nav.is-scrolled {
  box-shadow: 0 6px 18px rgba(33, 28, 21, 0.08);
  background: color-mix(in srgb, var(--paper) 97%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .path-card, .work-card, .roster-card, .bundle-card { transition: none; }
  .path-card:hover, .work-card:hover, .roster-card:hover, .bundle-card:hover { transform: none; box-shadow: none; }
  .menu-entry::details-content { transition: none; }
}

/* --------------------------------------------------- selected work */
.work-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: var(--space-3); margin-top: var(--space-2); }
.work-card { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--paper-deep); }
.work-plate {
  display: block;
  aspect-ratio: 4 / 3;
  border-bottom: 1px solid var(--line);
  background: var(--ink);
  overflow: hidden;
}
.work-plate img { width: 100%; height: 100%; object-fit: cover; object-position: top left; transition: transform 0.2s ease; }
.work-plate:hover img { transform: scale(1.025); }
.work-meta { padding: var(--space-2) var(--space-2) var(--space-3); }
.work-kind { font-size: var(--step--1); font-weight: 620; letter-spacing: 0.12em; text-transform: uppercase; color: var(--vermilion-text); margin: 0 0 0.2rem; }
.work-name { font-family: var(--serif); font-weight: 600; font-size: var(--step-1); margin: 0 0 0.35rem; }
.work-desc { margin: 0; font-size: 0.94rem; color: var(--ink-soft); }
.work-note { font-size: var(--step--1); color: var(--muted); margin-top: var(--space-3); }
@media (prefers-reduced-motion: reduce) {
  .work-plate img { transition: none; }
  .work-plate:hover img { transform: none; }
}

/* ------------------------------------------------------------ examples */

.example-block { padding-block: clamp(2rem, 5vw, 3.5rem); }
.example-grid { display: grid; gap: var(--space-3); margin-top: var(--space-2); }
@media (min-width: 860px) {
  .example-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); align-items: start; }
}
.example-plate {
  display: block;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--ink);
}
.example-plate img { width: 100%; height: 100%; object-fit: cover; object-position: top left; transition: transform 0.25s ease; }
.example-plate:hover img { transform: scale(1.02); }
.example-copy p { font-size: 0.97rem; color: var(--ink-soft); }
.example-copy .btn { margin-top: var(--space-1); }
@media (prefers-reduced-motion: reduce) {
  .example-plate img { transition: none; }
  .example-plate:hover img { transform: none; }
}

/* ------------------------------------------------------- examples index */
/* The three flagship documents keep their screenshot plates. Everything else
   lists as text: fourteen plates would be a slow page and a scroll, and the
   name plus one line is what a reader needs to decide which to open. */
.example-index { padding-block: clamp(2rem, 5vw, 3.5rem); border-top: 1px solid var(--line); }
.ex-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; border-top: 1px solid var(--line); }
.ex-list li { border-bottom: 1px solid var(--line); }
.ex-list a {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.2rem var(--space-2);
  align-items: baseline;
  padding: 0.9rem 0.35rem;
  color: inherit;
  text-decoration: none;
  transition: background-color 0.15s ease;
}
.ex-name { font-family: var(--serif); font-weight: 600; font-size: var(--step-0); }
.ex-what { grid-column: 1 / -1; color: var(--ink-soft); font-size: 0.95rem; max-width: 68ch; }
.ex-price { font-family: var(--serif); font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ex-list a:hover { background: var(--paper-deep); }
.ex-list a:hover .ex-name { color: var(--vermilion); }
.ex-list a:focus-visible { outline: 2px solid var(--vermilion); outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) { .ex-list a { transition: none; } }

/* ----------------------------------------------------------- price list */
/* The complete list of what is sold and what it costs, so a visitor can see
   every figure at once and open the one they want. Two columns on a wide
   screen, one on a phone; no horizontal scroll at any width. */
.pricelist { padding-block: clamp(2rem, 5vw, 3.5rem) 0; }
.pl-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3) var(--space-4);
  align-items: start;
}
@media (min-width: 860px) { .pl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.pl-group h3 {
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.4rem;
}
.pl-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
.pl-list li { border-bottom: 1px solid var(--line); }
.pl-list a {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
  padding: 0.62rem 0.35rem;
  color: inherit;
  text-decoration: none;
  transition: background-color 0.15s ease;
}
.pl-name { min-width: 0; }
.pl-sub { display: block; font-size: var(--step--1); color: var(--muted); margin-top: 0.1rem; }
.pl-price {
  flex: none;
  font-family: var(--serif);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  max-width: 14ch;
}
.pl-list a:hover { background: var(--paper-deep); }
.pl-list a:hover .pl-name { color: var(--vermilion); }
.pl-list a:focus-visible { outline: 2px solid var(--vermilion); outline-offset: -2px; }
.pl-note { margin-top: var(--space-3); max-width: 66ch; }

.routes-head { padding-block: var(--space-3) 0; max-width: 60ch; }
.routes-head h2 { margin-bottom: var(--space-1); }
.routes-head p { color: var(--ink-soft); }

@media (prefers-reduced-motion: reduce) { .pl-list a { transition: none; } }

/* -------------------------------------------------------------- routes */
/* The compare page is a routing problem, not a comparison problem: nobody
   lands there knowing which service they need. Each route opens with a
   sentence the artist would actually say, then answers with ONE build.
   Replaced two feature matrices whose rows described our process ("time with
   a person", "you correct our facts first") and were 14/24 "No". */

.routes { padding-block: 0 clamp(3rem, 7vw, 5rem); display: flex; flex-direction: column; }
.route {
  border-top: 1px solid var(--line);
  padding-block: var(--space-3);
  display: grid;
  gap: var(--space-2);
}
.route:first-child { border-top: 0; padding-top: 0; }
.route-said {
  font-family: var(--serif);
  font-size: var(--step-2);
  line-height: 1.25;
  color: var(--ink);
  margin: 0;
  max-width: 30ch;
  text-wrap: balance;
}
.route-answer { display: flex; flex-direction: column; gap: var(--space-2); }
.route-answer p { margin: 0; font-size: 0.97rem; color: var(--ink-soft); }
.route-lead { font-size: 1.03rem !important; color: var(--ink) !important; }
.route-price {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.2rem !important;
}
.route-price span { font-family: var(--sans); font-size: var(--step--1); color: var(--muted); }

.route-tiers { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.55rem; }
.route-tiers li {
  border-left: 3px solid var(--line-strong);
  padding-left: var(--space-2);
  font-size: 0.95rem;
  color: var(--ink-soft);
}
.route-tiers b {
  display: inline-block;
  min-width: 4.2rem;
  font-family: var(--mono, var(--sans));
  color: var(--ink);
}

/* Name and price share a line, the description sits under them. A three
   column grid was tried and collapsed: these lists live inside the route's
   answer column, which is roughly 400px wide, so the middle column wrapped to
   one word per line. */
.route-single { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; }
.route-single li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.1rem var(--space-2);
  padding: 0.75rem 0;
  border-top: 1px solid var(--line);
  align-items: baseline;
}
.route-single li:first-child { border-top: 0; }
/* Explicit placement: DOM order is name, description, price, so auto-flow
   pushed the price onto a third row instead of aligning it with the name. */
.rs-name { grid-column: 1; grid-row: 1; }
.rs-price { grid-column: 2; grid-row: 1; text-align: right; }
.rs-for { grid-column: 1 / -1; grid-row: 2; }
@media (min-width: 760px) {
  .route { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.5fr); gap: var(--space-4); }
  .route-said { position: sticky; top: 6rem; align-self: start; }
}
.rs-name { font-weight: 620; color: var(--ink); font-size: 0.95rem; }
.rs-for { color: var(--muted); font-size: 0.92rem; }
.rs-price { font-weight: 620; color: var(--ink); font-size: 0.95rem; white-space: nowrap; }
.rs-price em { display: block; font-style: normal; font-weight: 400; font-size: var(--step--1); color: var(--vermilion-text); }

/* ------------------------------------------------------------- linkhub */
/* The owned link-in-bio page. It exists so the Instagram bio can point at a
   page we control instead of a third-party list; keep it boring and fast. */

.linkhub { padding-block: 0 clamp(3rem, 7vw, 5rem); }
.linkhub-head {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--vermilion-text);
  margin: var(--space-4) 0 var(--space-2);
}
.linkhub-head:first-child { margin-top: 0; }
.linkhub-list { display: flex; flex-direction: column; gap: 0.7rem; }
.linkhub-list .btn { width: 100%; }
.linkhub-fine { margin-top: var(--space-4); }

/* Roster rows carry the artist's face, because a name alone asks a stranger
   to already know who these people are. Where no usable portrait exists the
   row falls back to initials rather than an empty frame, so the column edge
   stays straight and nothing looks broken while a photo is missing. */
.linkhub-roster { display: flex; flex-direction: column; gap: 0.7rem; }
.roster-link {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.roster-link:hover { border-color: var(--line-strong); background: var(--paper-deep); }
.roster-face {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--paper-deep);
}
.roster-initials {
  display: grid;
  place-items: center;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  border: 1px solid var(--line);
}
.roster-name { font-weight: 620; }
@media (prefers-reduced-motion: reduce) { .roster-link { transition: none; } }

/* ------------------------------------------------------------- compare */
/* Side-by-side service tables. The table itself is allowed to be wider than
   a phone; the scroll lives in .compare-scroll so the page body never scrolls
   sideways. First column is sticky so a row keeps its label while scrolling. */

.menu-compare { margin-top: var(--space-3); color: var(--ink-soft); font-size: var(--step--1); }

.compare-block { padding-block: clamp(2.5rem, 6vw, 4.5rem); border-top: 1px solid var(--line); }
.compare-block h2 { margin-bottom: var(--space-1); }
.compare-block .sec-intro { margin-bottom: var(--space-3); }
.compare-block .fine { margin-top: var(--space-2); max-width: 52ch; }

.compare-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--line);
  background: var(--paper);
}

.compare { border-collapse: collapse; width: 100%; min-width: 44rem; font-size: var(--step-0); }
.compare th, .compare td {
  text-align: left;
  vertical-align: top;
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--line);
}
.compare thead th {
  text-wrap: balance;
  font-family: var(--serif);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.2;
  border-bottom: 2px solid var(--line-strong);
  vertical-align: bottom;
}
.compare thead th span {
  display: block;
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--muted);
  margin-top: 0.2rem;
}
/* Row labels stay put while the columns scroll under them. */
.compare tbody th {
  position: sticky;
  left: 0;
  background: var(--paper);
  font-family: var(--sans);
  font-weight: 600;
  color: var(--ink);
  min-width: 11rem;
  border-right: 1px solid var(--line);
}
.compare tbody tr:last-child th,
.compare tbody tr:last-child td { border-bottom: 0; }
.compare td { color: var(--ink-soft); }
.compare td.yes { color: var(--ink); font-weight: 600; }
.compare td.no { color: var(--muted); }
@media (hover: hover) {
  .compare tbody tr:hover td,
  .compare tbody tr:hover th { background: color-mix(in srgb, var(--paper-deep) 55%, transparent); }
}

.compare-list { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--line); }
.compare-list li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.15rem var(--space-2);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}
.cl-name { font-family: var(--serif); font-size: var(--step-0); font-weight: 600; }
.cl-for { grid-column: 1; color: var(--ink-soft); font-size: var(--step--1); max-width: 46ch; }
.cl-price { grid-column: 2; grid-row: 1 / span 2; text-align: right; font-family: var(--serif); font-weight: 600; font-variant-numeric: tabular-nums; }
.cl-price em { display: block; font-family: var(--sans); font-style: normal; font-size: var(--step--1); font-weight: 400; color: var(--muted); }

/* Only shown where the table cannot fit, so it is not a nag on desktop. */
.compare-hint { display: none; }

@media (max-width: 48rem) {
  .compare-hint { display: block; margin-bottom: var(--space-1); color: var(--muted); font-size: var(--step--1); }
  /* A narrower label column leaves room for more than one option on screen. */
  .compare tbody th { min-width: 8rem; }
  .compare { min-width: 38rem; }
  .compare th, .compare td { padding: 0.6rem 0.65rem; }
  /* Edge shadow on the sticky column: the standard cue that more sits to the right. */
  .compare tbody th { box-shadow: 1px 0 0 var(--line), 6px 0 8px -6px rgba(33, 28, 21, 0.28); }
}

@media (max-width: 34rem) {
  .compare-list li { grid-template-columns: 1fr; }
  .cl-price { grid-column: 1; grid-row: auto; text-align: left; }
}

/* --------------------------------------------------------------- print */
/* A services page people sometimes save as PDF. Drop the sticky chrome,
   flatten the letterpress shadows, keep the type. */
@media print {
  .nav, .book-bar, .b2b, .skip { display: none !important; }
  body { background: #fff; background-image: none; }
  .hero-card, .case-snapshot, .about-photo, .retainer { box-shadow: none; }
  .menu-entry summary { cursor: auto; }
  a { text-decoration: underline; }

  /* A printed services page used to contain no services: every offer body is
     a closed <details>, so the PDF showed seven one-line summaries and no
     spec sheets or FAQ answers. Force them open. */
  details > *:not(summary) { display: revert !important; }
  .menu-detail, .faq details > div { display: block !important; }
  .menu-more, .compare-hint { display: none !important; }

  /* Reveal targets start fully transparent until the observer fires, so
     printing within ~1.2s of load would otherwise emit blank sections. */
  .reveal, .stagger > *, html.js .reveal, html.js .stagger > * {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }

  /* Comparison tables are wider than a page and would print clipped. */
  .compare-scroll { overflow: visible !important; border: 0 !important; }
  .compare { min-width: 0 !important; font-size: 9pt !important; }
  .compare tbody th { position: static !important; box-shadow: none !important; }

  /* The quote band is a moving strip clipped to the viewport. Printed as-is
     it would emit one and a half quotes frozen at whatever transform the
     animation reached. This page gets handed to venues; the proof has to
     survive the paper. */
  /* content-visibility would let the band print as a blank reserved box. */
  .voices { content-visibility: visible !important; overflow: visible !important; }
  .voices-viewport { overflow: visible !important; }
  .voices-track { animation: none !important; transform: none !important; width: auto !important; flex-wrap: wrap; }
  .voices-run[aria-hidden="true"] { display: none !important; }
  .voices-run { flex-wrap: wrap; }
  .voice-card { width: 46% !important; box-shadow: none; break-inside: avoid; margin-bottom: var(--space-2); }
  .voices-control { display: none !important; }
}
