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

/* ── Artpilot — the story ───────────────────────────────────────────────
 * The Artpilot EXTENSION of the shared story structure (css/page/story.css:
 * cover, spine, spreads, plates, statements, spec, numbers, list,
 * performances, close). This file carries only what is Artpilot's: the
 * graded film and the lockup's entrance on the cover, the three
 * performances — the inbox ported from the deck (artpilot-showcase.css)
 * onto the page's own view timeline, the walkthrough of the order flow
 * on the shared specimen phone, and the shared results plane on Sticker
 * Red — and the screen plates.
 * Page: ux-case-studies/artpilot.html.
 * Driver: js/page/story.js (shared). No page JS of its own: every
 * performance is CSS on the shared --st-perf timeline.
 *
 * The Artpilot colours (Sticker Red, the app icon's orange, the ambient
 * glow, the film grade) are brand constants from project-colours.css —
 * not site tokens, and they don't theme. Everything else sits on the
 * tokens and the ten type roles; the only literals are the media-locked
 * constants and the optical pixels ported from the deck, each commented.
 *
 * Every performance follows the shared recipe: base styles are the END
 * state and keyframes start from the beginning (a from-keyframe for
 * every property the base sets), so an engine without scroll timelines —
 * and reduced motion, which strips the animations — shows the finished
 * composition. */

/* ── Cover — the film, graded; the lockup, stamped ──────────────────── */
/* The footage carries its own treatment: knocked down and slightly
 * desaturated in the grade so the white mark prints on real frames — no
 * wash sheet on top (the deck's rule). */
.st-cover-media video {
  filter: var(--ap-grade);
  --pos: 50% 50%;
}

/* The lockup — badge and wordmark — is the h1. A touch narrower than the
 * deck's hero, so the pitch line beneath keeps its room. */
.st-cover-title svg {
  width: min(560px, 76vw, 80dvh);
}

/* Entrance choreography, from the deck (the shared st-letter-enter and
 * st-badge-stamp in story.css): letters cascade in reading order (--i
 * orders the wave, 45ms apart after a 400ms lead), then the badge
 * rubber-stamps in on its --bd delay. Both inline custom-property hooks. */
.st-cover-title .ap-letter {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  animation: st-letter-enter var(--duration-smooth) var(--ease-smooth)
             calc(400ms + var(--i) * 45ms) forwards;
}

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

/* ── The screens — plates that hold the product ──────────────────────── */
/* The persona sheet is 16:9 on white: its own ratio, so no bands. */
.st-plate--sheet .st-plate-media {
  aspect-ratio: 16 / 9;
}

/* Flat screens on a quiet ground: the home screen's three rounds, the
 * web dashboard beside the app. Each
 * screen keeps its own height (the shared plate rule crops to fill;
 * these are documents, not photographs). */
.st-plate--screens {
  height: auto;
  padding-block: 0;
}

.st-plate--screens .st-plate-media {
  height: auto;
  box-sizing: border-box;
  padding: var(--space-8);
  display: grid;
  gap: var(--space-4);
  align-items: start;
  background: var(--color-surface-secondary);
}

.st-plate--screens .st-plate-media img {
  height: auto;
  object-fit: contain;
  border-radius: var(--radius-sharp);
}

.st-plate--rounds .st-plate-media {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
}

/* The web dashboard, above the fold, with the same screen on the phone. */
.st-plate--two .st-plate-media {
  grid-template-columns: minmax(0, 3fr) minmax(0, 1fr);
  gap: var(--space-6);
}

/* A render at its own ratio, filling the plate exactly — the trailer.
 * The ratio is the file's own (media-locked). */
.st-plate--render {
  height: auto;
  padding-block: 0;
}

.st-plate--render .st-plate-media {
  height: auto;
}

.st-plate--trailer .st-plate-media {
  aspect-ratio: 2400 / 1118;
}

/* The card states are a transparent PNG: no plate, just the image on the
 * page, contained, at its natural width at most. */
.st-plate--states {
  height: auto;
  padding-block: 0;
}

.st-plate--states .st-plate-media {
  height: auto;
  background: none;
  border-radius: 0;
}

.st-plate--states .st-plate-media img {
  height: auto;
  max-width: 930px; /* the render's own width — never upscaled */
  object-fit: contain;
}

