@import '../tokens.css?v=a555c920';
@import './project-colours.css?v=28cf698b';

/* ── No Road Block — the story ──────────────────────────────────────────
 * The No Road Block EXTENSION of the shared story structure
 * (css/page/story.css: cover, spine, spreads, plates, statements, spec,
 * numbers, list, performances, the specimen phone, the results plane,
 * close). This file carries only what is No Road Block's: the cover (the
 * product's own dark map, rendered from the site's code, with the trail
 * drawing itself and the five gates dealing in), the mark's entrance, the
 * pitch (the sticker at the gate resolving into the status page), the
 * report (the live site rebuilt as a specimen and used), the results
 * plane in brand blue, the plates and the close.
 * Page: ux-case-studies/no-road-block.html.
 * Driver: js/page/story.js (shared). No page JS of its own: every
 * performance is CSS on the shared --st-perf timeline.
 *
 * The brand blue and the product paper are project constants from
 * project-colours.css; the product's status inks, chrome greys and scrim
 * are SPECIMEN constants (the live site's data/tokens.js, light theme;
 * its dark-theme statuses on the cover), declared once below with a
 * comment. Everything else sits on the tokens and the ten type roles.
 *
 * Every performance follows the shared recipe: base styles are the END
 * state and keyframes start from the beginning, so an engine without
 * scroll timelines — and reduced motion, which strips the animations —
 * shows the finished composition. */

/* ── Specimen constants — the product's own paint ──────────────────────
 * From noroadblock.com's data/tokens.js. The statuses are the product's
 * (light theme on the phone, the lifted dark-theme tints on the cover's
 * night map); the scrim is its halftone wash; the greys its quiet ink. */
.nrb-cover,
.nrb-phone {
  --nrb-card: #ffffff;                 /* the product's card white — a light GROUND, the mirror of --color-plane-dark */
  --nrb-card-ink: #000000;             /* type on the here-card */
  --nrb-muted: #655ec4;                /* the product's quiet blue */
  --nrb-clear: #007a33;                /* the three statuses, light theme: clear / on foot only / blocked */
  --nrb-foot: #c96a00;
  --nrb-blocked: #d0231c;
  --nrb-clear-night: #3dc873;          /* dark theme: lifted for the night map */
  --nrb-foot-night: #e89042;
  --nrb-blocked-night: #ff6a61;
  --nrb-night-paper: #131316;          /* the dark theme's paper: the disc ring and glyph on the night map */
  --nrb-scrim-dot: rgba(12, 4, 120, 0.85);
  --nrb-scrim-tint: rgba(12, 4, 120, 0.3);
  --nrb-wash: rgba(247, 246, 242, 0.85);
  --nrb-tap: rgba(0, 0, 0, 0.22);      /* the fingertip */
  --nrb-tap-ring: rgba(0, 0, 0, 0.3);
}

/* ── Cover — the corridor by night, the trail drawing itself ─────────────
 * The product's own map (its dark screenprint theme, rendered clean from
 * the site's vector tiles at zoom 15, no markers) fills the plane. Over
 * it the page draws what the product draws live: the trail line in the
 * status ink, and the five access-point discs dealing in as the line
 * reaches each one — the product's own disc-in spring. The scroll pushes
 * in toward Pottery Road, where the pitch performance picks up.
 *
 * Image and SVG share one box at the map's exact ratio, so the projected
 * coordinates (the site's latLngToContainerPoint, dumped at render time)
 * stay true at any crop; the box covers the plane the way object-fit
 * would, and the push-in scales the box, not the image alone. */
.nrb-cover-map {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  /* Cover: whichever of the plane's width or its height-derived width is
   * larger. 2400 / 1500 is the render's own ratio (media-locked). */
  width: max(100%, calc(100dvh * 2400 / 1500));
  aspect-ratio: 2400 / 1500;
  /* The push-in aims at Pottery Road: (1067, 120) of the 2400 × 1500
   * render — the gate the next plane opens on. */
  transform-origin: 44.5% 8%;
  /* Scroll-scrubbed descent across the first viewport, the cue that the
   * page scrolls (the shared cover zoom, aimed and deeper). Off the
   * duration scale: a scroll timeline. */
  animation: nrb-descend linear both;
  animation-timeline: scroll(root);
  animation-range: 0 100dvh;
}

@keyframes nrb-descend {
  to { scale: 1.1; }
}

