/* ============================================================================
   Rewind Bodyshop | modules.css  (v2 redesign)
   Component blocks. Depends on core.css tokens. Theme locked dark.
   v2 system: full-background hero + gauge pod, finish plate, services mosaic,
   segmented process panel, work filmstrip, anatomy diagram (rw-anat), category
   index filter, service bays + anchor rail (rw-svcrail), auto electric
   installs (rw-elec + rw-fit) / tour,
   review clamp + read-more, contact/estimate panels.
   ========================================================================== */

/* ---- Hero (full-viewport cinematic; video-ready media under a dark scrim;
        content mid-left, gauge deck pinned to the viewport bottom edge) ----- */
.rw-hero {
  position: relative; overflow: hidden; display: flex; flex-direction: column;
  margin-top: calc(-1 * var(--top-h));   /* media runs UNDER the glass header */
  min-height: 100vh; min-height: 100svh;
  border-bottom: 1px solid var(--rw-line);
}
.rw-hero__bg { position: absolute; inset: 0; z-index: 0; background: var(--rw-coal); }
/* the media slot lays <img> and <video> out identically */
.rw-hero__bg img, .rw-hero__bg video {
  width: 100%; height: 100%; object-fit: cover; object-position: 64% 38%;
}
/* ambient loops (hero, about) must NEVER surface a play/pause control.
   These rules no longer hold on modern iOS - WebKit changed the shadow
   structure and paints the start-playback overlay anyway - so the real
   answer is shell.js initLoops, which REPLACES the <video> with its own
   nested still <img> the moment play() is refused (low power mode) or
   reduced motion is set. Keep them as belt and braces for the moment
   between first paint and that swap. */
video[data-rw-loop]::-webkit-media-controls,
video[data-rw-loop]::-webkit-media-controls-start-playback-button {
  display: none !important; -webkit-appearance: none;
}
/* dark overlay: uniform wash for headline contrast over the unmirrored
   footage (round 8) + left column scrim for copy + top/bottom vignette.
   Three layers, one element. */
.rw-hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(rgba(11,11,13,.22), rgba(11,11,13,.22)),
    linear-gradient(90deg, rgba(11,11,13,.94) 0%, rgba(11,11,13,.78) 30%, rgba(11,11,13,.42) 58%, rgba(11,11,13,.5) 100%),
    linear-gradient(180deg, rgba(11,11,13,.46), transparent 28%, transparent 58%, rgba(11,11,13,.92));
}
/* the rewind seam: one crimson hairline at the hero base */
.rw-hero__seam {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px; z-index: 2;
  background: linear-gradient(90deg, transparent, var(--rw-crimson) 16%, var(--rw-crimson) 84%, transparent);
  box-shadow: 0 0 18px var(--rw-crimson-glow);
}
.rw-hero__grid {
  position: relative; z-index: 1; width: 100%; flex: 1;
  display: flex; flex-direction: column; justify-content: center;
  padding-top: calc(var(--top-h) + clamp(1.6rem, 4vh, 3rem));
  padding-bottom: clamp(1.4rem, 3vh, 2.4rem);
}
.rw-hero__content { max-width: 40rem; }
/* gauge deck row: pinned to the hero's (= viewport's) bottom edge */
/* one stable padding at every width (round 12): the old <=640 override
   cleared a bottom dock that never shipped AND keyed on
   env(safe-area-inset-bottom), which iOS re-resolves as its chrome hides -
   the hero visibly changed height mid-scroll */
.rw-hero__deck { position: relative; z-index: 1; padding-bottom: clamp(1rem, 2.4vh, 1.8rem); }
.rw-hero h1 {
  font-size: clamp(2.4rem, 1.5rem + 3.4vw, 4.4rem); color: var(--rw-bone); font-weight: 700;
  margin-bottom: 1.2rem; text-wrap: balance; letter-spacing: -.022em; line-height: 1.02;
}
.rw-hero h1 em { font-style: italic; color: var(--rw-crimson); }
.rw-hero__lead { font-size: var(--fs-lead); color: var(--rw-text); margin-bottom: 1.9rem; max-width: 42ch; }
/* the motto: second beat of the wind-back signature. Settled in HTML (no-JS /
   reduced-motion / first paint); hero-sig.js scrubs it (.is-winding) and
   releases it a beat after the rewind underline lands. */
.rw-hero__motto {
  display: flex; align-items: center; gap: .7rem;
  font-family: var(--ff-display); font-size: clamp(1.02rem, .92rem + .7vw, 1.42rem);
  color: var(--rw-titanium); letter-spacing: -.01em; margin: -.35rem 0 1.15rem;
  transition: filter .7s var(--rw-ease-io), opacity .7s var(--rw-ease-io);
}
/* the motto's ::before shift-light blades are defined with .rw-tick in core.css */
.rw-hero__motto em { font-style: italic; color: var(--rw-crimson-text); }
.js .rw-hero__motto.is-winding { filter: blur(6px); opacity: 0; transition: none; }
@media (prefers-reduced-motion: reduce) {
  .rw-hero__motto { filter: none !important; opacity: 1 !important; transition: none !important; }
}
.rw-hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; }
@media (max-width: 560px) {
  .rw-hero__actions { flex-direction: column; align-items: stretch; }
  .rw-hero__actions .rw-act { width: 100%; }
}

/* Wind-back signature: settled by default; JS adds .is-winding as the start-state
   then releases it so the word resolves blur->crisp + line right->full, once. */
.rw-rewind { position: relative; display: inline-block; }
.rw-rewind em { transition: filter .9s var(--rw-ease-io), opacity .9s var(--rw-ease-io); will-change: filter, opacity; }
.rw-rewind__line {
  position: absolute; left: 0; right: 0; bottom: -.04em; height: 2px;
  background: var(--rw-crimson); transform-origin: right;      /* grows right -> left = the rewind direction */
  transition: transform 1s var(--rw-ease-io);
}
.js .rw-rewind.is-winding em { filter: blur(6px); opacity: .32; transition: none; }
.js .rw-rewind.is-winding .rw-rewind__line { transform: scaleX(0); transition: none; }
@media (prefers-reduced-motion: reduce) {
  .rw-rewind em { filter: none !important; opacity: 1 !important; transition: none !important; }
  .rw-rewind__line { transform: none !important; transition: none !important; }
}

/* ---- Gauge deck (three meaning-dials as a horizontal instrument cluster,
        pinned along the hero's bottom edge at every breakpoint) ------------ */
/* glass strip at EVERY size so the small labels never sit on raw photo */
.rw-pod {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  width: min(100%, 920px); margin-inline: auto;
  background: rgba(11, 11, 13, .58); border: 1px solid var(--rw-line); border-radius: var(--r-3);
  padding: clamp(.75rem, 1.8vh, 1.15rem) clamp(.3rem, 1.4vw, 1rem);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--sh-top-light), 0 18px 50px rgba(0, 0, 0, .5);
}
.rw-dial { text-align: center; padding-inline: clamp(.35rem, 1.4vw, 1.2rem); min-width: 0; }
.rw-dial + .rw-dial { border-left: 1px solid var(--rw-line); }