/* ── 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;
}

/* ── The inbox — the problem, told with a mail-app icon ────────────────
 * The deck's problem slide, on the shared --st-perf timeline: a mail-app
 * icon floats alone on the shadow ground and its unread badge climbs as
 * the reader scrolls — the reader pumps the inbox — until the Artpilot
 * icon stamps in beside it, pushes the mail icon off the plane and takes
 * its place, slightly grown. Replacement, not coexistence. Tile inks are
 * media-locked constants, per the deck rule; the squircle and the pill
 * badge are specimen artwork (an app icon depicted), not site chrome. */

/* A gentle ambient behind the icons — media-locked radial wash (the
 * allowed class), lifting the void so the plane reads lit. Edges fall
 * back to the shadow ground: the vignette is the absence of glow. */
.st-inbox::before,
.st-walk::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(100vw at 50% 42%, var(--ap-glow), transparent 52%);
}

.st-inbox {
  /* App-icon tile size — the install, the takeover and the open all
   * agree what "the icon" measures. */
  --st-tile: clamp(140px, 18vw, 240px);
  --st-slot-gap: var(--space-12);
}

.st-inbox-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  /* No gap — the Artpilot tile opens its own room (margin) as it
   * installs, so the mail icon sits dead centre until then. */
  gap: 0;
}

.st-icon {
  position: relative;
  flex: none;
  width: var(--st-tile);
  aspect-ratio: 1;
  /* Size container: the badge sizes in cqw, so when the eject collapses
   * the tile, the badge shrinks in lockstep. */
  container-type: inline-size;
}

/* The art layer clips to the squircle so the Artpilot mark can bleed
 * off its tile the way the real icon does; the badge lives outside. */
.st-icon-art {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 22.5%;
  overflow: hidden;
}

.st-icon-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The tile's white is a media-locked light GROUND (an app icon
 * depicted), not ink — the mirror of --color-plane-dark, for which no
 * light-plane token exists — so it stays literal. */
.st-icon--mail .st-icon-art {
  background: #ffffff;
  color: var(--color-plane-dark);
}