/* The shared cover push-in rides the box above, not the image. */
.nrb-cover .st-cover-media img {
  animation: none;
  object-fit: fill;
}

.nrb-cover-trail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* The trail: the product's 12px status line at zoom 15, in the render's
 * units (18 of 2400 across the plane). It draws north to south — a
 * dash the length of the path, offset away and pulled back over the
 * draw (pathLength="1" on the path). Choreography, off the duration
 * scale, with a lead-in so the map has painted first. */
.nrb-cover {
  --nrb-trail-lead: 500ms;
  --nrb-trail-draw: 1800ms;
}

.nrb-trail {
  fill: none;
  stroke: var(--nrb-clear-night);
  stroke-width: 18;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: nrb-trail-draw var(--nrb-trail-draw) linear var(--nrb-trail-lead) both;
}

@keyframes nrb-trail-draw {
  from { stroke-dashoffset: 1; }
}

/* The gates: the product's status disc — colour-filled, ringed in the
 * night paper, the glyph knocked out — 52 units across (the 36px disc at
 * the render's scale). Each deals in with the product's spring the
 * moment the line reaches it: --at is its fraction along the trail. */
.nrb-gate {
  transform-box: fill-box;
  transform-origin: center;
  animation: nrb-gate-in var(--duration-slow) var(--ease-stamp)
             calc(var(--nrb-trail-lead) + var(--at) * var(--nrb-trail-draw)) both;
}

@keyframes nrb-gate-in {
  from { opacity: 0; scale: 0.4; }
}

.nrb-gate circle {
  stroke: var(--nrb-night-paper);
  stroke-width: 3;
}

.nrb-gate--clear circle { fill: var(--nrb-clear-night); }
.nrb-gate--foot circle { fill: var(--nrb-foot-night); }
.nrb-gate--blocked circle { fill: var(--nrb-blocked-night); }

.nrb-gate path {
  fill: none;
  stroke: var(--nrb-night-paper);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* A scrim rises from the bottom edge so the cover's foot reads on the lit
 * city — a gradient over media, the sanctioned kind. Under the type,
 * over the map. */
.nrb-cover::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 40%;
  z-index: 1;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
  pointer-events: none;
}

/* The mark is the h1: the stacked wordmark on phones, the horizontal
 * lockup from 900px — the same swap the product's own site makes. The
 * glyphs print in the one white; the letters cascade (38ms apart after
 * a 400ms lead, the product's own stagger), the two hazard badges stamp
 * in last and their exclamations pop a beat after — shared keyframes
 * (story.css) on the glyphs' inline --i / --bd hooks. */
.nrb-mark {
  display: block;
}

.nrb-mark svg {
  display: block;
  height: auto;
  overflow: visible;
  fill: var(--color-text-on-image);
}

/* (Two classes deep: the shared .st-cover-title svg rule would otherwise
 * out-rank the swap.) */
.nrb-mark .nrb-mark-stack {
  width: min(250px, 70vw);
}

.nrb-mark .nrb-mark-lockup {
  display: none;
}

.nrb-mark .nrb-letter {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: st-letter-enter var(--duration-smooth) var(--ease-smooth)
             calc(400ms + var(--i) * 38ms) forwards;
}

.nrb-mark .nrb-badge {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: st-badge-stamp var(--duration-slow) var(--ease-stamp) var(--bd) forwards;
}

.nrb-mark .nrb-bang {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: nrb-bang-pop var(--duration-medium) var(--ease-stamp)
             calc(var(--bd) + 180ms) forwards; /* delay: a beat after the badge */
}

@keyframes nrb-bang-pop {
  from { opacity: 0; transform: scale(0.3); }
  to { opacity: 1; transform: scale(1); }
}

/* ── The product's paper — the plates' ground ────────────────────────── */
.st-plate--paper {
  --st-plate-ground: var(--nrb-paper);
}

/* The barricade: a photograph, viewport-tall, the signs held in frame. */
.nrb-plate--barricade .st-plate-media img {
  --pos: 50% 58%;
}

/* The prototype's three screens: a composite, small, on a quiet ground
 * (the prototype was its own brand; the paper is the product's). */
.nrb-plate--proto .st-plate-media {
  --st-plate-ground: var(--color-surface-secondary);
}

/* A document on the plate, with room all round: the prototype composite,
 * the home screen, the sticker. */