/* the gauge face: machined bezel ring + recessed dial + glass highlight */
.rw-dial__gauge {
  position: relative; width: clamp(74px, 19vw, 104px); aspect-ratio: 1 / 1;
  margin: 0 auto .55rem; border-radius: 50%;
  background: radial-gradient(circle at 50% 30%, #24242b, #101014 60%, #0a0a0c);
  box-shadow:
    inset 0 2px 8px rgba(0, 0, 0, .65),      /* recessed face */
    inset 0 -1px 0 rgba(255, 255, 255, .05),
    0 8px 22px rgba(0, 0, 0, .55);
}
/* bezel: brushed metal ring behind the face (visible as the outer rim) */
.rw-dial__gauge::before {
  content: ""; position: absolute; inset: -6px; z-index: -1; border-radius: 50%;
  background: conic-gradient(from 210deg, #40404a, #17171c 22%, #4a4a54 48%, #131318 74%, #40404a);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .08), 0 6px 16px rgba(0, 0, 0, .6);
}
/* glass: lit-from-above highlight across the top of the lens */
.rw-dial__gauge::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(ellipse 95% 55% at 50% -14%, rgba(255, 255, 255, .13), rgba(255, 255, 255, 0) 62%);
}
.rw-dial__gauge svg { position: relative; width: 100%; height: auto; transform: rotate(135deg); }
.rw-dial__ticks { fill: none; stroke: rgba(244, 242, 237, .28); stroke-width: 2.5; stroke-dasharray: 1 4; }
/* major graduations across the 270-degree sweep (pathLength 360; ends in a
   359-unit gap so the pattern cannot repeat into the bottom gap) */
.rw-dial__majors {
  fill: none; stroke: rgba(244, 242, 237, .55); stroke-width: 5;
  stroke-dasharray: 2 31.75 2 31.75 2 31.75 2 31.75 2 31.75 2 31.75 2 31.75 2 31.75 2 359;
  stroke-dashoffset: 1;
}
/* redline zone: last 30 degrees of the sweep */
.rw-dial__red {
  fill: none; stroke: var(--rw-crimson); stroke-width: 3.5; opacity: .8;
  stroke-dasharray: 32 328; stroke-dashoffset: -238;
}
.rw-dial__track { fill: none; stroke: rgba(255, 255, 255, .14); stroke-width: 6; stroke-linecap: round; }
.rw-dial__arc {
  fill: none; stroke: var(--rw-crimson); stroke-width: 6; stroke-linecap: round;
  filter: drop-shadow(0 0 4px var(--rw-crimson-glow));
}
/* needle: crimson pointer + machined hub; the settled rotation is the dial's
   own class below (HDR-039, 2026-09-22: it was a style attribute) and
   heroDials.js animates it through the CSSOM. transform-box makes 50%/50%
   the viewBox centre. */
.rw-dial__needle {
  stroke: var(--rw-crimson-text); stroke-width: 2.4; stroke-linecap: round;
  transform-box: view-box; transform-origin: 50% 50%;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .8));
}
.rw-dial__hub { fill: #101014; stroke: #3d3d46; stroke-width: 2; }
/* Settled states: what each dial shows with scripts off, under reduced
   motion, and before heroDials.js takes over. SWEEP is 2*pi*42*0.75 = 197.92
   (heroDials.js), the offset is SWEEP*(1 - target), the needle target*270deg. */
.rw-dial--t60 .rw-dial__arc { stroke-dasharray: 197.92 263.89; stroke-dashoffset: 79.17; }
.rw-dial--t60 .rw-dial__needle { transform: rotate(162deg); }
.rw-dial--t80 .rw-dial__arc { stroke-dasharray: 197.92 263.89; stroke-dashoffset: 39.58; }
.rw-dial--t80 .rw-dial__needle { transform: rotate(216deg); }
.rw-dial--t100 .rw-dial__arc { stroke-dasharray: 197.92 263.89; stroke-dashoffset: 0; }
.rw-dial--t100 .rw-dial__needle { transform: rotate(270deg); }
.rw-dial.is-settled .rw-dial__num { animation: rw-dial-click .3s var(--rw-ease-out); }
@keyframes rw-dial-click { 0% { transform: scale(1); } 45% { transform: scale(1.07); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .rw-dial.is-settled .rw-dial__num { animation: none; } }
/* reading sits in the bottom gap of the 270-degree sweep, like a real tacho */
.rw-dial__num {
  position: absolute; left: 0; right: 0; bottom: 4%; display: flex; justify-content: center;
  font-family: var(--ff-mono); font-variant-numeric: tabular-nums; font-weight: 600;
  font-size: clamp(.72rem, 2vw, .95rem); color: var(--rw-bone);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}
.rw-dial__label { font-size: var(--fs-xs); color: var(--rw-ash); line-height: 1.3; max-width: 16ch; margin: 0 auto; }
.rw-dial__label b { color: var(--rw-text); display: block; font-weight: 600; }
/* wide readings (4+ digits) shrink to stay inside the bezel at every gauge size */
.rw-dial--wide .rw-dial__num { font-size: clamp(.62rem, 1.7vw, .82rem); letter-spacing: -.03em; }
/* roomier breakpoints: gauge left, label right, one row per instrument cell */
@media (min-width: 720px) {
  .rw-dial {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 1rem;
    align-items: center; text-align: left;
  }
  .rw-dial__gauge { margin: 0; }
  .rw-dial__label { margin: 0; max-width: none; font-size: var(--fs-sm); }
}
/* Compact instrument cluster on phones (2026-07-22, per Ellis): the 3-across
   pod pushed the hero copy below the first fold on small viewports - the
   gauges shrink and the pod tightens so h1 + motto + lead + CTAs land inside
   100svh on 360-430px phones. Desktop/tablet unchanged. */
@media (max-width: 560px) {
  .rw-pod { padding: .55rem .3rem; }
  .rw-dial { padding-inline: .3rem; }
  .rw-dial__gauge { width: clamp(50px, 14vw, 62px); margin-bottom: .4rem; }
  .rw-dial__gauge::before { inset: -4px; }
  .rw-dial__num { font-size: .56rem; bottom: 2%; }
  .rw-dial--wide .rw-dial__num { font-size: .5rem; letter-spacing: -.04em; }
  .rw-dial__label { font-size: .6rem; max-width: 12ch; }
  .rw-hero__deck { padding-bottom: .75rem; }
}

/* ---- Featured lanes (home: two headline services directly under the hero)
   2026-09-08, per Ellis: the grey card ground is now a PHOTO (.rw-lane__bg,
   the same still each lane's service bay uses) under an ink scrim that runs
   heavy on the left, where the copy sits, and thins to the right so the car
   still reads. The crimson left tab is unchanged. The scrim is the ::before,
   the copy is lifted above it, and hover eases the photo up a touch. */
.rw-lanes { display: grid; gap: var(--sp-2); }
@media (min-width: 760px) { .rw-lanes { grid-template-columns: 1fr 1fr; } }
.rw-lane {
  position: relative; display: grid; gap: .55rem; align-content: end; isolation: isolate;
  overflow: hidden; min-height: clamp(240px, 24vw, 320px);
  background: var(--rw-coal);
  border: 1px solid var(--rw-line); border-left: 2px solid var(--rw-crimson);
  border-radius: var(--r-3);
  padding: clamp(1.3rem, 2.6vw, 1.9rem) clamp(1.2rem, 2.6vw, 1.8rem);
  box-shadow: var(--sh-card);
  transition: border-color .2s var(--rw-ease-out), box-shadow .2s var(--rw-ease-out);
}
.rw-lane__bg {
  position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 38%;
  transform: scale(1.02); transition: transform .5s var(--rw-ease-out);
}
.rw-lane::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(11, 11, 13, .88) 0%, rgba(11, 11, 13, .72) 48%, rgba(11, 11, 13, .38) 100%),
    linear-gradient(180deg, rgba(11, 11, 13, .12), rgba(11, 11, 13, .62));
  transition: opacity .2s var(--rw-ease-out);
}
.rw-lane h2 {
  font-size: clamp(1.3rem, 1.05rem + 1.1vw, 1.8rem); color: var(--rw-bone);
  letter-spacing: -.015em; text-wrap: balance;
  text-shadow: 0 1px 2px rgba(11, 11, 13, .6);
}
.rw-lane p { color: var(--rw-text); font-size: .98rem; max-width: 52ch; text-shadow: 0 1px 2px rgba(11, 11, 13, .6); }
.rw-lane .rw-go { margin-top: .3rem; }
.rw-lane:active { transform: scale(.995); }
@media (hover: hover) and (pointer: fine) {
  .rw-lane:hover {
    border-color: rgba(236, 50, 36, .45); border-left-color: var(--rw-crimson);
    box-shadow: var(--sh-card), var(--rw-edge-crimson);
  }
  .rw-lane:hover .rw-lane__bg { transform: scale(1.06); }
  .rw-lane:hover .rw-go { color: var(--rw-crimson); }
}
@media (prefers-reduced-motion: reduce) {
  .rw-lane__bg, .rw-lane:hover .rw-lane__bg { transform: none; transition: none; }
}

/* ---- Before / after comparison slider (home only) ------------------------ */
.rw-ba {
  position: relative; width: 100%; border-radius: var(--r-3); overflow: hidden;
  border: 1px solid var(--rw-line); background: var(--rw-coal); aspect-ratio: 16 / 10;
  touch-action: pan-y;
  box-shadow: var(--sh-2), inset 0 0 0 1px rgba(255,255,255,.05);
}
/* no selection flash while dragging: suppress selection on the whole block */
.rw-ba, .rw-ba * {
  -webkit-user-select: none; -moz-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
.rw-ba img { -webkit-user-drag: none; }
.rw-ba ::selection { background: transparent; }
.rw-ba__img { position: absolute; inset: 0; }
.rw-ba__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rw-ba__img--after { z-index: 1; }
.rw-ba__img--before { z-index: 2; clip-path: inset(0 calc(100% - var(--rw-ba-pos, 50%)) 0 0); }
/* handle + grip clamped inside the frame so the arrows can never leave the window */
.rw-ba__handle {
  position: absolute; top: 0; bottom: 0; z-index: 3;
  left: clamp(28px, var(--rw-ba-pos, 50%), calc(100% - 28px));
  width: 3px; transform: translateX(-1.5px); cursor: ew-resize;
  background: linear-gradient(180deg, var(--rw-crimson), var(--rw-crimson-deep));
  box-shadow: 0 0 14px var(--rw-crimson-glow);
}
.rw-ba__grip {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 46px; height: 46px; border-radius: 50%;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.10) 0 1px, transparent 1px 4px),
    linear-gradient(160deg, #2c2c33, #141417);
  border: 2px solid var(--rw-crimson);
  display: flex; align-items: center; justify-content: center;
  color: var(--rw-crimson-text);
  box-shadow: var(--sh-1), 0 0 0 4px rgba(11,11,13,.45), var(--sh-top-light);
}
.rw-ba__grip svg { width: 22px; height: 22px; }
.rw-ba__tag {
  position: absolute; bottom: .8rem; z-index: 4; font-family: var(--ff-mono); font-size: var(--fs-xs);
  letter-spacing: .04em; text-transform: uppercase; color: var(--rw-bone);
  background: rgba(11,11,13,.66); padding: .3rem .6rem; border-radius: var(--r-1);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  transition: opacity .2s var(--rw-ease-out);
}
.rw-ba__tag--before { left: .8rem; }
.rw-ba__tag--after { right: .8rem; }
.rw-ba__range {
  position: absolute; inset: auto 0 0 0; z-index: 5; width: 100%; opacity: 0; height: 44px; margin: 0;
  cursor: ew-resize;
}
.rw-ba__range:focus-visible ~ .rw-ba__handle {
  box-shadow: 0 0 0 3px var(--rw-crimson), 0 0 14px var(--rw-crimson-glow);
}
@media (prefers-reduced-motion: reduce) { .rw-ba__img--before { transition: none; } }