.st-icon--mail .st-icon-glyph {
  width: 54%;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The badge — the beat's actual subject, at display scale, in the app
 * icon's own orange: the chaos counts in the exact colour that answers
 * it. The number renders from the scrubbed counter; base is the count at
 * its worst. */
@property --st-count {
  syntax: '<integer>';
  initial-value: 212;
  inherits: false;
}

.st-icon-badge {
  position: absolute;
  top: 0;
  right: 0;
  transform: translate(30%, -30%);
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.7em;
  min-width: 1.7em;
  padding-inline: 0.5em;
  border-radius: 0.85em;
  background: var(--ap-orange);
  color: var(--color-text-on-image);
  /* cqw of the tile — the badge scales with its icon, including all the
   * way down through the eject. */
  font-size: 17.5cqw;
  letter-spacing: -0.01em;
  font-weight: var(--font-semi-bold);
  font-variant-numeric: tabular-nums;
  counter-reset: st-inbox var(--st-count);
  animation: st-climb linear both;
  animation-timeline: --st-perf;
  /* The climb ends where the install begins — the moment the
   * alternative exists, the counting stops. */
  animation-range: contain 0% contain 50%;
}

.st-icon-badge::after {
  content: counter(st-inbox);
}

@keyframes st-climb {
  from { --st-count: 3; }
  to { --st-count: 212; }
}

/* The mail icon is ejected in the takeover window: its slot collapses
 * while it flies off the plane, so the flex row recentres Artpilot into
 * the vacated spot — pushed out, not faded out. Ease-in: it accelerates
 * away. The blur is a depth cue (further back, more blurred), the
 * deck's deliberate exception to the no-blur guardrail. Base: gone. */
.st-icon--mail {
  width: 0;
  opacity: 0;
  transform: translateX(-38vw) rotate(-6deg);
  filter: blur(9px);
  animation: st-eject var(--ease-eject) both;
  animation-timeline: --st-perf;
  animation-range: contain 64% contain 74%;
}

@keyframes st-eject {
  from {
    width: var(--st-tile);
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
  40% {
    filter: blur(1px);
  }
  to {
    width: 0;
    opacity: 0;
    transform: translateX(-38vw) rotate(-6deg);
    filter: blur(9px);
  }
}

/* The Artpilot icon: zero-width until it installs (the hero's
 * rubber-stamp, scrubbed; the row makes room the way a home screen
 * does), then glides into the centre the mail icon vacates and grows a
 * touch — the replacement landed. Base: installed, centred. The
 * takeover's missing from-values pick up the install beneath it. */
.st-icon--artpilot {
  width: var(--st-tile);
  margin-left: 0;
  opacity: 1;
  scale: 1.12;
  animation:
    st-install var(--ease-stamp) both,
    st-takeover var(--ease-smooth) both;
  animation-timeline: --st-perf, --st-perf;
  animation-range:
    contain 54% contain 62%,
    contain 64% contain 74%;
}

@keyframes st-install {
  from {
    width: 0;
    margin-left: 0;
    opacity: 0;
    transform: scale(1.45) rotate(-8deg);
  }
  to {
    width: var(--st-tile);
    margin-left: var(--st-slot-gap);
    opacity: 1;
    transform: none;
  }
}

@keyframes st-takeover {
  from {
    scale: 1;
  }
  to {
    margin-left: 0;
    scale: 1.12;
  }
}

/* ── The walkthrough — the order, placed ──────────────────────────────
 * The product itself, used while the plane is pinned. The app is a
 * SPECIMEN — its own inks and its own sizes, rebuilt on the page's face
 * the way the Rafa & Nicky session rebuilds the terminal and the site
 * window — and it does not theme: a white screen stays white in dark
 * mode. The frame and its unit (--u, one point of the 390 × 844 screen)
 * are the shared specimen phone in story.css; this file is the app.
 *
 * The use is choreographed on the shared --st-perf timeline: a service
 * is ticked, the note types itself, the button presses, the screen
 * pushes left as the next slides in (the iOS push); a time is chosen;
 * the cost breaks down line by line; the order is paid for; the
 * confirmation stamps in. Every beat is a [data-beat] with its window;
 * the screens carry a second window (--c/--d) for their exit. Base
 * styles are the end state — the order placed — so an engine without
 * scroll timelines, and reduced motion, show the confirmation. */
.st-walk-slot {
  height: 400dvh;
}

.ap-phone {
  /* The app's own inks (specimen constants, one-off here). The screen's
   * white is a light GROUND, the mirror of --color-plane-dark. */
  --ap-screen: #ffffff;
  --ap-ink: #000000;
  --ap-ink-2: #4a4a4a;
  --ap-ink-3: #6e6e6e;
  --ap-rule: #e0e0e0;
  --ap-fill: #f3f3f3;
  --ap-tap: rgba(0, 0, 0, 0.22);
  --ap-tap-ring: rgba(0, 0, 0, 0.3);
  --ap-on-dark-dim: rgba(255, 255, 255, 0.6);
  background: var(--ap-screen);
  color: var(--ap-ink);
  font-family: var(--font-sans); /* the app's face is the site's face */
  font-size: calc(14 * var(--u));
}

/* ── The chrome — status bar and nav, fixed; the title swaps on the
 * last screen. ─────────────────────────────────────────────────── */
.ap-chrome {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  height: calc(96 * var(--u));
  background: var(--ap-ink);
  color: var(--ap-screen);
}

.ap-status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: calc(44 * var(--u));
  padding: 0 calc(24 * var(--u)) 0 calc(28 * var(--u));
  font-size: calc(15 * var(--u));
  font-weight: var(--font-semi-bold);
}

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

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

.ap-nav {
  display: grid;
  grid-template-columns: calc(40 * var(--u)) minmax(0, 1fr) calc(40 * var(--u));
  align-items: center;
  height: calc(52 * var(--u));
  padding: 0 calc(12 * var(--u));
  font-size: calc(17 * var(--u));
  font-weight: var(--font-semi-bold);
  text-align: center;
}

.ap-nav-back svg {
  display: block;
  height: calc(16 * var(--u));
  width: auto;
  margin-left: calc(6 * var(--u));
}

.ap-nav-title {
  display: grid;
}

.ap-nav-t {
  grid-area: 1 / 1;
}

/* The order title leaves on the last push; base: gone. */
.ap-nav-t--order {
  opacity: 0;
}

.ap-nav-t--order[data-beat] {
  animation-name: st-leave;
  animation-range: contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

.ap-nav-more {
  text-align: right;
  font-size: calc(14 * var(--u));
  letter-spacing: calc(1 * var(--u));
}

/* ── The screens — each one pushes left as the next slides in ──────── */
.ap-screen {
  position: absolute;
  top: calc(96 * var(--u));
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  background: var(--ap-screen);
  translate: -100% 0;
}

.ap-screen--last {
  translate: 0 0;
}

.ap-screen[data-beat] {
  animation-name: st-push-in, st-push-out;
  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%);
}

/* The first screen is there from the start and only leaves; the last
 * only arrives. */
.ap-screen--first[data-beat] {
  animation-name: st-push-out;
  animation-timing-function: var(--ease-smooth);
  animation-fill-mode: both;
  animation-timeline: --st-perf;
  animation-range: contain calc(var(--c) * 1%) contain calc(var(--d) * 1%);
}

.ap-screen--last[data-beat] {
  animation-name: st-push-in;
  animation-timing-function: var(--ease-smooth);
  animation-fill-mode: both;
  animation-timeline: --st-perf;
  animation-range: contain calc(var(--a) * 1%) contain calc(var(--b) * 1%);
}

@keyframes st-push-in {
  from { translate: 100% 0; }
  to { translate: 0 0; }
}

@keyframes st-push-out {
  from { translate: 0 0; }
  to { translate: -100% 0; }
}

/* The step bar, black, one dot per step; the current step lit. */
.ap-progress {
  position: relative;
  display: flex;
  justify-content: space-between;
  padding: 0 calc(20 * var(--u)) calc(12 * var(--u));
  background: var(--ap-ink);
  color: var(--ap-on-dark-dim);
}

.ap-progress::before {
  content: "";
  position: absolute;
  left: calc(40 * var(--u));
  right: calc(40 * var(--u));
  top: calc(14 * var(--u));
  height: calc(1 * var(--u));
  background: var(--ap-on-dark-dim);
}

.ap-progress i {
  position: relative;
  padding-top: calc(24 * var(--u));
  font-style: normal;
  font-size: calc(13 * var(--u));
}

.ap-progress i::before {
  content: "";
  position: absolute;
  top: calc(11 * var(--u));
  left: 50%;
  translate: -50% 0;
  width: calc(6 * var(--u));
  height: calc(6 * var(--u));
  border-radius: var(--radius-circle);
  background: var(--ap-screen);
}

.ap-progress i.is-on {
  color: var(--ap-screen);
  font-weight: var(--font-semi-bold);
}

.ap-progress i.is-on::before {
  top: calc(9 * var(--u));
  width: calc(11 * var(--u));
  height: calc(11 * var(--u));
}

/* ── The body ───────────────────────────────────────────────────────── */
.ap-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: calc(16 * var(--u)) calc(20 * var(--u)) 0;
}