.nrb-plate--proto .st-plate-media,
.nrb-plate--phone .st-plate-media,
.nrb-plate--sticker .st-plate-media {
  box-sizing: border-box;
  padding: var(--space-12);
}

/* ── The framed clip — the mosaic zoom in the product's own device frame.
 * The overlay PNG is generated from the same geometry recipe as the
 * project's framed screenshots (the NRB generator: 790 × 1686 body,
 * 102px status band, 6px bezel, r85 / r79), so the video sits in the
 * screen hole with insets written as percentages of that geometry —
 * the deck's recipe (showcase.css), on the dark plate. ─────────────── */
.nrb-frame-phone {
  position: relative;
  height: 100%;
  aspect-ratio: 790 / 1686;
  margin-inline: auto;
}

.nrb-frame-phone video {
  position: absolute;
  top: 6.0498%;    /* 102 / 1686 */
  left: 0.7595%;   /*   6 /  790 */
  right: 0.7595%;
  bottom: 0.3559%; /*   6 / 1686 */
  width: 98.481%;
  height: 93.5943%;
  object-fit: cover;
  /* The overlay's screen hole rounds its bottom corners (r79 of the 790
   * geometry); clip the video to the same curve. */
  border-bottom-left-radius: 10.154% 5.006%;
  border-bottom-right-radius: 10.154% 5.006%;
}

.nrb-frame-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
}

/* ── The type specimen — Pilowlava, the face behind the wordmark ───────
 * Velvetyne's Pilowlava (Anton Moglia, Jérémy Landes; Cyrillic by Maksym
 * Kobuzan; 2019, SIL Open Font License), self-hosted for this specimen
 * only — the way case-study.css registers Space Grotesk for the Rafa &
 * Nicky specimens. Two cuts: Atome, whose letters already carry the
 * holes, and the plain Regular. Caps only. Set live, black on the
 * product's paper (the one theme-agnostic black; the paper doesn't
 * theme), the way the logo grid prints monochrome. */
@font-face {
  font-family: "Pilowlava Atome";
  src: url('../fonts/Pilowlava-Atome.otf') format('opentype');
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Pilowlava";
  src: url('../fonts/Pilowlava-Regular.otf') format('opentype');
  font-weight: 400;
  font-display: swap;
}

.nrb-type {
  box-sizing: border-box;
  padding: var(--space-12);
  border-radius: var(--radius-sharp);
  background: var(--nrb-paper);
  color: var(--color-plane-dark);
  /* Size container: the character set sizes itself to the plate's width. */
  container-type: inline-size;
}

.nrb-type p {
  margin: 0;
  word-spacing: normal;
}

.nrb-type > p + p {
  margin-top: var(--space-8);
}

/* The name, set in Atome at display-art scale — the line the drawn
 * wordmark started from. Specimen size: the deck's solo figure, stepped
 * to the column. */
.nrb-type-line {
  font-family: "Pilowlava Atome", sans-serif; /* specimen: the wordmark's face */
  font-size: clamp(40px, 5.5vw, 80px);
  line-height: 1.05;
  letter-spacing: 0;
  font-weight: 400;
  text-wrap: balance;
}

.nrb-type-line--regular {
  font-family: "Pilowlava", sans-serif; /* specimen: the plain cut */
}

/* The full character set in the plain cut — every encoded glyph but
 * the accents (222 of them: Latin, extended Latin, Cyrillic, digits,
 * punctuation and symbols), set in rows by letter family — the accented
 * forms grouped under their base letter, the Cyrillic in four even
 * runs, the marks by kind, a space between families — each row at most
 * 16.2 em and broken in the markup, so at 6.1 cqw of the content box
 * (the plate's padding is outside the box) the alphabet runs edge to
 * edge and nothing wraps by accident. It sits a line further off the
 * two names. */
.nrb-type p.nrb-type-set {
  margin-top: var(--space-16);
  font-family: "Pilowlava", sans-serif; /* specimen: the plain cut */
  font-size: 6.1cqw;
  line-height: 1.2;
  letter-spacing: 0;
  font-weight: 400;
  white-space: nowrap;
}

/* The cut's name under each line: the product's own mono, Caption trio. */
.nrb-type-label {
  margin-top: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--font-size-caption);
  line-height: var(--line-height-caption);
  letter-spacing: var(--letter-spacing-caption);
  font-weight: var(--font-weight-caption);
  color: color-mix(in srgb, var(--color-plane-dark) 60%, transparent);
}