/* ---- Finish plate (tight spec strip; replaces the tall manifesto) -------- */
.rw-plate__lede {
  font-family: var(--ff-display); font-size: clamp(1.7rem, 1.15rem + 2.4vw, 3rem);
  line-height: 1.06; letter-spacing: -.02em; color: var(--rw-bone); max-width: 22ch;
  margin-bottom: clamp(1.6rem, 3vw, 2.4rem); text-wrap: balance;
}
.rw-plate__lede em { font-style: italic; color: var(--rw-crimson); }
.rw-specs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--rw-line); border-block: 1px solid var(--rw-line);
}
@media (min-width: 880px) { .rw-specs { grid-template-columns: repeat(4, 1fr); } }
.rw-specs--3 { grid-template-columns: 1fr; }
@media (min-width: 880px) { .rw-specs--3 { grid-template-columns: repeat(3, 1fr); } }
/* open-rule variant (about ethos): crimson top rules, no machined plate - deliberately
   a different surface from the home finish plate so the component does not repeat */
.rw-specs--rules { background: transparent; border-block: 0; gap: 1.4rem; }
.rw-specs--rules .rw-spec { background: transparent !important; padding: 1rem 0 0; border-top: 2px solid var(--rw-crimson); }
.rw-spec { background: var(--rw-ink); padding: 1.25rem 1.3rem 1.4rem; }
.rw-bay--coal .rw-spec { background: var(--rw-coal); }
.rw-spec b {
  display: block; font-family: var(--ff-display); font-size: 1.18rem; color: var(--rw-bone);
  letter-spacing: -.01em; margin-bottom: .4rem;
}
.rw-spec p { font-size: var(--fs-sm); color: var(--rw-ash); max-width: 30ch; }

/* ---- Standards sign-off (about, round 15) -------------------------------
   Replaces the SECOND rw-specs--rules strip, which read as a straight repeat
   of the ethos plate. Real bay footage (the polish boomerang alone since
   2026-07-21 - the interior still moved to the gallery jobs wall; mono caption
   strip) beside the standards as a signed-off checklist: bordered crimson
   tick plates + hairline rows - deliberately nothing like the crimson
   top-rule grid above it, and no Pivtech tells. */
.rw-sign { display: grid; gap: clamp(1.8rem, 4vw, 3.2rem); }
@media (min-width: 880px) {
  .rw-sign { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); align-items: center; }
}
.rw-sign__media { display: grid; gap: var(--sp-1); }
/* single tile: below the two-column break the near-square video would blow
   up to a full-frame square - cap and centre it in the stacked layout */
@media (max-width: 879px) {
  .rw-sign__media { max-width: 520px; margin-inline: auto; width: 100%; }
}
.rw-sign__media figure {
  margin: 0; border-radius: var(--r-3); overflow: hidden;
  border: 1px solid var(--rw-line); background: var(--rw-carbon);
  box-shadow: var(--sh-card);
}
.rw-sign__media video, .rw-sign__media img { display: block; width: 100%; height: auto; }
.rw-sign__cap {
  font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash);
  letter-spacing: .02em; padding: .55rem .8rem; border-top: 1px solid var(--rw-line);
}
.rw-sign__list { list-style: none; margin: 0; padding: 0; }
.rw-sign__list li {
  display: flex; align-items: flex-start; gap: 1rem;
  padding-block: clamp(1.1rem, 2.2vw, 1.6rem);
}
.rw-sign__list li + li { border-top: 1px solid var(--rw-line); }
.rw-sign__mark {
  flex: none; display: grid; place-items: center; width: 26px; height: 26px;
  margin-top: .2rem; border: 1px solid var(--rw-line-strong); border-radius: var(--r-1);
  color: var(--rw-crimson); background: rgba(236, 50, 36, .08);
}
.rw-sign__list b {
  display: block; font-family: var(--ff-display); font-size: 1.18rem; color: var(--rw-bone);
  letter-spacing: -.01em; margin-bottom: .35rem;
}
.rw-sign__list p { font-size: var(--fs-sm); color: var(--rw-ash); max-width: 46ch; }

/* ---- Services mosaic (home: flagship panel + four media cards) ----------- */
.rw-mos { display: grid; gap: var(--sp-1); }
.rw-mos__cell {
  position: relative; overflow: hidden; border-radius: var(--r-3);
  border: 1px solid var(--rw-line); min-height: 210px;
  display: flex; align-items: flex-end; background: var(--rw-coal);
}
.rw-mos__cell img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(.28) brightness(.82);
  transition: transform .5s var(--rw-ease-out), filter .35s var(--rw-ease-out);
}
.rw-mos__body {
  position: relative; z-index: 1; width: 100%; padding: 4.5rem 1.3rem 1.25rem;
  /* scrim starts at .35 (never transparent) so headline rows hold AA on light photography */
  background: linear-gradient(180deg, rgba(11,11,13,.35), rgba(11,11,13,.66) 30%, rgba(11,11,13,.94));
}
.rw-mos__body h3 { font-size: clamp(1.2rem, 1rem + .9vw, 1.6rem); color: var(--rw-bone); margin-bottom: .3rem; }
.rw-mos__body p { font-size: var(--fs-sm); color: var(--rw-text); max-width: 44ch; }
.rw-mos__go {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: .65rem;
  color: var(--rw-crimson-text); font-weight: 600; font-size: var(--fs-sm);
}
.rw-mos__cell:active { transform: scale(.995); }
@media (hover: hover) and (pointer: fine) {
  .rw-mos__cell:hover img { transform: scale(1.05); filter: grayscale(0) brightness(.94); }
}
@media (min-width: 900px) {
  .rw-mos { grid-template-columns: 1.2fr 1fr 1fr; grid-auto-rows: 240px; }
  .rw-mos__cell--flag { grid-row: 1 / span 2; }
  .rw-mos__cell--flag .rw-mos__body h3 { font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2.1rem); }
}
/* flagship carries the crimson spine */
.rw-mos__cell--flag { border-color: rgba(236, 50, 36, .4); box-shadow: var(--rw-edge-crimson); }

/* ---- Process (segmented instrument panel; 01 -> 04 in strict DOM order) -- */
.rw-process {
  position: relative; display: grid; gap: 1px; background: var(--rw-line);
  border: 1px solid var(--rw-line); border-radius: var(--r-3); overflow: hidden;
  --rw-proc: 100;
}
.js .rw-process { --rw-proc: 0; }                    /* JS drives it up; no-JS stays full */
@media (prefers-reduced-motion: reduce) { .rw-process { --rw-proc: 100 !important; } }
.rw-process__track { position: absolute; z-index: 2; background: rgba(255,255,255,.06); overflow: hidden; }
.rw-process__track i {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--rw-crimson), var(--rw-crimson-deep));
  box-shadow: 0 0 10px var(--rw-crimson-glow);
}
.rw-step { position: relative; z-index: 1; background: var(--rw-coal);
  padding: clamp(1.15rem, .9rem + 1.2vw, 1.6rem) clamp(1.05rem, .85rem + 1vw, 1.45rem) clamp(1.3rem, 1rem + 1.4vw, 1.8rem); }
.rw-bay--coal .rw-step { background: var(--rw-carbon); }
/* gauge-bar stage marker: stage k lights the first k graduations (no numerals);
   bar geometry: 3px wide, 9px dim / 15px lit - change together */
.rw-gear { display: flex; align-items: flex-end; gap: 4px; height: 15px; }
.rw-gear i {
  width: 3px; height: 9px; border-radius: 1px; background: var(--rw-line-strong);
  transition: background-color .3s var(--rw-ease-out), box-shadow .3s var(--rw-ease-out);
}
.rw-gear i.is-on { height: 15px; background: var(--rw-ash); }
.rw-step.is-lit .rw-gear i.is-on {
  background: var(--rw-crimson); box-shadow: 0 0 8px var(--rw-crimson-glow);
}
.rw-step .rw-gear { margin-bottom: .1rem; }
.rw-step h3 { font-size: var(--fs-h3); color: var(--rw-bone); margin: .5rem 0 .5rem; }
.rw-step p { color: var(--rw-ash); font-size: var(--fs-sm); }
/* mobile: one column, spine fills down the left edge */
@media (max-width: 559px) {
  .rw-process__track { left: 0; top: 0; bottom: 0; width: 3px; }
  .rw-process__track i { transform-origin: top; transform: scaleY(calc(var(--rw-proc) / 100)); }
  .rw-step { padding-left: 1.7rem; }
}
/* >=560px: cells in a row (2x2 then 4-up), progress rail along the top edge */
@media (min-width: 560px) {
  .rw-process { grid-template-columns: repeat(2, 1fr); }
  .rw-process__track { top: 0; left: 0; right: 0; height: 3px; }
  .rw-process__track i { transform-origin: left; transform: scaleX(calc(var(--rw-proc) / 100)); }
}
@media (min-width: 980px) { .rw-process { grid-template-columns: repeat(4, 1fr); } }