.ap-h {
  font-size: calc(18 * var(--u));
  color: var(--ap-ink-2);
  margin-bottom: calc(6 * var(--u));
}

.ap-section {
  margin-top: calc(14 * var(--u));
  padding-bottom: calc(6 * var(--u));
  border-bottom: calc(1 * var(--u)) solid var(--ap-rule);
  font-size: calc(14 * var(--u));
  color: var(--ap-ink-3);
}

.ap-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: calc(12 * var(--u));
  padding: calc(12 * var(--u)) 0;
  border-bottom: calc(1 * var(--u)) solid var(--ap-rule);
}

.ap-row--plain {
  border-bottom: 0;
}

.ap-row-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--u));
}

.ap-row-text b {
  font-size: calc(15 * var(--u));
  font-weight: var(--font-semi-bold);
}

.ap-row-text small {
  font-size: calc(13 * var(--u));
  line-height: 1.3;
  color: var(--ap-ink-3);
}

.ap-row-price {
  flex: none;
  font-size: calc(15 * var(--u));
  font-weight: var(--font-semi-bold);
}

.ap-tag {
  align-self: flex-start;
  margin-top: calc(4 * var(--u));
  padding: calc(2 * var(--u)) calc(6 * var(--u));
  border-radius: calc(3 * var(--u));
  background: var(--ap-fill);
  font-size: calc(11 * var(--u));
  font-style: normal;
  color: var(--ap-ink-2);
}

.ap-link {
  margin-top: calc(10 * var(--u));
  font-size: calc(13 * var(--u));
  color: var(--ap-ink-2);
  text-decoration: underline;
}

.ap-hint {
  margin-top: calc(6 * var(--u));
  font-size: calc(12 * var(--u));
  color: var(--ap-ink-3);
}

/* The checkbox: base ticked, in the app's red. */
.ap-check {
  flex: none;
  display: grid;
  place-items: center;
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  box-sizing: border-box;
  border: calc(1.5 * var(--u)) solid var(--ap-red);
  border-radius: calc(3 * var(--u));
  background: var(--ap-red);
  color: var(--ap-screen);
}