.nrb-type > p.nrb-type-label {
  margin-top: var(--space-2);
}

/* ── Borrowed components, placed ────────────────────────────────────── */
.st-chapter > .cs-logo-grid {
  margin: var(--space-16) 0 0;
}

.st-chapter > .cs-flow-strip {
  margin: var(--space-8) 0 0;
}

.st-chapter > .cs-compare {
  border-radius: var(--radius-sharp);
}

/* ── The pitch — the sticker at the gate, the status page rising ───────
 * The trailhead board fills the plane; the scroll leans in on the
 * sticker (the cover's own push-in, scrubbed on the dwell), then the
 * phone rises over it with that spot's live page — the disc deals in,
 * the card arrives — and the statement lands. Base: leaned in, shaded,
 * the phone up. */
.nrb-pitch-photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.nrb-pitch-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  display: block;
  /* The sticker sits at 54% / 56% of the frame — the push-in's anchor. */
  transform-origin: 54% 56%;
  scale: 1.08;
  animation: st-cover-zoom linear both;
  animation-timeline: --st-perf;
  animation-range: contain 0% contain 45%;
}

/* The photograph shades as the phone rises — a scrim over media. */
.nrb-pitch-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  animation: nrb-shade linear both;
  animation-timeline: --st-perf;
  animation-range: contain 38% contain 50%;
}

@keyframes nrb-shade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.nrb-pitch .st-phone[data-beat] {
  animation-name: st-rise;
  animation-timing-function: var(--ease-smooth);
}

/* ── The report's plane — the corridor, faint, behind the phone ────────
 * The cover's night map at a whisper, so the walkthrough sits on the
 * product's own ground rather than a void. Media over the dark plane,
 * knocked down by opacity. */
.nrb-report::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url('../../media/case-studies/no-road-block/cover-map-dark.png') center / cover no-repeat;
  opacity: 0.08;
  pointer-events: none;
}

/* ── The specimen — the live site, rebuilt on the page's face ──────────
 * The product itself: its paper, its blue ink, its single mono face at
 * the site's own pixel sizes (every size a multiple of --u, the shared
 * specimen unit — one point of the 390 × 844 screen), so the phone fits
 * any plane. It does not theme: the product's paper stays paper in dark
 * mode. The map beneath is the product's own light theme, rendered clean
 * from its vector tiles at Pottery Road; everything on it — the rondel,
 * the disc, the here-card, the tools, the nav pill, the report sheet —
 * is the site's markup and CSS re-set here. */
.nrb-phone {
  background: var(--nrb-paper);
  color: var(--nrb-blue);
  font-family: var(--font-mono); /* the product's one face: Suisse Int'l Mono */
  font-size: calc(12 * var(--u));
}

/* The status band — the device frame's, above the product. */
.nrb-status {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: calc(51 * var(--u));
  padding: 0 calc(24 * var(--u)) 0 calc(28 * var(--u));
  background: var(--nrb-paper);
  color: var(--nrb-card-ink);
  font-family: var(--font-sans);
  font-size: calc(15 * var(--u));
  font-weight: var(--font-semi-bold);
}

.nrb-status-icons {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
}

.nrb-status-icons svg {
  height: calc(12 * var(--u));
  width: auto;
  fill: currentColor;
}

/* The map layer: the render, the rondel, the disc and its card. It
 * glides up while the sheet is open — the product centres the spot in
 * the strip of map left showing — and back when it closes. */
.nrb-map {
  position: absolute;
  top: calc(51 * var(--u));
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
}

.nrb-map-layer {
  position: absolute;
  inset: 0;
  translate: 0 0;
}

.nrb-map-layer > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0; /* the render is the full 844 screen; the band crops it from the bottom, under the nav */
  display: block;
}

/* The rondel — the product's mark, top-left; the only branding on the
 * map view. */
.nrb-rondel {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(20 * var(--u));
  width: calc(40 * var(--u));
  color: var(--nrb-blue);
}

.nrb-rondel svg {
  display: block;
  width: 100%;
  height: auto;
  fill: currentColor;
}

/* The status disc at the spot (the render's Pottery Road point: 195 /
 * 332 of the 390 × 844 screen): 48u, ringed in the card white, the
 * glyph knocked out. Base: blocked — the report made. */