/* ---- Work filmstrip (home teaser; horizontal scroll-snap) ---------------- */
.rw-strip {
  display: flex; gap: .9rem; overflow-x: auto; padding-bottom: .8rem;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  scrollbar-color: var(--rw-crimson-deep) var(--rw-carbon); scrollbar-width: thin;
}
/* the strip scrollbar is clearly, permanently visible: crimson thumb at rest */
.rw-strip::-webkit-scrollbar { height: 6px; }
.rw-strip::-webkit-scrollbar-thumb { background: var(--rw-crimson-deep); border-radius: 3px; }
.rw-strip::-webkit-scrollbar-track { background: var(--rw-carbon); border-radius: 3px; }
/* the end arrow is a bare crimson chevron IN the scroll flow, after the last
   card - you scroll to reach it. No circle, no ground; just the pointer. */
.rw-strip__go {
  flex: 0 0 auto; align-self: center; display: inline-flex; align-items: center;
  justify-content: center; min-width: 44px; min-height: 44px; padding-inline: .4rem;
  color: var(--rw-crimson-text); font-size: 2.6rem; line-height: 1;
  transition: color .16s var(--rw-ease-out), transform .16s var(--rw-ease-out);
}
.rw-strip__go span { transform: translateY(-3px); }
.rw-strip__go:active { transform: scale(.95); }
@media (hover: hover) and (pointer: fine) {
  .rw-strip__go:hover { color: var(--rw-crimson); transform: translateX(3px); }
}
/* cards sized so ~2.5-3 show at desktop widths and the strip genuinely
   scrolls to reach the chevron (round 5: too much was visible at rest) */
.rw-strip > a:not(.rw-strip__go) {
  position: relative; flex: 0 0 clamp(240px, 30vw, 380px); scroll-snap-align: start;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-2); overflow: hidden; border: 1px solid var(--rw-line);
  display: block; background: var(--rw-carbon);
}
.rw-strip img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .45s var(--rw-ease-out);
}
.rw-strip__cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 2.6rem .95rem .85rem;
  background: linear-gradient(180deg, rgba(11,11,13,0), rgba(11,11,13,.55) 40%, rgba(11,11,13,.92));
  color: var(--rw-bone); font-size: var(--fs-sm);
}
@media (hover: hover) { .rw-strip a:hover img { transform: scale(1.05); } }

/* ---- Reviews (quotes; clamp + read-more on the reviews page) ------------- */
/* HOME (2026-07-21): exactly three cards styled as centred testimonials at
   EVERY width - the round-5 mobile treatment promoted to desktop - riding
   three-across >=880px and stacking beneath. No lead banner on home (the
   markup dropped data-reviews-lead and sets limit=3); the reviews PAGE
   keeps the banner + support grid (rw-revgrid below). STRETCH-aligned
   (2026-08-04, per Ellis): cards in a row share the row's height so the
   vertical gap between cards is always exactly the grid gap - the old
   align-items:start left ragged column gaps wherever natural heights
   differed. The quote (flex:1 0 auto) absorbs the surplus, so captions land
   flush at the plate foot. Stretch is the REST state only: while any Read
   more is open, reviews.js pins every card at its rest height (inline
   align-self:start + min-height - the WALL PIN, 2026-08-06 per Ellis), so
   opening a card extends ONLY that card, never its row sibling. */
.rw-reviews { display: grid; gap: var(--sp-2); }
@media (min-width: 880px) {
  .rw-reviews { grid-template-columns: repeat(3, 1fr); }
}
/* reviews PAGE grid (round 11 redesign): every support quote reserves the
   full 5-line clamp height (min-height below) so quotes match, and the grid
   STRETCH-aligns (2026-08-04, per Ellis - replacing the 2026-07-23
   align-items:start): a card that earns a Read more button is a button-row
   taller than one that does not, and start-alignment turned that delta into
   an uneven gap above the next card in the column (all cards in a row must
   read a uniform size, gaps identical). The 2026-08-04 "accepted cost"
   (opening a card stretched its row sibling) is RETIRED (2026-08-06, per
   Ellis): while any Read more is open, reviews.js pins every card at its
   rest height (inline align-self:start + min-height - the WALL PIN), so only
   the clicked card extends and stretch governs the rest state alone. */
.rw-revgrid { display: grid; gap: var(--sp-2); }
@media (min-width: 880px) {
  .rw-revgrid { grid-template-columns: 1fr 1fr; }
  .rw-revgrid .rw-quote--lead { grid-column: 1 / -1; }
}
/* A card that would sit alone on the last row spans both columns instead
   (2026-09-04, per Ellis: the two-star floor shortens the wall, and it must
   end flush rather than on a half row). With the lead banner in place the
   support cards pair from index 2, so an orphan is EVEN; without it they
   pair from index 1, so an orphan is ODD - a single card counts. */
.rw-revgrid .rw-quote--lead ~ .rw-quote:last-child:nth-child(even),
.rw-revgrid .rw-quote:not(.rw-quote--lead):first-child:last-child,
.rw-revgrid .rw-quote:not(.rw-quote--lead):first-child ~ .rw-quote:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}
.rw-revgrid .rw-quote blockquote { min-height: 7.5em; }   /* 5 clamp lines x 1.5 line-height */
.rw-revgrid .rw-quote--lead blockquote { min-height: 0; }
.rw-quote__when { margin-left: auto; font-family: var(--ff-mono); font-size: var(--fs-xs);
  color: var(--rw-ash); letter-spacing: 0; }
.rw-revgrid .rw-quote--lead .rw-quote__plate {
  background: linear-gradient(135deg, var(--rw-carbon), #17171c);
}
.rw-revgrid .rw-quote--lead .rw-quote__plate::before {
  content: "\201C"; position: absolute; top: .55rem; left: 1.1rem;
  font-family: var(--ff-display); font-size: 4rem; line-height: 1; color: var(--rw-crimson);
  opacity: .55;
}
.rw-reviews[hidden], .rw-revgrid[hidden] { display: none; }   /* display:grid must not defeat [hidden] */
/* SHELL vs PLATE (2026-07-27): the <figure> is the grid item; every visual
   (ground, border, padding, flex flow, shadow) lives on the inner
   .rw-quote__plate that reviews.js builds, which is also what carries the open
   card's crimson catch and its top seam (see UNROLL IN PLACE below). The plate
   stays IN FLOW at all times - Ellis rejected the out-of-flow overlay version,
   so an open card grows its own height and pushes the cards below it down.
   Style the PLATE, never the shell, or a card will fall out of alignment. */
.rw-quote { position: relative; display: flex; }
.rw-quote__plate {
  position: relative; flex: 1 1 auto; min-width: 0;
  background: var(--rw-carbon); border: 1px solid var(--rw-line); border-radius: var(--r-3);
  padding: clamp(1.25rem, 1rem + 1.2vw, 1.7rem) clamp(1.15rem, .95rem + 1vw, 1.55rem);
  display: flex; flex-direction: column; gap: var(--sp-2); box-shadow: var(--sh-card);
  transition: border-color .35s var(--rw-ease-out), box-shadow .35s var(--rw-ease-out);   /* the open "lift" */
}
.rw-quote__stars { display: inline-flex; align-items: center; gap: .55rem; color: var(--rw-crimson-text);
  letter-spacing: .15em; font-size: .95rem; }
.rw-quote__stars b { font-family: var(--ff-mono); letter-spacing: 0; color: var(--rw-text); font-weight: 600; font-size: var(--fs-sm); }
.rw-quote blockquote { color: var(--rw-text); font-size: 1.05rem; line-height: 1.5; flex: 1 0 auto; }
.rw-quote figcaption { font-size: var(--fs-sm); color: var(--rw-ash); margin-top: auto; }
.rw-quote figcaption b { color: var(--rw-bone); display: block; font-weight: 600; }
.rw-quote--lead .rw-quote__plate { padding: clamp(1.8rem, 4vw, 2.6rem); justify-content: center;
  border-left: 2px solid var(--rw-crimson); }
.rw-quote--lead blockquote { font-family: var(--ff-display); font-size: clamp(1.35rem, 1rem + 1.5vw, 2rem);
  line-height: 1.22; letter-spacing: -.01em; color: var(--rw-bone); text-wrap: pretty; }
.rw-reviews__empty {
  display: grid; gap: .8rem; justify-items: center; text-align: center;
  color: var(--rw-ash); border: 1px dashed var(--rw-line-strong); border-radius: var(--r-3);
  padding: clamp(2rem, 4vw, 3rem);
}
.rw-reviews__empty[hidden] { display: none; }
.rw-reviews__empty p { max-width: 44ch; }
/* Live-feed loading (round 11, true Pivtech parity): the honest empty panel
   is visible from first paint and the cards swap in the moment the feed
   lands - the round-5 blur/timer hold was what read as "blurred and slow"
   and is gone. Do not reintroduce a pending fade. */
/* aggregate rating strip: hidden until reviews.js fills it with real figures;
   styled as an instrument readout line */
.rw-revagg {
  display: inline-flex; align-items: center; gap: .65rem;
  font-family: var(--ff-mono); font-size: var(--fs-sm); color: var(--rw-text);
  margin-bottom: var(--sp-2);
  padding: .55rem .9rem; background: var(--rw-carbon);
  border: 1px solid var(--rw-line); border-left: 2px solid var(--rw-crimson);
  border-radius: var(--r-2);
}
.rw-revagg[hidden] { display: none; }   /* the display above must not defeat [hidden] */
.rw-revagg::before { content: "★"; color: var(--rw-crimson-text); }
/* clamp long quotes behind the .js gate (no-JS reads everything);
   reviews.js only adds the Read more button when the text truly overflows */
.js [data-reviews-clamp] .rw-quote blockquote {
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden;
}
/* READ MORE = UNROLL IN PLACE (2026-07-27, per Ellis - this REPLACES the
   overlay "docket" idiom shipped earlier the same day, which lifted the plate
   out of flow and painted OVER the cards beneath: Ellis rejected it). The card
   now grows IN FLOW and PUSHES the cards below it down; an open review must
   never sit on top of another card, so there is no absolute plate and no
   z-index promotion here.

   The animated box is the BLOCKQUOTE, not the plate: the Read less button and
   the figcaption sit BELOW the quote inside the plate, so animating the plate
   (an overflow-hidden box) clipped them mid-fold. Animating the quote lets
   them ride the fold and stay visible throughout.

   Closing re-clips the text line by line as the height falls (overflow hidden
   on the quote), so the copy shortens IN STEP with the card instead of
   sitting at full length until the fold ends. The promoted look lives on its
   own .is-promoted class, which reviews.js drops on the FIRST click of Read
   less - the crimson catch and the seam leave immediately, not when the fold
   finishes. */
.js [data-reviews-clamp] .rw-quote.is-open blockquote {
  display: block; -webkit-line-clamp: unset; overflow: hidden;
  transition: height .42s var(--rw-ease-out);
}
/* .is-done frees the pinned height so a later re-wrap can never clip the text */
.js [data-reviews-clamp] .rw-quote.is-done blockquote { overflow: visible; }
/* reviews.js sets .is-measuring around its height:auto probe - height is not
   interpolable from/to auto, so the transition MUST be off for that frame.
   flex is pinned to natural too (2026-08-04): under the stretch-aligned grid
   the quote's flex:1 0 auto absorbs a taller row sibling's surplus, so an
   unpinned auto probe would read the STRETCHED height, not the text's own. */
.js [data-reviews-clamp] .rw-quote.is-measuring blockquote {
  transition: none !important; flex: 0 0 auto !important;
}
/* the promoted look: crimson border catch + lift shadow, and the rewind seam
   sweeping the plate's top edge. ON while open, OFF the instant Read less is
   pressed (reviews.js removes .is-promoted before the fold starts). */
.js [data-reviews-clamp] .rw-quote.is-promoted .rw-quote__plate {
  border-color: rgba(236, 50, 36, .5);
  box-shadow: 0 22px 55px -26px rgba(0, 0, 0, .85), var(--sh-card);
}
.js [data-reviews-clamp] .rw-quote.is-promoted .rw-quote__plate::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--rw-crimson), transparent);
  transform: scaleX(1); transform-origin: 50% 50%;
  animation: rw-seam-in .5s var(--rw-ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .js [data-reviews-clamp] .rw-quote.is-open blockquote { transition: none; }
  .js [data-reviews-clamp] .rw-quote.is-promoted .rw-quote__plate::after { animation: none; }
}
/* nothing escapes the grid box now that the growth is in flow, but the open
   card's drop shadow still would: core.css's reduced-motion block forces
   clip-path: inset(0 0 0 0) !important on every [data-rw-reveal], and a
   stylesheet !important beats the inline clipPath:none shell.js writes on
   settle - so the release needs !important too. reviews.js adds .is-in itself
   (no wind-in for this container), so releasing the clip costs no motion. */