.ap-check svg {
  width: calc(12 * var(--u));
  height: auto;
}

.ap-check--off {
  background: transparent;
  border-color: var(--ap-ink-3);
}

.ap-check[data-beat] {
  animation-name: st-tick;
}

@keyframes st-tick {
  from { background: transparent; border-color: var(--ap-ink-3); color: transparent; }
  to { background: var(--ap-red); border-color: var(--ap-red); color: var(--ap-screen); }
}

/* The radio: base chosen. */
.ap-radio {
  flex: none;
  display: grid;
  place-items: center;
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  box-sizing: border-box;
  border: calc(1.5 * var(--u)) solid var(--ap-red);
  border-radius: var(--radius-circle);
}

.ap-radio-dot {
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  border-radius: var(--radius-circle);
  background: var(--ap-red);
}

.ap-radio--off {
  border-color: var(--ap-ink-3);
}

.ap-radio[data-beat] {
  animation-name: st-ring;
}

.ap-radio-dot[data-beat] {
  animation-name: st-dot;
}

@keyframes st-ring {
  from { border-color: var(--ap-ink-3); }
  to { border-color: var(--ap-red); }
}

@keyframes st-dot {
  from { scale: 0; }
  to { scale: 1; }
}

/* The note field: base focused (the app's red outline), the note typed. */
.ap-field {
  position: relative;
  margin-top: calc(14 * var(--u));
  padding: calc(14 * var(--u)) calc(14 * var(--u)) calc(12 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--ap-red);
  border-radius: calc(4 * var(--u));
  font-size: calc(14 * var(--u));
}

.ap-field[data-beat] {
  animation-name: st-focus;
}

@keyframes st-focus {
  from { border-color: var(--ap-rule); }
  to { border-color: var(--ap-red); }
}

.ap-field-label {
  position: absolute;
  top: calc(-8 * var(--u));
  left: calc(10 * var(--u));
  padding: 0 calc(4 * var(--u));
  background: var(--ap-screen);
  font-size: calc(12 * var(--u));
  font-weight: var(--font-semi-bold);
}

.ap-field-text {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ap-field-text[data-beat] {
  animation-name: st-type;
}

/* The tap: a fingertip's worth of shade on the thing pressed, pulsing
 * once in its window (st-tap, shared). Base: gone. */
.ap-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(--ap-tap);
  border: calc(1 * var(--u)) solid var(--ap-tap-ring);
  opacity: 0;
  pointer-events: none;
}

.ap-row > .ap-tap {
  left: calc(11 * var(--u));
}

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

/* The buttons: base at rest; a press dips once in its window (st-press,
 * shared). */
.ap-foot {
  flex: none;
  padding: calc(12 * var(--u)) calc(20 * var(--u)) calc(20 * var(--u));
  border-top: calc(1 * var(--u)) solid var(--ap-rule);
}

.ap-foot--two {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(10 * var(--u));
}

.ap-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(48 * var(--u));
  border-radius: calc(4 * var(--u));
  background: var(--ap-ink);
  color: var(--ap-screen);
  font-size: calc(15 * var(--u));
  font-weight: var(--font-semi-bold);
  text-align: center;
}

.ap-btn--ghost {
  margin-top: calc(10 * var(--u));
  height: calc(44 * var(--u));
  box-sizing: border-box;
  border: calc(1.5 * var(--u)) solid var(--ap-ink);
  background: transparent;
  color: var(--ap-ink);
}

.ap-foot--two .ap-btn--ghost {
  margin-top: 0;
  height: calc(48 * var(--u));
}

.ap-btn[data-beat] {
  animation-name: st-press;
}

/* Contact, payment, cost. */
.ap-contact {
  display: flex;
  align-items: flex-start;
  gap: calc(12 * var(--u));
  padding: calc(12 * var(--u)) 0;
}

.ap-avatar {
  flex: none;
  width: calc(36 * var(--u));
  height: calc(36 * var(--u));
  border-radius: var(--radius-circle);
  background: var(--ap-fill);
}

.ap-card {
  margin-top: calc(10 * var(--u));
  padding: calc(12 * var(--u)) calc(14 * var(--u));
  border: calc(1 * var(--u)) solid var(--ap-rule);
  border-radius: calc(4 * var(--u));
}

.ap-card--pay {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
}