.nrb-here {
  position: absolute;
  left: calc(195 * var(--u));
  top: calc(332 * var(--u));
  width: 0;
  height: 0;
}

.nrb-disc {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(48 * var(--u));
  height: calc(48 * var(--u));
  margin: calc(-24 * var(--u)) 0 0 calc(-24 * var(--u));
  box-sizing: border-box;
  border: calc(2 * var(--u)) solid var(--nrb-card);
  border-radius: var(--radius-circle);
  background: var(--nrb-blocked);
  display: grid;
  place-items: center;
}

.nrb-disc svg {
  grid-area: 1 / 1;
  width: 80%;
  height: 80%;
  fill: none;
  stroke: var(--nrb-card);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The here-card hangs under the disc: name, tallies, the report CTA. */
.nrb-card {
  position: absolute;
  left: 50%;
  top: calc(32 * var(--u));
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: calc(20 * var(--u));
  width: calc(200 * var(--u));
  padding: calc(18 * var(--u)) 0 calc(8 * var(--u)); /* 18 top per Figma — the name hangs off the disc */
  background: var(--nrb-card);
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  color: var(--nrb-card-ink);
  text-align: center;
}

.nrb-card-name {
  display: block;
  font-size: calc(12 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

/* The tallies swap when the report lands: two stacks in one cell. */
.nrb-card-meta {
  display: grid;
}

.nrb-card-meta span {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--u));
  font-size: calc(10 * var(--u));
  line-height: calc(10 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

.nrb-card-actions {
  display: flex;
  flex-direction: column;
  padding-inline: calc(8 * var(--u));
}

/* One button voice across card and sheet: solid = act, outline = choose. */
.nrb-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(40 * var(--u));
  border: 0;
  background: var(--nrb-blue);
  color: var(--nrb-card);
  font-size: calc(12 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

.nrb-btn--ghost {
  box-sizing: border-box;
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  background: var(--nrb-card);
  color: var(--nrb-blue);
}

/* The map tools: the full-trail and locate circles over the zoom pill on
 * the right; the tour and theme circles on the left. */
.nrb-rail {
  position: absolute;
  bottom: calc(124 * var(--u)); /* 20 + the 64 nav + 40, the product's clearance */
  width: calc(40 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
}

.nrb-rail--right { right: calc(20 * var(--u)); }
.nrb-rail--left { left: calc(20 * var(--u)); }

.nrb-rail-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: calc(40 * var(--u));
  box-sizing: border-box;
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  border-radius: var(--radius-circle);
  background: var(--nrb-card);
  color: var(--nrb-blue);
}

.nrb-rail-btn svg {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  fill: currentColor;
}

/* The zoom pair share one pill. */
.nrb-rail-zoom {
  display: flex;
  flex-direction: column;
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  border-radius: calc(20 * var(--u));
  overflow: hidden;
  background: var(--nrb-card);
}

.nrb-rail-zoom .nrb-rail-btn {
  height: calc(44 * var(--u));
  border: 0;
  border-radius: 0;
}

.nrb-rail-zoom .nrb-rail-btn + .nrb-rail-btn {
  border-top: calc(1 * var(--u)) solid var(--nrb-blue);
}

/* The attribution, bottom-right on the map's wash. */
.nrb-attr {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: calc(2 * var(--u)) calc(6 * var(--u));
  font-size: calc(10 * var(--u));
  line-height: 1.4;
  color: var(--nrb-muted);
  background: var(--nrb-wash);
}

/* The nav pill: two tabs, the current one filled. It bows out while the
 * report owns the screen. */
.nrb-nav {
  position: absolute;
  left: calc(20 * var(--u));
  right: calc(20 * var(--u));
  bottom: calc(20 * var(--u));
  z-index: 2;
  display: flex;
  height: calc(64 * var(--u));
  box-sizing: border-box;
  background: var(--nrb-card);
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  border-radius: calc(32 * var(--u));
  overflow: hidden;
}

.nrb-nav-item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(2 * var(--u));
  color: var(--nrb-blue);
  font-size: calc(12 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

.nrb-nav-item svg {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  fill: currentColor;
}

.nrb-nav-item.is-current {
  background: var(--nrb-blue);
  color: var(--nrb-card);
}

/* ── The report — the scrim and the sheet ─────────────────────────────
 * The product's halftone wash screens the map back (two offset dot
 * grids over a tint); the sheet rises from the bottom edge with the
 * pill's radius on its top corners. Base: closed — the report made. */
.nrb-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background:
    radial-gradient(circle, var(--nrb-scrim-dot) calc(1.1 * var(--u)), transparent calc(1.3 * var(--u))) 0 0 / calc(4 * var(--u)) calc(4 * var(--u)),
    radial-gradient(circle, var(--nrb-scrim-dot) calc(1.1 * var(--u)), transparent calc(1.3 * var(--u))) calc(2 * var(--u)) calc(2 * var(--u)) / calc(4 * var(--u)) calc(4 * var(--u)),
    var(--nrb-scrim-tint);
  opacity: 0;
  pointer-events: none;
}

.nrb-sheet {
  position: relative;
  display: grid;
  min-height: calc(312 * var(--u));
  padding: calc(24 * var(--u)) calc(20 * var(--u)) calc(24 * var(--u));
  box-sizing: border-box;
  background: var(--nrb-card);
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  border-bottom: 0;
  border-radius: calc(20 * var(--u)) calc(20 * var(--u)) 0 0; /* the pill's radius, turned into a sheet */
  color: var(--nrb-blue);
  text-align: center;
  translate: 0 100%;
}

.nrb-sheet-x {
  position: absolute;
  top: 0;
  right: 0;
  width: calc(44 * var(--u)); /* thumb-sized */
  height: calc(44 * var(--u));
  display: grid;
  place-items: center;
  font-size: calc(20 * var(--u));
  line-height: 1;
}

/* The sheet's faces share one cell: the question, the picker, the done. */
.nrb-face {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(20 * var(--u));
  opacity: 0;
}

.nrb-face--done {
  opacity: 1;
}

.nrb-sheet-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8 * var(--u));
}

.nrb-sheet-name {
  font-size: calc(15 * var(--u));
  line-height: calc(20 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

.nrb-sheet-q {
  font-size: calc(12 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

/* The question wears its status's disc — the legend's drawing, sized up. */
.nrb-sheet-ic {
  width: calc(64 * var(--u));
  height: calc(64 * var(--u));
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nrb-sheet-ic circle { fill: var(--nrb-clear); stroke: none; }
.nrb-sheet-ic path { stroke: var(--nrb-card); }

.nrb-yn {
  display: flex;
  gap: calc(8 * var(--u));
}

.nrb-yn .nrb-btn {
  flex: 1 1 0;
}

/* The picker: three tiles, the legend's disc over its label. The pick
 * floods the tile with its status colour and the disc inverts so the
 * glyph keeps reading. Base: Blocked picked. */
.nrb-tiles {
  display: flex;
  gap: calc(8 * var(--u));
}

.nrb-tile {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(8 * var(--u));
  min-height: calc(104 * var(--u));
  padding: calc(12 * var(--u)) calc(4 * var(--u));
  box-sizing: border-box;
  border: calc(1 * var(--u)) solid var(--nrb-blue);
  background: var(--nrb-card);
  color: var(--nrb-blue);
  font-size: calc(11 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

.nrb-tile svg {
  width: calc(32 * var(--u));
  height: calc(32 * var(--u));
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nrb-tile svg circle { stroke: none; }
.nrb-tile svg path { stroke: var(--nrb-card); }
.nrb-tile--clear svg circle { fill: var(--nrb-clear); }
.nrb-tile--foot svg circle { fill: var(--nrb-foot); }
.nrb-tile--blocked svg circle { fill: var(--nrb-blocked); }

/* The pick, flooded: base for the Blocked tile. */
.nrb-tile--blocked {
  background: var(--nrb-blocked);
  border-color: var(--nrb-blocked);
  color: var(--nrb-card);
}

.nrb-tile--blocked svg circle { fill: var(--nrb-card); }
.nrb-tile--blocked svg path { stroke: var(--nrb-blocked); }

/* Confirm wakes once a status is picked. Base: awake. */
.nrb-confirm {
  background: var(--nrb-blue);
  color: var(--nrb-card);
  border: calc(1 * var(--u)) solid var(--nrb-blue);
}

/* The success moment: the check stamps in, then the thanks. */
.nrb-done {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(16 * var(--u));
}

.nrb-done svg {
  width: calc(64 * var(--u));
  height: calc(64 * var(--u));
  fill: none;
  stroke: var(--nrb-blue);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nrb-done-msg {
  font-size: calc(12 * var(--u));
  line-height: calc(16 * var(--u));
  letter-spacing: calc(0.5 * var(--u));
}

/* The tap: a fingertip's worth of shade on the thing pressed, pulsing
 * once in its window (st-tap, shared). Base: gone. */
.nrb-tap {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(36 * var(--u));
  height: calc(36 * var(--u));
  margin: calc(-18 * var(--u)) 0 0 calc(-18 * var(--u));
  border-radius: var(--radius-circle);
  background: var(--nrb-tap);
  border: calc(1 * var(--u)) solid var(--nrb-tap-ring);
  opacity: 0;
  pointer-events: none;
}

.nrb-tap[data-beat] {
  animation-name: st-tap;
}

.nrb-btn[data-beat],
.nrb-tile[data-beat] {
  animation-name: st-press;
}

/* ── The report, performed ─────────────────────────────────────────────
 * Every beat rides the shared [data-beat] recipe (story.css) with its
 * window; the ones that do more than arrive take their own keyframes,
 * and the ones that also leave carry a second window (--c/--d). */

/* Two-window beats: in on --a/--b, out on --c/--d. */
.nrb-in-out[data-beat] {
  animation-name: st-arrive, st-leave;
  animation-timing-function: linear, linear;
  animation-fill-mode: both, forwards;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

/* Leave-only beats (the question face is there when the sheet rises). */
.nrb-out[data-beat] {
  animation-name: st-leave;
  animation-range: contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

/* The nav pill bows out and returns. */
.nrb-nav[data-beat] {
  animation-name: nrb-fade-out, nrb-fade-in;
  animation-timing-function: linear, linear;
  animation-fill-mode: both, forwards;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

@keyframes nrb-fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes nrb-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The scrim washes in and out. */
.nrb-scrim[data-beat] {
  animation-name: nrb-fade-in, nrb-fade-out;
  animation-timing-function: linear, linear;
  animation-fill-mode: both, forwards;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

/* The sheet rises and drops (the product's sheet-up). */
.nrb-sheet[data-beat] {
  animation-name: nrb-sheet-up, nrb-sheet-down;
  animation-timing-function: var(--ease-smooth), var(--ease-smooth);
  animation-fill-mode: both, forwards;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

@keyframes nrb-sheet-up {
  from { translate: 0 100%; }
  to { translate: 0 0; }
}

@keyframes nrb-sheet-down {
  from { translate: 0 0; }
  to { translate: 0 100%; }
}

/* The map glides up behind the sheet and back. */
.nrb-map-layer[data-beat] {
  animation-name: nrb-glide-up, nrb-glide-down;
  animation-timing-function: var(--ease-smooth), var(--ease-smooth);
  animation-fill-mode: both, forwards;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

@keyframes nrb-glide-up {
  from { translate: 0 0; }
  to { translate: 0 calc(-120 * var(--u)); }
}

@keyframes nrb-glide-down {
  from { translate: 0 calc(-120 * var(--u)); }
  to { translate: 0 0; }
}

/* The Blocked tile floods on the pick. */
.nrb-tile--blocked[data-beat] {
  animation-name: nrb-flood;
  animation-timing-function: var(--ease-smooth);
}

@keyframes nrb-flood {
  from { background: var(--nrb-card); border-color: var(--nrb-blue); color: var(--nrb-blue); }
  to { background: var(--nrb-blocked); border-color: var(--nrb-blocked); color: var(--nrb-card); }
}

.nrb-tile--blocked[data-beat] svg circle {
  animation: nrb-flood-disc linear both;
  animation-timeline: --st-perf;
  animation-range: contain calc(var(--a) * 1%) contain calc(var(--b) * 1%);
}

.nrb-tile--blocked[data-beat] svg path {
  animation: nrb-flood-glyph linear both;
  animation-timeline: --st-perf;
  animation-range: contain calc(var(--a) * 1%) contain calc(var(--b) * 1%);
}

@keyframes nrb-flood-disc {
  from { fill: var(--nrb-blocked); }
  to { fill: var(--nrb-card); }
}

@keyframes nrb-flood-glyph {
  from { stroke: var(--nrb-card); }
  to { stroke: var(--nrb-blocked); }
}

/* Confirm wakes (from the muted outline to solid) on --a/--b, and is
 * pressed on --c/--d. */
.nrb-confirm[data-beat] {
  animation-name: nrb-wake, st-press;
  animation-timing-function: var(--ease-smooth), linear;
  animation-fill-mode: both, both;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain calc(var(--a) * 1%) contain calc(var(--b) * 1%),
    contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

@keyframes nrb-wake {
  from { background: var(--nrb-card); color: var(--nrb-muted); border-color: var(--nrb-muted); }
  to { background: var(--nrb-blue); color: var(--nrb-card); border-color: var(--nrb-blue); }
}

/* The check stamps in (st-badge-stamp, shared). */
.nrb-done svg[data-beat] {
  animation-name: st-badge-stamp;
  animation-timing-function: var(--ease-stamp);
}

/* The disc turns: green to red, the check out, the cross in. */
.nrb-disc[data-beat] {
  animation-name: nrb-turn;
}

@keyframes nrb-turn {
  from { background: var(--nrb-clear); }
  to { background: var(--nrb-blocked); }
}

.nrb-disc .nrb-glyph--check {
  opacity: 0;
}

.nrb-disc .nrb-glyph--check[data-beat] {
  animation-name: nrb-fade-out;
}

.nrb-disc .nrb-glyph--cross[data-beat] {
  animation-name: nrb-gate-in;
}

/* The tallies: the old count leaves, the new one lands. */
.nrb-card-meta .nrb-meta--before {
  opacity: 0;
}

/* The pitch's phone carries the clear disc and the old tally, unreported. */
.nrb-pitch .nrb-disc {
  background: var(--nrb-clear);
}

.nrb-pitch .nrb-disc .nrb-glyph--check {
  opacity: 1;
}

.nrb-pitch .nrb-disc .nrb-glyph--cross {
  opacity: 0;
}

.nrb-pitch .nrb-card-meta .nrb-meta--before {
  opacity: 1;
}

/* The disc deals in on the pitch — the product's own spring. */
.nrb-pitch .nrb-disc[data-beat] {
  animation-name: nrb-gate-in;
  animation-timing-function: var(--ease-stamp);
}

/* ── The results — on brand blue ──────────────────────────────────────── */
.st-nums {
  --st-nums-ground: var(--nrb-blue);
}

/* ── Close — the road ahead ───────────────────────────────────────────── */
.st-close {
  --pos: 50% 45%;
}

/* ── Widths ─────────────────────────────────────────────────────────── */
@media (min-width: 900px) {
  .nrb-mark .nrb-mark-stack { display: none; }
  .nrb-mark .nrb-mark-lockup {
    display: block;
    /* A touch under the case-study hero's, so the corridor shows around it. */
    width: min(600px, 50vw);
  }
}

@media (max-width: 768px) {
  /* The framed clip fills the dark plate's height on a phone. */
  .st-plate--dark .nrb-frame-phone {
    height: auto;
    width: 60%;
  }

  .nrb-plate--proto .st-plate-media,
  .nrb-plate--phone .st-plate-media,
  .nrb-plate--sticker .st-plate-media,
  .nrb-type {
    padding: var(--space-5);
  }
}

/* ── Reduced motion — keyed off data-motion="reduce" on the root, which
 * the head script stamps from the OS preference or the visitor's switch.
 * The performances unpin (story.css) and, stripped of their animations,
 * stand on their base styles: the finished frames. The cover holds the
 * trail drawn, the gates in place, the mark printed. ──────────────── */
:root[data-motion="reduce"] .nrb-cover-map,
:root[data-motion="reduce"] .nrb-trail,
:root[data-motion="reduce"] .nrb-gate,
:root[data-motion="reduce"] .nrb-mark .nrb-letter,
:root[data-motion="reduce"] .nrb-mark .nrb-badge,
:root[data-motion="reduce"] .nrb-mark .nrb-bang,
:root[data-motion="reduce"] .nrb-pitch-photo img,
:root[data-motion="reduce"] .nrb-pitch-photo::after,
:root[data-motion="reduce"] .nrb-tile--blocked svg circle,
:root[data-motion="reduce"] .nrb-tile--blocked svg path {
  animation: none;
}

:root[data-motion="reduce"] .nrb-mark .nrb-letter,
:root[data-motion="reduce"] .nrb-mark .nrb-badge,
:root[data-motion="reduce"] .nrb-mark .nrb-bang {
  opacity: 1;
}