.js [data-reviews-clamp] { clip-path: none !important; }
@keyframes rw-seam-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.rw-quote__more {
  align-self: flex-start; color: var(--rw-crimson-text); font-weight: 600; font-size: var(--fs-sm);
  padding: .45rem 0; margin-top: -.6rem; margin-bottom: -.3rem;   /* 44px-friendly target, same rhythm */
}
.rw-quote__more:active { transform: scale(.97); }
@media (hover: hover) { .rw-quote__more:hover { color: var(--rw-crimson); } }
.rw-revcta { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 1.6rem; }
/* Home testimonial card (2026-07-21, ALL widths - was mobile-only round 5):
   centred under an oversized crimson quote mark, the quote itself in the
   display face - deliberately a different card from the reviews-page grid.
   The nth-child guard is belt and braces behind data-reviews-limit="3". */
.rw-reviews .rw-quote:nth-child(n+4) { display: none; }
.rw-reviews .rw-quote__plate { text-align: center; align-items: center; padding-top: 3rem; }
.rw-reviews .rw-quote__plate::before {
  content: "\201C"; position: absolute; top: .35rem; left: 50%; transform: translateX(-50%);
  font-family: var(--ff-display); font-size: 3.4rem; line-height: 1; color: var(--rw-crimson);
}
.rw-reviews .rw-quote blockquote {
  font-family: var(--ff-display); font-style: italic; font-size: 1.08rem; line-height: 1.45;
  letter-spacing: -.01em; color: var(--rw-text); flex: none;
}
.rw-reviews .rw-quote__stars { justify-content: center; }
.rw-reviews .rw-quote__stars .rw-quote__when { margin-left: 0; }   /* centred row: no push-right */
.rw-reviews .rw-quote figcaption { margin-top: 0; }
.rw-reviews .rw-quote figcaption b { display: block; }
.rw-reviews .rw-quote__more { align-self: center; }

/* ---- FAQ (custom disclosure) --------------------------------------------- */
.rw-faq { display: grid; max-width: 760px; }
.rw-q { border-top: 1px solid var(--rw-line); position: relative; z-index: 0; }
.rw-q:last-child { border-bottom: 1px solid var(--rw-line); }
.rw-q > summary {
  display: flex; align-items: center; gap: 1rem; justify-content: space-between;
  padding: 1.2rem 0; cursor: pointer; list-style: none; color: var(--rw-bone);
  font-family: var(--ff-display); font-size: var(--fs-h3); font-weight: 600;
  transition: color .2s var(--rw-ease-out);
}
.rw-q > summary::-webkit-details-marker { display: none; }
.rw-q > summary:active { transform: scale(.995); transform-origin: left; }
@media (hover: hover) and (pointer: fine) { .rw-q > summary:hover { color: var(--rw-crimson-text); } }
/* open wash bleeds from the viewport's left edge (z-index:0 on .rw-q makes a
   stacking context so the -1 pseudo stays above the section ground). It exists
   in BOTH states, clipped shut, so opening SWEEPS it out of the viewport edge
   (clip-path, not scaleX, keeps the gradient unstretched). The transition
   lives ONLY on the open state (round 5): opening animates, closing snaps -
   the base state owns no transition, so removing [open] applies instantly.
   Reduced-motion: the global kill switch zeroes the transition. */
.rw-q::before {
  content: ""; position: absolute; z-index: -1; top: 0; bottom: 0; right: 0;
  left: calc(50% - 50vw); pointer-events: none;
  background: linear-gradient(90deg, rgba(236,50,36,.12), rgba(236,50,36,.05) 48%, transparent 80%);
  clip-path: inset(0 100% 0 0);
}
.rw-q[open]::before {
  clip-path: inset(0 0 0 0);
  transition: clip-path .5s var(--rw-ease-out);
}
.rw-q[open] > summary { color: var(--rw-crimson-text); }
.rw-q__sign { flex: none; width: 22px; height: 22px; position: relative;
  transition: transform .28s var(--rw-ease-out); }
.rw-q[open] .rw-q__sign { transform: rotate(90deg); }
.rw-q__sign::before, .rw-q__sign::after {
  content: ""; position: absolute; background: currentColor; border-radius: 2px; color: var(--rw-crimson);
  transition: transform .22s var(--rw-ease-out), opacity .22s var(--rw-ease-out);
}
.rw-q[open] .rw-q__sign::before, .rw-q[open] .rw-q__sign::after { color: var(--rw-crimson-text); }
.rw-q__sign::before { top: 10px; left: 0; width: 22px; height: 2px; }
.rw-q__sign::after { top: 0; left: 10px; width: 2px; height: 22px; }
.rw-q[open] .rw-q__sign::after { transform: rotate(90deg); opacity: 0; }
.rw-q__body { padding-bottom: 1.3rem; color: var(--rw-text); }
.rw-q__body p { max-width: 64ch; }
.rw-q[open] .rw-q__body { animation: rw-q-open .3s var(--rw-ease-out); }
@keyframes rw-q-open { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .rw-q[open] .rw-q__body { animation: none; } }

/* ---- Interior page header (cockpit banner: lit coal panel, mono context
        tick, crimson dash on the base line; content starts tight under the
        fixed header - no dead ink gap) ----------------------------------- */
.rw-phead {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, var(--rw-coal), var(--rw-ink));
  border-bottom: 1px solid var(--rw-line);
  padding-block: clamp(2.1rem, 2vw + .9rem, 3.6rem) clamp(1.8rem, 3vw, 3rem);
}
.rw-phead::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 90% 75% at 16% 0%, rgba(255, 255, 255, .05), transparent 62%);
}
.rw-phead::after {
  content: ""; position: absolute; left: 0; bottom: -1px; width: 96px; height: 2px;
  background: linear-gradient(90deg, var(--rw-crimson), transparent);
  box-shadow: 0 0 12px var(--rw-crimson-glow);
}
.rw-phead__tick {
  display: inline-flex; align-items: center; gap: .65rem;
  font-family: var(--ff-mono); font-size: var(--fs-mono); color: var(--rw-ash);
  letter-spacing: .02em; margin-bottom: 1.25rem;
}
/* its ::before shift-light blades are defined with .rw-tick in core.css */
.rw-phead h1 { font-size: clamp(2.2rem, 1.4rem + 3vw, 4rem); color: var(--rw-bone); max-width: 20ch;
  letter-spacing: -.022em; line-height: 1.02; text-wrap: balance; }