.ap-visa {
  flex: none;
  padding: calc(3 * var(--u)) calc(6 * var(--u));
  border: calc(1 * var(--u)) solid var(--ap-rule);
  border-radius: calc(3 * var(--u));
  font-size: calc(11 * var(--u));
  font-weight: var(--font-semi-bold);
  letter-spacing: calc(0.5 * var(--u));
}

.ap-cost {
  display: flex;
  justify-content: space-between;
  padding: calc(5 * var(--u)) 0;
  font-size: calc(14 * var(--u));
  color: var(--ap-ink-2);
}

.ap-cost--total {
  margin-top: calc(4 * var(--u));
  padding-top: calc(10 * var(--u));
  border-top: calc(1 * var(--u)) solid var(--ap-rule);
  font-weight: var(--font-semi-bold);
  color: var(--ap-ink);
}

/* The map, and the confirmation. */
.ap-map {
  flex: none;
  overflow: hidden;
  border-radius: calc(4 * var(--u));
}

.ap-map img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ap-map--small {
  height: calc(110 * var(--u));
  margin-top: calc(10 * var(--u));
}

.ap-map--tall {
  height: calc(300 * var(--u));
  border-radius: 0;
}

.ap-body--done {
  align-items: center;
  text-align: center;
  margin-top: calc(-28 * var(--u));
}

.ap-done-check {
  display: grid;
  place-items: center;
  width: calc(56 * var(--u));
  height: calc(56 * var(--u));
  border-radius: var(--radius-circle);
  background: var(--ap-ink);
  color: var(--ap-screen);
  transform-origin: center;
}

.ap-done-check svg {
  width: calc(22 * var(--u));
  height: auto;
}

.ap-done-check[data-beat] {
  animation-name: st-badge-stamp;
  animation-timing-function: var(--ease-stamp);
}

.ap-done-title {
  margin-top: calc(10 * var(--u));
  font-size: calc(20 * var(--u));
  font-weight: var(--font-semi-bold);
}

.ap-done-sub {
  margin-top: calc(2 * var(--u));
  font-size: calc(14 * var(--u));
  color: var(--ap-ink-3);
}

.ap-section--rule {
  align-self: stretch;
  text-align: left;
  margin-top: calc(24 * var(--u));
}

/* ── The numbers — the results, on Sticker Red ────────────────────────
 * The shared results plane (story.css): completion arrives and parks
 * left, preference arrives and parks right, the usability score arrives
 * last and holds the centre with its industry tick. The windows and the
 * figures are inline hooks on the page; this file is the plate's colour
 * and the scale under the score — the tick at the industry average and
 * the marker's travel to 78, on the count's clock. */
.st-nums {
  --st-nums-ground: var(--ap-red);
}

.st-metric--sus .st-metric-ref {
  left: calc(68% - 0.5px);
}

/* The marker's travel comes from the shared count gate — same clock,
 * same curve as the figure. */
@container style(--st-on: 1) {
  .st-metric--sus .st-metric-marker {
    animation: st-mc-mark var(--duration-luxury) var(--ease-out-cubic) both;
  }
}

@keyframes st-mc-mark { to { left: calc(78% - 5px); } }

/* ── Close — the billboard carries its own line; only the asks sit on it. */
.st-close {
  --pos: 56% 50%;
}

/* ── Widths ─────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .st-plate--screens .st-plate-media {
    padding: var(--space-5);
    gap: var(--space-3);
  }

  .st-plate--two .st-plate-media {
    grid-template-columns: minmax(0, 1fr);
  }

  .st-plate--two .st-plate-media img:last-child {
    width: 50%;
  }

  .st-plate--states .st-plate-media img {
    max-width: 100%;
  }
}

@media (max-width: 640px) {
  .st-inbox {
    --st-slot-gap: var(--space-6);
  }
}

/* ── 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. ─────────────────── */
:root[data-motion="reduce"] .st-cover-title .ap-letter,
:root[data-motion="reduce"] .st-cover-title .ap-badge {
  animation: none;
  opacity: 1;
}

:root[data-motion="reduce"] .st-icon-badge,
:root[data-motion="reduce"] .st-icon--mail,
:root[data-motion="reduce"] .st-icon--artpilot {
  animation: none;
}

/* The score's marker, parked at 78 (the counts are the shared rule). */
:root[data-motion="reduce"] .st-metric--sus .st-metric-marker {
  left: calc(78% - 5px);
}