.rw-phead .rw-lead { margin-top: 1.1rem; }

/* ---- Anatomy of a repair (Work: scroll-scrubbed teardown, round 5) ---------
   30 keyframes of the transparent red 1 Series scrub with scroll on a sticky
   lit stage. anatomy.js adds .is-live and builds the canvas, callout boxes
   and leader-line svg from the sheet list; WITHOUT .is-live (no-JS, reduced
   motion, missing APIs) the poster + sheet render as a plain readable spread
   and none of the scrub rules apply - nothing dead ever ships. Callouts
   crossfade per phase (opacity+blur, staggered via --i); leader lines are
   1px hairlines from box edge to a crimson anchor dot, kept LIVE at phone
   widths too (round 8), where the boxes shrink into corner slots that leave
   the car clear. Reduced-motion safe: the static path never scrubs and the
   global kill switch flattens every transition. */
.rw-anat { position: relative; }

/* static / no-JS spread: the first frame + the sheet as a readable list */
.rw-anat__bed { position: relative; }
.rw-anat__poster { width: 100%; height: auto; }
.rw-anat__view { margin: 0; position: relative; }
.rw-anat__sheet { margin: 1.6rem 0 0; padding: 0; list-style: none; display: grid; gap: 1.1rem; }
.rw-anat__sheet li { border-top: 1px solid var(--rw-line); padding-top: 1rem; }
.rw-anat__sheet h3 { font-size: 1.15rem; color: var(--rw-bone); margin-bottom: .35rem; }
.rw-anat__sheet p { color: var(--rw-ash); font-size: var(--fs-sm); max-width: 68ch; }
@media (min-width: 880px) {
  .rw-anat__sheet { grid-template-columns: 1fr 1fr; gap: 1.1rem 2.2rem; }
  .rw-anat:not(.is-live) .rw-anat__bed { max-width: 640px; margin-inline: auto; }
}

/* phase readout exists only on the live stage */
.rw-anat__phase { display: none; }

/* ---- live scrub (anatomy.js adds .is-live) ---- */
.rw-anat.is-live .rw-anat__scrub { height: 320vh; }
.rw-anat.is-live .rw-anat__view {
  position: sticky;
  /* equal air above and below the stage (round 15's top: --top-h /
     height: 100svh - --top-h sat flush under the header and touched the
     fold on desktop; the gap fixes that at every width). SVH, not dvh
     (2026-08-12, per Ellis): dvh re-resolves live as mobile chrome
     collapses/expands, so the pinned stage grew/shrank mid-scroll - the
     flex-centred car bobbed with every direction change and the tab bar,
     and anatomy.js's travel (scrub height - view height) jumped the drawn
     frame with no scroll. svh is constant, so the stage holds one size and
     position and the scrub moves only with real scroll; it also keeps the
     whole stage inside the worst-case visible viewport, so pin-in (p=0)
     always means fully in view. Cost accepted: a dead band opens under the
     stage once the chrome collapses (the reason round 15 picked dvh) -
     static beats centred. Desktop unchanged (svh = dvh there); vh fallback
     for engines without svh. */
  --anat-gap: clamp(14px, 2.4vh, 30px);
  top: calc(var(--top-h) + var(--anat-gap));
  height: calc(100vh - var(--top-h) - (2 * var(--anat-gap)));
  height: calc(100svh - var(--top-h) - (2 * var(--anat-gap)));
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--rw-line); border-radius: var(--r-3); overflow: hidden;
  /* the lit stage plate is BACK (round 7): the frames were keyed transparent
     (border flood-fill + feather - see MANIFEST), so the car floats on the
     spotlight ground again like the original cutout did */
  background: radial-gradient(ellipse 85% 70% at 50% 46%, #232320, #1d1d19 55%, #141412);
  box-shadow: var(--sh-card);
}
.rw-anat.is-live .rw-anat__view::after {   /* edge vignette: one surface */
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  box-shadow: inset 0 0 90px rgba(11, 11, 13, .5), var(--sh-top-light);
}
.rw-anat.is-live .rw-anat__bed { width: min(78vh, 92%); max-width: 820px; aspect-ratio: 1 / 1; flex: none; }
.rw-anat.is-live .rw-anat__bed::after {    /* crimson floor glow under the car */
  content: ""; position: absolute; left: 10%; right: 10%; bottom: 13%; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(236, 50, 36, .4) 30%, rgba(236, 50, 36, .4) 70%, transparent);
  filter: blur(1px);
}
.rw-anat.is-live .rw-anat__poster { display: none; }
.rw-anat__canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.rw-anat.is-live .rw-anat__sheet { display: none; }

/* phase readout: bottom-left instrument line */
.rw-anat.is-live .rw-anat__phase {
  display: block; position: absolute; left: 1.1rem; bottom: .95rem; z-index: 4;
  font-size: var(--fs-mono); color: var(--rw-ash); letter-spacing: .04em; margin: 0;
}
.rw-anat__phase b { color: var(--rw-crimson-text); font-weight: 600; }

/* leader-line overlay (svg, built by JS; spans the whole view) */
.rw-anat__lines { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.rw-anat__lines line {
  stroke: var(--rw-line-strong); stroke-width: 1;
  opacity: 0; transition: opacity .3s var(--rw-ease-out);
}
.rw-anat__lines circle {
  fill: var(--rw-crimson); opacity: 0; transition: opacity .3s var(--rw-ease-out);
  filter: drop-shadow(0 0 6px var(--rw-crimson-glow));
}
.rw-anat__lines line.is-on, .rw-anat__lines circle.is-on { opacity: 1; }

/* callout boxes: blurred-glass chips with the crimson spine, edge columns */
.rw-anat__call {
  position: absolute; z-index: 3; width: min(240px, 26%);
  background: rgba(28, 28, 33, .82); border: 1px solid var(--rw-line);
  border-left: 2px solid var(--rw-crimson); border-radius: var(--r-2);
  padding: .75rem .85rem .8rem;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: var(--sh-1);
  opacity: 0; filter: blur(6px); transform: translateY(6px); pointer-events: none;
  transition: opacity .4s var(--rw-ease-out), filter .4s var(--rw-ease-out),
              transform .4s var(--rw-ease-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.rw-anat__call.is-on { opacity: 1; filter: none; transform: none; pointer-events: auto; }
.rw-anat__call--l { left: .9rem; }
.rw-anat__call--r { right: .9rem; }
.rw-anat__call h3 {
  font-family: var(--ff-mono); font-size: var(--fs-xs); font-weight: 600;
  color: var(--rw-bone); letter-spacing: .03em; text-transform: uppercase; margin: 0 0 .3rem;
}
.rw-anat__call p { font-size: .82rem; line-height: 1.45; color: var(--rw-ash); margin: 0; max-width: none; }

/* phones (round 9): REAL compact callout boxes whose slots MOVE with the
   phase (each phase lays its boxes out differently - corners AND mid-band
   positions near their features), copy clamped to two lines, leader lines +
   dots LIVE (anatomy.js picks the box edge nearest the anchor at these
   widths). The centred readout at the stage base carries progress as a live
   percentage (anatomy.js; since round 15 every width reads the percentage). */
@media (max-width: 879px) {
  .rw-anat.is-live .rw-anat__scrub { height: 260vh; }
  .rw-anat.is-live .rw-anat__bed { width: min(64vh, 96%); }
  .rw-anat__call, .rw-anat__call--l, .rw-anat__call--r {
    left: .8rem; right: auto; top: .75rem !important; width: min(43%, 195px);
    padding: .55rem .65rem .6rem;
  }
  /* phones carry the zones' data-short line (swapped in by anatomy.js), so
     nothing truncates */
  .rw-anat__call p { font-size: .72rem; line-height: 1.4; }
  .rw-anat__call h3 { margin: 0 0 .25rem; }
  /* per-phase slot layouts: every phase mixes corner and MID-BAND positions
     (none pinned to the stage base - the readout owns that band) */
  /* phase 1 - walkaround: glass line top-left, wheels mid-low left, paint high-right */
  .rw-anat__call[data-phase="1"][data-slot="1"] { top: auto !important; bottom: 18%; }
  .rw-anat__call[data-phase="1"][data-slot="2"] { top: 16% !important; left: auto; right: .9rem; }
  /* phase 2 - under the bonnet: both features sit left, so the boxes stagger
     down the left edge (bonnet high, engine bay mid-low) */
  .rw-anat__call[data-phase="2"][data-slot="1"] { top: auto !important; bottom: 20%; }
  /* phase 3 - full teardown: doors mid-high left, boot top-right, interior mid-low right */
  .rw-anat__call[data-phase="3"][data-slot="0"] { top: 18% !important; }
  .rw-anat__call[data-phase="3"][data-slot="1"] { top: .75rem !important; left: auto; right: .9rem; }
  .rw-anat__call[data-phase="3"][data-slot="2"] { top: auto !important; bottom: 16%; left: auto; right: .9rem; }
  .rw-anat.is-live .rw-anat__phase {
    left: 50%; right: auto; bottom: .6rem; transform: translateX(-50%);
    white-space: nowrap;
  }
}

/* ---- Work category index (filter; nothing like a chip row) --------------- */
.rw-worklayout { display: grid; gap: 1.8rem; align-items: start; }
/* gallery.js scrolls here after a filter shrinks the page - clear the bar */
#jobs-h { scroll-margin-top: calc(var(--top-h) + 1.25rem); }
@media (min-width: 960px) { .rw-worklayout { grid-template-columns: 220px minmax(0, 1fr); gap: 2.4rem; } }
/* mobile: WRAPPING segment bar (nothing hidden off-screen, no scroll affordance needed) */
.rw-windex { display: flex; flex-wrap: wrap; gap: .1rem .35rem; }
/* the index is inert without JS (all jobs already visible), so hide it no-JS */
html:not(.js) .rw-windex { display: none; }
.rw-windex button {
  flex: none; display: inline-flex; align-items: center; gap: .6rem;
  padding: .7rem .95rem; color: var(--rw-ash); font-weight: 600; font-size: .95rem;
  border-bottom: 2px solid var(--rw-line); white-space: nowrap;
  transition: color .16s var(--rw-ease-out), border-color .16s var(--rw-ease-out),
              background-color .16s var(--rw-ease-out);
}
.rw-windex button:active { transform: scale(.97); }
.rw-windex .rw-windex__n { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash); }
.rw-windex button[aria-pressed="true"] { color: var(--rw-bone); border-bottom-color: var(--rw-crimson); }
.rw-windex button[aria-pressed="true"] .rw-windex__n { color: var(--rw-crimson-text); }
@media (hover: hover) { .rw-windex button:hover { color: var(--rw-bone); } }
@media (min-width: 960px) {
  /* pin below the fixed top header */
  .rw-windex { position: sticky; top: calc(var(--top-h) + 1.25rem); flex-direction: column; flex-wrap: nowrap; }
  .rw-windex button {
    justify-content: space-between; text-align: left; padding: .75rem 1rem .75rem 1.05rem;
    border-bottom: 0; border-left: 2px solid var(--rw-line); white-space: normal;
  }
  .rw-windex button[aria-pressed="true"] {
    border-left-color: var(--rw-crimson);
    background: linear-gradient(90deg, rgba(236, 50, 36, .08), transparent 72%);
  }
}

/* ---- Jobs grid ------------------------------------------------------------ */
.rw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: var(--sp-2); }
.rw-job { border-radius: var(--r-3); overflow: hidden; border: 1px solid var(--rw-line); background: var(--rw-carbon); box-shadow: var(--sh-card); }
.rw-job__media { aspect-ratio: 4/3; overflow: hidden; }
.rw-job__media img { width: 100%; height: 100%; object-fit: cover;
  transition: transform .45s var(--rw-ease-out); }
.rw-job__body { padding: .95rem 1.05rem 1.2rem; }
/* quiet ash category tag: crimson is reserved for the active filter + hover states */
.rw-job__cat { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash); }
.rw-job h3 { font-size: 1.1rem; color: var(--rw-bone); margin: .35rem 0 .4rem; }
.rw-job p { font-size: var(--fs-sm); color: var(--rw-ash); }
.rw-job[hidden] { display: none; }
@media (hover: hover) { .rw-job:hover .rw-job__media img { transform: scale(1.04); } }

/* ---- Services anchor rail (horizontal, in the page header; underline idiom
        shared with the work index - deliberately NOT a chip row, and not the
        work page's sticky side column) ------------------------------------ */
.rw-svcrail { display: flex; flex-wrap: wrap; justify-content: center; gap: .1rem .35rem; margin-top: 1.6rem; }
.rw-svcrail a {
  flex: none; padding: .6rem .9rem;
  font-family: var(--ff-mono); font-size: var(--fs-sm); color: var(--rw-ash);
  transition: color .16s var(--rw-ease-out);
}
.rw-svcrail a:active { transform: scale(.97); }
/* scrollspy state (initSvcRail): the bay in view lights its rail link */
.rw-svcrail a.is-here { color: var(--rw-crimson-text); }
@media (hover: hover) and (pointer: fine) {
  .rw-svcrail a:hover { color: var(--rw-crimson-text); }
}
.rw-bays { display: grid; gap: 1.4rem; }
/* one surface per bay: the photo fills the whole card and the copy sits over
   it on a bottom-heavy ink scrim, so image and text read as a single panel */
.rw-baycard { position: relative; border: 1px solid var(--rw-line); border-radius: var(--r-3);
  overflow: hidden; background: var(--rw-coal); box-shadow: var(--sh-card);
  min-height: clamp(340px, 42vw, 440px); display: flex; flex-direction: column;
  transition: transform .2s var(--rw-ease-out), border-color .2s var(--rw-ease-out); }
.rw-baycard--flag { min-height: clamp(400px, 48vw, 520px); }
.rw-baycard__media { position: absolute; inset: 0; overflow: hidden; background: var(--rw-coal); }
.rw-baycard__media img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(.15) brightness(.9);
  transition: transform .45s var(--rw-ease-out); }
@media (hover: hover) and (pointer: fine) {
  .rw-baycard:hover { transform: translateY(-3px); border-color: rgba(236, 50, 36, .35); }
  .rw-baycard:hover .rw-baycard__media img { transform: scale(1.03); }
}
.rw-baycard__body {
  position: relative; z-index: 1; margin-top: auto;
  padding: clamp(5rem, 12vw, 8rem) clamp(1.3rem, 2.5vw, 1.8rem) clamp(1.3rem, 2.5vw, 1.8rem);
  background: linear-gradient(180deg, rgba(11, 11, 13, 0), rgba(11, 11, 13, .62) 26%, rgba(11, 11, 13, .9) 52%, rgba(11, 11, 13, .96));
}
.rw-baycard__body h2 { font-size: clamp(1.4rem, 1.1rem + 1.2vw, 1.9rem); color: var(--rw-bone); margin-bottom: .55rem; }
.rw-baycard__body > p { color: var(--rw-text); margin-bottom: .9rem; max-width: 62ch; }
.rw-baycard--flag { border-color: rgba(236, 50, 36, .4); box-shadow: var(--sh-card), var(--rw-edge-crimson); }
.rw-svc-covers { display: grid; gap: .35rem; margin: 0 0 1.1rem; padding-left: 1.15rem; color: var(--rw-ash); font-size: var(--fs-sm); }
.rw-svc-covers li { list-style: disc; }
.rw-go { display: inline-flex; align-items: center; gap: .4rem; color: var(--rw-crimson-text);
  font-weight: 600; font-size: var(--fs-sm); padding-block: .4rem; }
@media (hover: hover) { .rw-go:hover { color: var(--rw-crimson); } }
:target { scroll-margin-top: calc(var(--top-h) + 1.5rem); }

/* ---- Story split / media pair (about, contact) ---------------------------- */
.rw-split { display: grid; gap: clamp(1.6rem, 4vw, 3rem); align-items: center; }
.rw-split__media { border-radius: var(--r-3); overflow: hidden; border: 1px solid var(--rw-line); }
.rw-split__media img, .rw-split__media video { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/3; }
@media (min-width: 820px) { .rw-split { grid-template-columns: 1fr 1fr; } }

/* ---- Auto electric installs (about, 2026-09-04) ---------------------------
   Replaced the team 3-up (rw-team / rw-member, deleted with it). One photo
   with a mono caption strip beside a two-column FIT LIST: display titles
   with a short crimson dash, hairline rows - deliberately not the boxed
   tick plates of rw-sign two sections down, nor the crimson top-rule grid
   of the ethos plate above. */
.rw-elec { display: grid; gap: clamp(1.8rem, 4vw, 3.2rem); }
@media (min-width: 880px) {
  .rw-elec { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: center; }
}
.rw-elec__media {
  margin: 0; border-radius: var(--r-3); overflow: hidden;
  border: 1px solid var(--rw-line); background: var(--rw-carbon); box-shadow: var(--sh-card);
}
/* stacked: the portrait photo would otherwise run the full frame width */
@media (max-width: 879px) { .rw-elec__media { max-width: 520px; width: 100%; margin-inline: auto; } }
.rw-elec__media img { display: block; width: 100%; height: auto; }
.rw-elec__cap {
  font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash);
  letter-spacing: .02em; padding: .55rem .8rem; border-top: 1px solid var(--rw-line);
}
.rw-elec__body .rw-head { margin-bottom: clamp(1.1rem, 2.2vw, 1.6rem); }
.rw-fit { list-style: none; margin: 0 0 1.5rem; padding: 0; display: grid; gap: 0 2rem; }
@media (min-width: 640px) { .rw-fit { grid-template-columns: 1fr 1fr; } }
.rw-fit li { position: relative; padding: 1rem 0 1.05rem 1.25rem; border-top: 1px solid var(--rw-line); }
.rw-fit li::before {
  content: ""; position: absolute; left: 0; top: 1.62rem; width: .7rem; height: 2px;
  background: var(--rw-crimson);
}
.rw-fit b {
  display: block; font-family: var(--ff-display); font-size: 1.12rem; color: var(--rw-bone);
  letter-spacing: -.01em; margin-bottom: .3rem;
}
.rw-fit p { font-size: var(--fs-sm); color: var(--rw-ash); max-width: 34ch; }

/* ---- Sponsorship (sponsorship.html + the home community band, 2026-09-08,
   per Ellis) ------------------------------------------------------------
   The page is deliberately OFF the nav (reached from the home band, the
   sitemap and direct links). Split: one photo with a mono caption beside
   the community copy and a .rw-fit list of the kinds of support; then the
   "how to ask" block: heading beside the three-step gear ledger, actions
   under both. The home band is one bordered coal plate with a crimson top
   rule: copy left, a line button right. */
.rw-club { display: grid; gap: clamp(1.8rem, 4vw, 3.2rem); }
@media (min-width: 880px) {
  .rw-club { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: center; }
}
.rw-club__media {
  margin: 0; border-radius: var(--r-3); overflow: hidden;
  border: 1px solid var(--rw-line); background: var(--rw-carbon); box-shadow: var(--sh-card);
}
@media (max-width: 879px) { .rw-club__media { max-width: 520px; width: 100%; margin-inline: auto; } }
.rw-club__media img { display: block; width: 100%; height: auto; }
.rw-club__cap {
  font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash);
  letter-spacing: .02em; padding: .55rem .8rem; border-top: 1px solid var(--rw-line);
}
.rw-club__body .rw-head { margin-bottom: 1rem; }
.rw-club__body > p { color: var(--rw-text); max-width: 56ch; margin-bottom: clamp(1.1rem, 2.2vw, 1.6rem); }
.rw-club__ask { display: grid; gap: clamp(1.6rem, 3.5vw, 2.6rem); }
@media (min-width: 880px) {
  .rw-club__ask { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: start; }
  .rw-club__ask .rw-head { margin-bottom: 0; }
  .rw-club__actions { grid-column: 1 / -1; }
}
.rw-club__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.6rem; }
.rw-club__note { font-size: var(--fs-sm); color: var(--rw-ash); }
.rw-club__note a { color: var(--rw-bone); text-decoration: underline; text-decoration-color: var(--rw-crimson); text-underline-offset: .18em; }
@media (hover: hover) { .rw-club__note a:hover { color: var(--rw-crimson-text); } }

.rw-backing {
  position: relative; display: grid; gap: 1.4rem 2.5rem; align-items: center;
  background: linear-gradient(180deg, var(--rw-coal), var(--rw-ink));
  border: 1px solid var(--rw-line); border-top: 2px solid var(--rw-crimson); border-radius: var(--r-3);
  padding: clamp(1.5rem, 3vw, 2.4rem) clamp(1.3rem, 3vw, 2.4rem);
  box-shadow: var(--sh-card);
}
@media (min-width: 880px) { .rw-backing { grid-template-columns: minmax(0, 1fr) auto; } }
.rw-backing .rw-tick { margin-bottom: .9rem; }
.rw-backing h2 { font-size: var(--fs-h2); color: var(--rw-bone); letter-spacing: -.018em; margin-bottom: .7rem; }
.rw-backing p { color: var(--rw-text); max-width: 58ch; }

/* ---- Workshop tour (about; asymmetric captioned band) --------------------- */
.rw-tour { display: grid; gap: 1rem; }
.rw-tour figure { margin: 0; border-radius: var(--r-2); overflow: hidden; border: 1px solid var(--rw-line);
  display: flex; flex-direction: column; }
.rw-tour img { width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.rw-tour figcaption { padding: .7rem .9rem; font-size: var(--fs-sm); color: var(--rw-ash);
  background: var(--rw-carbon); border-top: 1px solid var(--rw-line); margin-top: auto; }
@media (min-width: 760px) {
  .rw-tour { grid-template-columns: 1.55fr 1fr; }
  .rw-tour figure:first-child { grid-row: 1 / span 2; }
  /* the tall tile FILLS the two rows the right column sets (flex: 1 + cover);
     its own intrinsic height must never be the thing that sizes those rows.
     A portrait photo at `auto` (2026-09-04, the underside-on-the-lift shot)
     did exactly that and left dead space under the two right-hand images, so
     the intrinsic contribution is pinned square: below the right column's
     height at every width from the 760px break up, then stretched. */
  .rw-tour figure:first-child img { aspect-ratio: 1 / 1; flex: 1; min-height: 0; }
}

/* ---- Contact / estimate panels -------------------------------------------- */
.rw-panel { background: var(--rw-carbon); border: 1px solid var(--rw-line); border-radius: var(--r-3);
  padding: clamp(1.4rem, 3vw, 2.2rem); box-shadow: var(--sh-card); }
.rw-panel > h2 { font-size: var(--fs-h3); color: var(--rw-bone); margin-bottom: 1.2rem; }
.rw-contactgrid { display: grid; gap: 1.4rem; align-items: start; }
@media (min-width: 980px) {
  .rw-contactgrid { grid-template-columns: 1.15fr .85fr; }
  /* the form pins while the longer workshop column scrolls (sticky must live
     on the GRID ITEM, mirroring the estimate aside) */
  .rw-contactgrid > .rw-panel:first-child { position: sticky; top: calc(var(--top-h) + 1.25rem); }
}
.rw-panel .rw-split__media { margin-top: 1.4rem; }

.rw-estgrid { display: grid; gap: 1.4rem; align-items: start; }
@media (min-width: 1020px) { .rw-estgrid { grid-template-columns: minmax(0, 1.25fr) minmax(260px, .75fr); gap: 2rem; } }
.rw-fieldset { border: 1px solid var(--rw-line); border-radius: var(--r-3); background: var(--rw-carbon);
  padding: 1.2rem 1.3rem 1.35rem; margin: 0 0 1.1rem; min-inline-size: 0; }
/* legend as a machined chip, not the browser's notched-border default */
.rw-fieldset legend { font-family: var(--ff-display); font-weight: 600; color: var(--rw-bone);
  font-size: .98rem; padding: .3rem .7rem; letter-spacing: -.01em;
  background: var(--rw-coal); border: 1px solid var(--rw-line); border-radius: var(--r-1); }
.rw-fieldset .rw-field:last-child { margin-bottom: 0; }
.rw-nextsteps { display: grid; gap: 1rem; }
/* sticky must live on the GRID ITEM (the aside): a nested sticky inside a
   content-height item has zero travel and never pins */
@media (min-width: 1020px) { .rw-estgrid > aside { position: sticky; top: calc(var(--top-h) + 1.25rem); } }
.rw-nextsteps li { display: grid; grid-template-columns: auto 1fr; gap: .9rem; align-items: start;
  border-top: 1px solid var(--rw-line); padding-top: .9rem; list-style: none; }
.rw-nextsteps ol, ol.rw-nextsteps { padding: 0; margin: 0; }
.rw-nextsteps .rw-gear { padding-top: .45rem; }
.rw-nextsteps .rw-gear i.is-on { background: var(--rw-crimson); box-shadow: 0 0 8px var(--rw-crimson-glow); }
.rw-nextsteps b { color: var(--rw-bone); display: block; margin-bottom: .15rem; }
.rw-nextsteps p { font-size: var(--fs-sm); color: var(--rw-ash); }

/* ---- Find-the-workshop directions card (contact; link-out, no map iframe) -- */
.rw-findus { display: grid; gap: .8rem; justify-items: start;
  border-top: 1px solid var(--rw-line); padding-top: 1.2rem; margin-top: 1.4rem; }
.rw-findus h3 { font-size: var(--fs-h3); color: var(--rw-bone); }
.rw-findus p { color: var(--rw-text); }

/* ---- Spec list (definition rows; contact info) ---------------------------- */
.rw-deflist { display: grid; gap: 1rem; }
.rw-deflist > div { display: grid; gap: .2rem; border-top: 1px solid var(--rw-line); padding-top: .9rem; }
.rw-deflist dt { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--rw-ash); }
.rw-deflist dd { color: var(--rw-bone); margin: 0; }

/* ---- Prose (legal pages) --------------------------------------------------- */
.rw-prose h2 { font-size: var(--fs-h3); color: var(--rw-bone); margin: 1.9rem 0 .6rem;
  padding-top: 1.2rem; border-top: 1px solid var(--rw-line); }
.rw-prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.rw-prose p { color: var(--rw-text); margin-bottom: .7rem; max-width: 68ch; }
/* Prose links are crimson, but a BUTTON dropped into prose keeps its own face:
   .rw-act paints white on crimson-deep and this rule outranks it (0,1,1 beats
   0,1,0, and modules.css loads second), which left the cookies page's "Cookie
   preferences" button reading crimson-on-crimson at 1.48:1. */
.rw-prose a:not(.rw-act) { color: var(--rw-crimson-text); }

/* ---- Section heading helper ------------------------------------------------ */
.rw-head { max-width: 56ch; margin-bottom: clamp(1.8rem, 3vw, 2.8rem); }
.rw-head h2 { font-size: var(--fs-h2); color: var(--rw-bone); letter-spacing: -.018em; }
.rw-head p { margin-top: .9rem; color: var(--rw-text); font-size: var(--fs-lead); }
.rw-head--row { max-width: none; display: flex; flex-wrap: wrap; gap: 1rem 2rem;
  align-items: flex-end; justify-content: space-between; }
.rw-head--row > div { max-width: 56ch; }
