/* ==========================================================================
   DAMAC Experience

   The conceit: the screen is an architectural drawing sheet. It has a
   drawing field, an elevation running up one edge, and a title block
   along the bottom, exactly like a real sheet. The visitor's answers
   build the elevation floor by floor, so progress is a tower going up
   rather than a bar filling in.

   Written by hand rather than compiled, because almost none of this is
   utility work and the booth machine should not need Node to deploy.

   Order: tokens, reset, sheet, title block, elevation, screens, motion,
   components, then the paper takeaway.
   ========================================================================== */

/* --------------------------------------------------------------- Tokens */

:root {
  /* Palette: warm near-black and brass, not black and yellow. Sampled
     from the materials the brand actually sells: dark stone, brass
     ironmongery, champagne anodising, and drawing paper. */
  --ground: #0b0a09;
  --ground-deep: #070605;
  --surface: #141210;
  --surface-hi: #1e1a16;
  --brass: #b98a44;
  --brass-dim: #7d5e2e;
  --champagne: #e5c77e;
  --paper: #ede7dc;
  --graphite: #2b2721;
  --ivory: #f2ede4;
  --ash: #8c857a;
  --line: rgb(242 237 228 / 12%);
  --line-strong: rgb(242 237 228 / 22%);
  --danger: #d4715f;
  --confirm: #8aa87f;

  /* The accent is swapped per archetype on the reveal and never before,
     so the moment it arrives it means something. */
  --accent: var(--brass);
  --accent-ink: #0b0a09;

  --font-display: "Bodoni Moda", Didot, "Bodoni MT", Georgia, serif;
  --font-ui: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Azeret Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  /* vmin drives the whole scale, so a 1080x1920 totem and a 1920x1080
     screen render at identical size and only a phone steps down. */
  --t-hero: calc(clamp(2.5rem, 9.5vmin, 8rem) * var(--scale));
  --t-display: calc(clamp(1.9rem, 6.2vmin, 5.25rem) * var(--scale));
  --t-heading: calc(clamp(1.35rem, 4vmin, 3.25rem) * var(--scale));
  --t-body-l: calc(clamp(1rem, 2.45vmin, 2rem) * var(--scale));
  --t-body: calc(clamp(0.9rem, 1.95vmin, 1.5rem) * var(--scale));
  --t-label: calc(clamp(0.7rem, 1.3vmin, 1rem) * var(--scale));
  --t-micro: clamp(0.7rem, 1.15vmin, 0.85rem);

  --s1: clamp(4px, 0.55vmin, 8px);
  --s2: clamp(8px, 1.1vmin, 14px);
  --s3: clamp(12px, 1.7vmin, 22px);
  --s4: clamp(18px, 2.6vmin, 34px);
  --s5: clamp(26px, 3.8vmin, 50px);
  --s6: clamp(36px, 5.4vmin, 72px);
  --s7: clamp(48px, 7.6vmin, 104px);

  --gutter: clamp(20px, 5vmin, 68px);
  --tap: 56px;

  /* Prose measure. Controls use --controls instead: a paragraph wants a
     comfortable reading width, a touch target wants to be as big as the
     sheet allows. Capping both the same way made choice tiles sit in a
     narrow column with a third of a totem empty beside them. */
  --measure: 72ch;
  --controls: 100%;

  /* Type multiplier. A totem is read standing in front of it and has the
     height to carry more weight, so the scale steps up on tall screens.
     Set once here and applied by every type token below. */
  --scale: 1;

  /* Motion is slow and weighted. Nothing springs. */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.7, 0, 0.84, 0);
  --fast: 240ms;
  --base: 480ms;
  --slow: 900ms;
  --cinematic: 1600ms;
}

/* A totem is taller than it is wide and is read standing in front of it.
   More height to spend and a longer viewing distance both argue for a
   heavier scale and a narrower measure. */
@media (max-aspect-ratio: 4/5) {
  :root {
    --scale: 1.18;
    --measure: 46ch;
  }

}

/* Landscape and desktop. Controls stop stretching on an ultrawide screen;
   on a totem they are free to use the whole sheet. */
@media (min-aspect-ratio: 1/1) {
  :root {
    --controls: 78rem;
  }
}

/* Phone. The scale is already at its clamp floor; what matters here is
   that a single column has room to breathe. */
@media (max-width: 640px) {
  :root {
    --measure: 100%;
    --gutter: clamp(18px, 5vw, 28px);
  }

}

/* ---------------------------------------------------------------- Reset */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--ground);
  color: var(--ivory);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  overscroll-behavior: none;
}

/* The kiosk is touched, not clicked. Kill the blue tap flash and text
   selection, which otherwise make every drag look like a bug. */
body.is-kiosk {
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

input,
select {
  font: inherit;
  color: inherit;
}

svg {
  display: block;
}

:focus-visible {
  outline: 2px solid var(--champagne);
  outline-offset: 3px;
}

/* The `hidden` attribute has to outrank the layout classes.
   The UA rule is [hidden]{display:none}, specificity (0,1,0), and every
   author rule like .actions{display:flex} beats it simply by being an
   author rule. Without this, hiding a .actions block in JS does nothing
   and the visitor sees Retake next to a camera that never opened. */
[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------ The sheet */

.sheet {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: 1fr auto;
  grid-template-areas:
    "field elevation"
    "titleblock titleblock";
  height: 100dvh;
  position: relative;
  isolation: isolate;
}

/* A faint construction grid, the kind that sits under a drawing before
   anything is inked. Never brighter than this: it should register as
   texture, not as a pattern. */
.sheet::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(to right, rgb(185 138 68 / 4%) 1px, transparent 1px),
    linear-gradient(to bottom, rgb(185 138 68 / 4%) 1px, transparent 1px);
  background-size: 7vmin 7vmin;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 42%, #000 30%, transparent 100%);
}

.field {
  grid-area: field;
  position: relative;
  overflow: hidden;
  padding: var(--gutter);
  display: grid;
}

/* Landscape puts the elevation on the left, where a drawing's key
   elevation usually sits, and gives the field a wider measure. */
@media (min-aspect-ratio: 1/1) {
  .sheet {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "elevation field"
      "titleblock titleblock";
  }
}

/* ------------------------------------------------------------ Elevation */

.elevation {
  grid-area: elevation;
  width: clamp(88px, 13vmin, 190px);
  border-inline-start: 1px solid var(--line);
  padding: var(--s4) var(--s2) 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--s2);
}

@media (min-aspect-ratio: 1/1) {
  .elevation {
    border-inline-start: 0;
    border-inline-end: 1px solid var(--line);
  }
}

.elevation__svg {
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: visible;
}

.elevation__caption {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
  text-align: center;
  padding-block-end: var(--s3);
}

/* On a phone the rail costs about 14% of the width to show a drawing too
   small to read. The sheet counter in the title block carries the same
   information there, so the rail stands down rather than taking space it
   cannot use. */
@media (max-width: 640px) {
  .elevation {
    display: none;
  }
}

/* Every stroke in the tower is drawn, never faded in. stroke-dasharray
   is set per element in JS from its own measured length. */
.tower-line {
  stroke: var(--brass-dim);
  stroke-width: 1.15;
  fill: none;
  vector-effect: non-scaling-stroke;
}

.tower-floor {
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity var(--base) var(--ease),
    transform var(--base) var(--ease);
}

.tower-floor.is-built {
  opacity: 1;
  transform: none;
}

/* The floor just answered glows briefly, so the visitor sees their tap
   land somewhere in the world rather than only on the button. */
.tower-floor.is-fresh .tower-line {
  stroke: var(--champagne);
  stroke-width: 1.6;
  transition:
    stroke var(--slow) var(--ease),
    stroke-width var(--slow) var(--ease);
}

.tower-crown {
  opacity: 0;
  transition: opacity var(--cinematic) var(--ease);
}

.tower-crown .tower-line {
  stroke: var(--accent);
  stroke-width: 1.4;
}

.tower-crown.is-built {
  opacity: 1;
}

.tower-ground {
  stroke: var(--brass);
  stroke-width: 1.4;
}

/* --------------------------------------------------------- Title block */

/* Bottom strip of every architectural sheet: who drew it, what it is,
   which sheet you are looking at. Here it carries the DAMAC lockup, the
   visitor's name once known, and the step counter. It is the only
   persistent chrome in the product. */
.titleblock {
  grid-area: titleblock;
  border-block-start: 1px solid var(--line-strong);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: stretch;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
  background: linear-gradient(to bottom, transparent, rgb(0 0 0 / 25%));
}

.titleblock__cell {
  padding: var(--s2) var(--gutter);
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: calc(var(--s5) + var(--s2));
}

.titleblock__cell + .titleblock__cell {
  border-inline-start: 1px solid var(--line);
}

.titleblock__cell--meta {
  justify-content: flex-end;
  gap: var(--s4);
}

.titleblock__value {
  color: var(--ivory);
}

.titleblock__sheet {
  color: var(--champagne);
  font-variant-numeric: tabular-nums;
}

.lockup {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: var(--t-label);
  letter-spacing: 0.42em;
  color: var(--ivory);
  text-transform: uppercase;
  white-space: nowrap;
}

.lockup__rule {
  display: block;
  width: 100%;
  height: 1px;
  background: var(--brass);
  margin-block-start: 3px;
}

@media (max-width: 620px) {
  .titleblock {
    grid-template-columns: auto 1fr;
  }

  .titleblock__cell--name {
    display: none;
  }
}

/* ------------------------------------------------------------- Screens */

/* All screens are stacked in the same grid cell. Only one is current;
   the rest are inert, unfocusable and out of the accessibility tree. */
/* Screens compose as one optically centred group, bounded by a measure.
 *
 * They used to be stretched to the full height of the field with `auto`
 * margins pushing actions to the bottom. That reads fine on a 16:9 screen
 * and falls apart on a 1080x1920 totem, where it left roughly 900px of
 * dead space between a question and its own answers, so the two read as
 * unrelated fragments. Centring a bounded group holds at every height.
 *
 * The attract screen is the one deliberate exception: it anchors low so
 * the type sits on the skyline's horizon. */
.screen {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
  gap: var(--s3);
}

/* Lists of controls stop at a comfortable measure rather than running the
   full 1080px of a totem. Deliberately not a blanket rule on every child:
   the viewfinder, the marks and the result card size themselves and must
   not be overridden. */
.question__options,
.paths,
.blocks {
  max-width: var(--controls);
  width: 100%;
}

/* Hiding is done with :not(.is-current), not with a plain `display:none`
   on .screen. Several screens carry a layout class of their own (.stack,
   .question in landscape) that also sets `display`, and at equal
   specificity the later rule wins: a plain .screen{display:none} loses
   to .stack{display:flex} and every screen renders at once. The extra
   class in this selector is what keeps it ahead of them. */
.screen:not(.is-current) {
  display: none;
}

.screen.is-entering {
  animation: screen-in var(--base) var(--ease) both;
  animation-delay: 120ms;
}

.screen.is-leaving {
  animation: screen-out 320ms var(--ease-out) both;
}

@keyframes screen-in {
  from {
    opacity: 0;
    transform: translateY(3vmin);
  }
}

@keyframes screen-out {
  to {
    opacity: 0;
    transform: translateY(-2vmin);
  }
}

/* Anything marked as a step enters staggered. --i is set in the markup. */
.step {
  animation: step-in var(--base) var(--ease) both;
  animation-delay: calc(200ms + var(--i, 0) * 60ms);
}

@keyframes step-in {
  from {
    opacity: 0;
    transform: translateY(1.6vmin);
  }
}

/* ------------------------------------------------------- Dimension rule */

/* A divider drawn the way a dimension line is drawn, with tick ends.
   It replaces the plain hairline everywhere a section break is needed. */
.rule {
  --rule-color: var(--line-strong);

  position: relative;
  height: 1px;
  background: var(--rule-color);
  transform-origin: left center;
  animation: rule-draw var(--base) var(--ease) both;
  animation-delay: calc(160ms + var(--i, 0) * 60ms);
}

.rule::before,
.rule::after {
  content: "";
  position: absolute;
  top: -3px;
  width: 1px;
  height: 7px;
  background: var(--rule-color);
}

.rule::before {
  left: 0;
}

.rule::after {
  right: 0;
}

.rule--accent {
  --rule-color: var(--brass);
}

@keyframes rule-draw {
  from {
    transform: scaleX(0);
  }
}

/* ---------------------------------------------------------- Typography */

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
}

.eyebrow--accent {
  color: var(--champagne);
}

.hero-type {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.015em;
  margin: 0;
}

.display-type {
  font-family: var(--font-display);
  font-size: var(--t-display);
  font-weight: 500;
  line-height: 1.06;
  margin: 0;
}

.heading-type {
  font-family: var(--font-ui);
  font-size: var(--t-heading);
  font-weight: 500;
  line-height: 1.18;
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}

.lede {
  font-size: var(--t-body-l);
  line-height: 1.5;
  color: var(--ash);
  margin: 0;
  max-width: 34ch;
}

.prose {
  font-size: var(--t-body-l);
  line-height: 1.6;
  margin: 0;
  max-width: 46ch;
}

/* ------------------------------------------------------------- Buttons */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--ivory);
  --btn-border: var(--line-strong);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--tap);
  padding: var(--s2) var(--s5);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-border);
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  transition:
    background var(--fast) var(--ease),
    color var(--fast) var(--ease),
    border-color var(--fast) var(--ease),
    transform 120ms var(--ease);
}

.btn:active {
  transform: scale(0.98);
}

.btn--primary {
  --btn-bg: var(--champagne);
  --btn-fg: var(--ground);
  --btn-border: var(--champagne);

  font-weight: 600;
}

.btn--primary:hover {
  --btn-bg: var(--ivory);
  --btn-border: var(--ivory);
}

.btn--ghost:hover {
  --btn-border: var(--brass);
  --btn-fg: var(--champagne);
}

.btn[disabled] {
  opacity: 0.38;
  pointer-events: none;
}

.btn--quiet {
  min-height: var(--tap);
  padding-inline: var(--s3);
  border-color: transparent;
  color: var(--ash);
}

.btn--quiet:hover {
  color: var(--ivory);
}

/* ------------------------------------------------------------- Attract */

.attract {
  justify-content: center;
  align-items: flex-start;
  gap: var(--s5);
  position: relative;
}

/* Bottom-aligned, so the skyline's ground line lands on the foot of the
   drawing field and reads as a horizon. Centred, it floated as a band
   across the middle of a totem with a hard edge under it. */
.attract__mark {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: grid;
  place-items: end center;
  pointer-events: none;
  overflow: hidden;
}

.attract__mark svg {
  width: min(130%, 165vmin);
  height: auto;
  opacity: 0.5;

  /* Fades the tops of the towers into the ground rather than ending
     them on a crisp horizontal. */
  mask-image: linear-gradient(to bottom, transparent, #000 42%, #000);
}

.attract .hero-type {
  max-width: 14ch;
  text-wrap: balance;
}

.skyline-line {
  fill: none;
  stroke: var(--brass-dim);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* The only ambient motion in the product: the skyline breathes, very
   slowly, the way a long exposure does. */
.attract__mark svg {
  animation: skyline-drift 24s ease-in-out infinite alternate;
}

@keyframes skyline-drift {
  to {
    transform: translateY(-1.2vmin) scale(1.015);
  }
}

.attract__cta {
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
}

/* The one pulsing element anywhere. Slow enough to read as breathing. */
.pulse {
  position: relative;
}

.pulse::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 1px solid var(--champagne);
  animation: pulse 3.2s var(--ease) infinite;
  pointer-events: none;
}

@keyframes pulse {
  0% {
    opacity: 0.8;
    transform: scale(1);
  }

  70%,
  100% {
    opacity: 0;
    transform: scale(1.14);
  }
}

/* -------------------------------------------------------------- Blocks */

.blocks {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-block: var(--s5);
}

.block-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s4);
  align-items: baseline;
  padding-block: var(--s4);
}

.block-row__index {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  color: var(--brass);
  letter-spacing: 0.1em;
}

.block-row__name {
  font-family: var(--font-ui);
  font-size: var(--t-heading);
  font-weight: 500;
  margin: 0 0 var(--s1);
  line-height: 1.2;
}

.block-row__note {
  color: var(--ash);
  margin: 0;
  font-size: var(--t-body);
}

/* ------------------------------------------------------------ Question */

.question {
  gap: var(--s4);
  position: relative;
}

.question__back {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  padding-inline-start: 0;
  z-index: 1;
}

.question__head {
  display: flex;
  flex-direction: column;
  gap: var(--s3);

  /* Room for the pinned Back button. Applied on every question, including
     the first, which has no Back: the question text must not jump down a
     line between question one and question two. */
  padding-block-start: calc(var(--tap) + var(--s2));
}

.question__text {
  max-width: 22ch;
}

.question__options {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  margin-block-start: var(--s3);
}

/* Two by two, sharing whatever height the sheet has left. A fixed
   aspect ratio on the tiles pushed the fourth one below the fold on a
   short screen, and a choice a visitor cannot see is a choice they
   cannot make. */
.question__options--visual {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
  min-height: 0;
  flex: 0 1 auto;
}

/* Landscape reads better as two columns: the question holds the left,
   the choices the right, divided by the same hairline language. */
@media (min-aspect-ratio: 1/1) {
  .question {
    display: grid;
    grid-template-columns: 2fr 3fr;
    grid-template-rows: 1fr;
    gap: var(--s6);
  }

  /* Both columns centre on the same optical line and the divider runs the
     full height of the field, so the pair reads as one division of a
     sheet rather than as two blocks that happen to sit side by side. */
  .question__head {
    padding-block-start: 0;
    padding-inline-end: var(--s5);
    border-inline-end: 1px solid var(--line);
    justify-content: center;
  }

  .question__options {
    margin-block-start: 0;
    justify-content: center;
  }
}

/* --------------------------------------------------------------- Choice */

.choice {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  min-height: var(--tap);
  padding: var(--s3) var(--s4);
  text-align: start;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ivory);
  position: relative;
  overflow: hidden;
  transition:
    background var(--fast) var(--ease),
    border-color var(--fast) var(--ease),
    transform 120ms var(--ease);
}

.choice:hover {
  background: var(--surface-hi);
  border-color: var(--brass-dim);
}

.choice:active {
  transform: scale(0.985);
}

.choice__key {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  color: var(--ash);
  letter-spacing: 0.1em;
  transition: color var(--fast) var(--ease);
}

.choice__label {
  font-size: var(--t-body-l);
  line-height: 1.3;
  text-wrap: balance;
}

/* A hairline sweeps the tile on selection, the way a highlighter passes
   over a drawing. It is the confirmation, so it must be visible at a
   glance from standing distance. */
.choice::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 100%;
  background: linear-gradient(90deg, transparent, rgb(229 199 126 / 16%), transparent);
  transform: translateX(-100%);
  pointer-events: none;
}

.choice.is-chosen {
  border-color: var(--champagne);
  background: var(--surface-hi);
}

.choice.is-chosen .choice__key {
  color: var(--champagne);
}

.choice.is-chosen::after {
  animation: sweep 520ms var(--ease) both;
}

@keyframes sweep {
  to {
    transform: translateX(100%);
  }
}

/* Visual variant: a drawn mark above a short label, in a square tile. */
/* Mark and label centre as a pair. Tiles stay large because this is
   touched, not clicked. */
.choice--visual {
  grid-template-columns: 1fr;
  grid-template-rows: auto auto;
  justify-items: center;
  align-content: center;
  gap: var(--s3);
  min-height: clamp(110px, 16vmin, 230px);
  padding: var(--s3);
  text-align: center;
}

.choice__mark {
  width: clamp(40px, 8vmin, 92px);
  height: clamp(40px, 8vmin, 92px);
  max-height: 100%;
}

.choice__mark path,
.choice__mark circle,
.choice__mark line,
.choice__mark polyline {
  fill: none;
  stroke: var(--brass);
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
  transition: stroke var(--fast) var(--ease);
}

.choice.is-chosen .choice__mark path,
.choice.is-chosen .choice__mark circle,
.choice.is-chosen .choice__mark line,
.choice.is-chosen .choice__mark polyline {
  stroke: var(--champagne);
}

.choice--visual .choice__label {
  font-size: var(--t-body);
}

/* ------------------------------------------------------------ Analysing */

.analysing {
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: var(--s4);
}

.analysing__status {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--champagne);
  min-height: 1.4em;
}

.analysing__status span {
  display: inline-block;
  animation: status-in 400ms var(--ease) both;
}

@keyframes status-in {
  from {
    opacity: 0;
    transform: translateY(0.5em);
  }
}

/* -------------------------------------------------------------- Reveal */

.reveal {
  justify-content: center;
  gap: var(--s4);
  position: relative;
}

.reveal__mark {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.reveal__mark svg {
  width: min(100%, 92vmin);
  height: auto;
  opacity: 0.22;
  animation: mark-bloom var(--cinematic) var(--ease) both;
}

/* In landscape the text holds the left, so the mark moves out from under
   it and sits in the open right of the sheet. Centred, it cut straight
   through the narrative. */
@media (min-aspect-ratio: 1/1) {
  .reveal__mark {
    place-items: center end;
    padding-inline-end: var(--s6);
  }

  .reveal__mark svg {
    width: min(56%, 76vmin);
    opacity: 0.18;
  }
}

.reveal__mark path,
.reveal__mark circle,
.reveal__mark line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.1;
  vector-effect: non-scaling-stroke;
}

@keyframes mark-bloom {
  from {
    opacity: 0;
    transform: scale(0.92);
  }
}

.reveal__name {
  color: var(--ivory);
}

/* Each word rises behind its own mask, the way a name is unveiled. */
.mask-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
}

.mask-word > span {
  display: inline-block;
  animation: mask-rise var(--slow) var(--ease) both;
  animation-delay: calc(400ms + var(--i, 0) * 90ms);
}

@keyframes mask-rise {
  from {
    transform: translateY(105%);
  }
}

.strengths {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  padding: 0;
  margin: 0;
  list-style: none;
}

.strength {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--accent);
  color: var(--ivory);
  animation: step-in var(--base) var(--ease) both;
  animation-delay: calc(900ms + var(--i, 0) * 90ms);
}

/* --------------------------------------------------------------- Paths */

/* The list takes the space that is left and scrolls inside itself if the
   copy runs long. Without this the action below it is pushed past the
   sheet's gutter and clipped by the title block, which is exactly the
   button the visitor needs. */
.paths {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  margin-block: var(--s4);
  padding: 0;
  list-style: none;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}

.paths::-webkit-scrollbar {
  display: none;
}

/* Set by JS only when the list actually overflows. */
.paths.is-scrollable {
  mask-image: linear-gradient(to bottom, #000 calc(100% - 6vmin), transparent);
}

.path {
  border: 1px solid var(--line);
  padding: var(--s4);
  background: var(--surface);
  display: grid;
  gap: var(--s2);
  animation: step-in var(--base) var(--ease) both;
  animation-delay: calc(200ms + var(--i, 0) * 120ms);
}

.path--lead {
  background: var(--surface-hi);
  border-color: var(--brass);
}

.path__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
}

.path__name {
  font-family: var(--font-ui);
  font-size: var(--t-heading);
  font-weight: 500;
  margin: 0;
  line-height: 1.15;
}

.path__fit {
  font-family: var(--font-mono);
  font-size: var(--t-body);
  color: var(--champagne);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.path__why {
  color: var(--ash);
  margin: 0;
  font-size: var(--t-body);
  max-width: 56ch;
}

.fitbar {
  height: 2px;
  background: var(--line);
  position: relative;
  overflow: hidden;
}

.fitbar::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--fit, 0%);
  background: var(--accent);
  transform-origin: left center;
  animation: fill var(--slow) var(--ease) both;
  animation-delay: calc(500ms + var(--i, 0) * 120ms);
}

@keyframes fill {
  from {
    transform: scaleX(0);
  }
}

/* ------------------------------------------------------------- Capture */

.capture {
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  text-align: center;
}

.viewfinder {
  position: relative;
  width: min(100%, 52vmin);
  aspect-ratio: 3 / 4;
  background: var(--surface);
  border: 1px solid var(--line);
  overflow: hidden;
}

.viewfinder video,
.viewfinder img,
.viewfinder canvas {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Corner brackets rather than a full frame: a registration mark, not a
   picture frame. */
.viewfinder__guide {
  position: absolute;
  inset: var(--s3);
  pointer-events: none;
}

.viewfinder__guide span {
  position: absolute;
  width: 4vmin;
  height: 4vmin;
  border: 1px solid var(--champagne);
}

.viewfinder__guide span:nth-child(1) {
  top: 0;
  left: 0;
  border-width: 1px 0 0 1px;
}

.viewfinder__guide span:nth-child(2) {
  top: 0;
  right: 0;
  border-width: 1px 1px 0 0;
}

.viewfinder__guide span:nth-child(3) {
  bottom: 0;
  left: 0;
  border-width: 0 0 1px 1px;
}

.viewfinder__guide span:nth-child(4) {
  bottom: 0;
  right: 0;
  border-width: 0 1px 1px 0;
}

.viewfinder__count {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: var(--t-hero);
  color: var(--ivory);
  background: rgb(11 10 9 / 45%);
}

.viewfinder__flash {
  position: absolute;
  inset: 0;
  background: var(--ivory);
  opacity: 0;
  pointer-events: none;
}

.viewfinder__flash.is-firing {
  animation: flash 220ms var(--ease-out) both;
}

@keyframes flash {
  0% {
    opacity: 0.55;
  }

  100% {
    opacity: 0;
  }
}

.shutter {
  width: var(--s7);
  height: var(--s7);
  min-width: 64px;
  min-height: 64px;
  border-radius: 50%;
  background: var(--champagne);
  border: none;
  transition: transform 120ms var(--ease);
}

.shutter:active {
  transform: scale(0.94);
}

.dropzone {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  gap: var(--s2);
  border: 1px dashed var(--brass-dim);
  color: var(--ash);
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* The generation wait. A scan line passes down the photograph and the
   graded version resolves behind it, so the visitor watches the change
   happen rather than watching a spinner. */
.viewfinder.is-processing img {
  filter: grayscale(1) contrast(1.1) brightness(0.72);
}

.scanline {
  position: absolute;
  inset-inline: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--champagne), transparent);
  box-shadow: 0 0 3vmin rgb(229 199 126 / 45%);
  animation: scan 2.6s var(--ease) infinite alternate;
}

@keyframes scan {
  from {
    top: 2%;
  }

  to {
    top: 98%;
  }
}

/* -------------------------------------------------------------- Split */

/* The same division as a question screen: heading on the left, the thing
   the visitor acts on to the right of a full-height hairline. Used by the
   details form, which is too tall to stack under a headline on a 16:9
   screen and would push its own consent box and submit button off the
   sheet. */
.split {
  gap: var(--s4);
}

.split__head {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.split__body {
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}

.split__body::-webkit-scrollbar {
  display: none;
}

@media (min-aspect-ratio: 1/1) {
  .split {
    display: grid;
    grid-template-columns: 2fr 3fr;
    grid-template-rows: 1fr;
    gap: var(--s6);
  }

  .split__head {
    padding-inline-end: var(--s5);
    border-inline-end: 1px solid var(--line);
    justify-content: center;
  }
}

/* --------------------------------------------------------------- Form */

.form {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin-block: var(--s4);
  max-width: 46ch;
  width: 100%;
}

.field-row {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.field-row__label {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ash);
}

/* Bottom-ruled inputs, the way a form is ruled on a drawing sheet.
   No boxes: boxes make a luxury layout look like a database. */
.field-row input,
.field-row select {
  background: transparent;
  border: 0;
  border-block-end: 1px solid var(--line-strong);
  padding: var(--s2) 0;
  font-size: var(--t-body-l);
  min-height: var(--tap);
  border-radius: 0;
  transition: border-color var(--fast) var(--ease);
}

.field-row select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--brass) 50%),
    linear-gradient(135deg, var(--brass) 50%, transparent 50%);
  background-position: right 6px center, right 1px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

.field-row select option {
  background: var(--surface);
  color: var(--ivory);
}

.field-row input:focus,
.field-row select:focus {
  outline: none;
  border-block-end-color: var(--champagne);
}

.field-row.has-error input,
.field-row.has-error select {
  border-block-end-color: var(--danger);
}

.field-row__error {
  color: var(--danger);
  font-size: var(--t-micro);
  min-height: 1.2em;
}

.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s3);
  align-items: start;
  padding-block: var(--s2);
  cursor: pointer;
  min-height: var(--tap);
}

/* 32px, not 24. The label wraps the copy so the whole row is the target,
   but the box is what a pointer aims at and 24px was under every
   accessible-size guideline going. */
.consent input {
  appearance: none;
  width: 32px;
  height: 32px;
  margin: 0;
  border: 1px solid var(--line-strong);
  background: transparent;
  display: grid;
  place-items: center;
  flex: none;
  transition: border-color var(--fast) var(--ease);
}

/* No pseudo-element here to enlarge the hit area: a ::before inside a
   grid container becomes a grid item of its own, taking the first cell
   and pushing the box and its text onto separate rows. The <label> wraps
   the input and the copy, so the whole row is already the tap target. */

.consent input::after {
  content: "";
  width: 15px;
  height: 9px;
  border: 2px solid var(--champagne);
  border-block-start: 0;
  border-inline-end: 0;
  transform: rotate(-45deg) translate(1px, -2px) scale(0);
  transition: transform var(--fast) var(--ease);
}

.consent input:checked {
  border-color: var(--champagne);
}

.consent input:checked::after {
  transform: rotate(-45deg) translate(1px, -2px) scale(1);
}

.consent__text {
  font-size: var(--t-micro);
  line-height: 1.55;
  color: var(--ash);
  letter-spacing: 0.01em;
}

/* ------------------------------------------------------------ Takeaway */

.takeaway {
  display: grid;
  gap: var(--s5);
  align-content: center;
  justify-items: center;
}

@media (min-aspect-ratio: 1/1) {
  .takeaway {
    grid-template-columns: auto auto;
    align-items: center;
    justify-content: center;
  }
}

.qr {
  background: var(--paper);
  padding: var(--s3);
  display: grid;
  gap: var(--s2);
  justify-items: center;
}

.qr canvas,
.qr img {
  width: clamp(120px, 22vmin, 240px);
  height: auto;
  image-rendering: pixelated;
}

.qr__caption {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--graphite);
}

.takeaway__actions {
  display: flex;
  gap: var(--s2);
  flex-wrap: wrap;
  justify-content: center;
}

.sent {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--confirm);
  min-height: var(--tap);
}

/* ---------------------------------------------------- The result card */

/* The one place the palette inverts. Everything else in the product is
   a gallery at night; the takeaway is a drawing on warm paper, because
   a document is what a person keeps. */
.card {
  /* Wide enough that a three-word strength does not wrap to three lines
     once the portrait and the tower have taken their columns. */
  --card-w: min(90vw, 62vmin);

  width: var(--card-w);
  aspect-ratio: 4 / 5;
  background: var(--paper);
  color: var(--graphite);
  display: grid;
  grid-template-rows: auto 1fr auto;
  border: 1px solid var(--brass);
  position: relative;
  overflow: hidden;
}

.card::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 4px;
  background: var(--accent);
}

.card__head,
.card__foot {
  padding: var(--s3) var(--s4);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s2);
}

.card__head {
  border-block-end: 1px solid rgb(43 39 33 / 20%);
}

.card__foot {
  border-block-start: 1px solid rgb(43 39 33 / 20%);
}

.card__head-logo {
  height: 32px;
  width: auto;
  display: block;
}

/* Three columns, in the order a drawing reads: the subject, the notes on
   the subject, and the elevation keyed down the right edge. Two columns
   wrapped the tower onto a second row underneath the portrait, which
   read as a mistake rather than as a key. */
/* Stretch, not centre: the portrait fills the height of the field and the
   elevation runs its full depth, the way a drawing fills its sheet.
   Centring left a band of empty paper above and below both. */
.card__body {
  display: grid;
  grid-template-columns: 38% 1fr auto;
  /* Without this the single implicit row sizes to `auto`, i.e. to its
     tallest child's intrinsic size. The cloned tower SVG is set to
     height:100%, but a percentage height against an auto-sized ancestor
     resolves to auto too, so the SVG fell back to its own natural
     height (tall) and blew the row past the card's fixed height, the
     fit line printing over the graphic bleeding out from above it.
     minmax(0, 1fr) gives the row a definite height to stretch to, which
     the percentage heights below can then actually resolve against. */
  grid-template-rows: minmax(0, 1fr);
  gap: var(--s3);
  padding: var(--s4);
  align-items: stretch;
  min-height: 0;
}

.card__portrait {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: sepia(0.16) contrast(1.04);
  border: 1px solid rgb(43 39 33 / 25%);
}

.card__meta {
  align-content: center;
}

/* Stands in for the photograph when the visitor skipped that step. */
.card__portrait--empty {
  position: relative;
  border-style: dashed;
  overflow: hidden;
}

/* An elevation drawing of a DAMAC tower, filling the frame edge to
   edge as quiet background texture rather than sitting inset. cover,
   not contain: this is the frame's whole content now, not one layer
   behind a logo watermark, so it should read as filling the space a
   photograph would rather than floating inside it. */
.card__watermark-tower {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.75;
}

.card__meta {
  display: grid;
  gap: var(--s2);
  align-content: center;
  min-width: 0;
}

.card__name {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(43 39 33 / 70%);
  margin: 0;
}

.card__archetype {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 3.4vmin, 2.6rem);
  line-height: 1.05;
  margin: 0;
}

.card__strengths {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  color: rgb(43 39 33 / 78%);
}

.card__tower {
  width: clamp(20px, 4.5vmin, 46px);
  align-self: stretch;
}

.card__tower .tower-line {
  stroke: var(--graphite);
  opacity: 0.55;
}

/* ------------------------------------------------------------- Notices */

/* Used for camera denial and delivery failure. Never styled as an error:
   at a live stand, a red panel is a bigger problem than the fault. */
.notice {
  border: 1px solid var(--brass-dim);
  background: var(--surface);
  padding: var(--s4);
  display: grid;
  gap: var(--s2);
  max-width: 46ch;
}

.notice__title {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
  margin: 0;
}

.notice p {
  margin: 0;
  color: var(--ash);
  font-size: var(--t-body);
}

/* ---------------------------------------------------------- Idle prompt */

.idle {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: none;
  place-items: center;
  background: rgb(7 6 5 / 88%);
  text-align: center;
  padding: var(--gutter);
}

.idle.is-open {
  display: grid;
}

.idle__inner {
  display: grid;
  gap: var(--s4);
  justify-items: center;
}

/* ---------------------------------------------------------- Utilities */

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.stack--tight {
  gap: var(--s2);
}

.stack--loose {
  gap: var(--s5);
}

/* Kept as a no-op hook so markup does not have to change everywhere.
   It used to be `margin-block-start: auto`, which is exactly what tore
   screens apart on tall displays. Screens now centre as a group instead;
   see the note on .screen. */
.push-down {
  margin-block-start: var(--s2);
}

.actions {
  display: flex;
  gap: var(--s2);
  flex-wrap: wrap;
  align-items: center;
}

/* ------------------------------------------- Pages, not kiosk screens */

/* The result page and the admin table are ordinary web pages: they
   scroll, they are read on a phone or a laptop, and they must not
   inherit the kiosk's locked viewport. */
body.is-page {
  overflow: auto;
  height: auto;
  min-height: 100%;
}

.page {
  max-width: 46rem;
  margin-inline: auto;
  padding: var(--gutter) var(--gutter) var(--s7);
  display: flex;
  flex-direction: column;
  gap: var(--s5);
}

.page--wide {
  max-width: 78rem;
}

.page__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  padding-block-end: var(--s3);
  border-block-end: 1px solid var(--line);
}

.page__hero {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  align-items: flex-start;
}

.page__portrait {
  width: min(100%, 22rem);
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border: 1px solid var(--brass-dim);
  margin-block-end: var(--s2);
}

.page__block {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

/* The page reuses .paths from the kiosk, where the list is a flexible
   scroller. On a page it must simply be as tall as its content. */
.page .paths {
  flex: none;
  overflow: visible;
  margin-block: 0;
}

.page__cta {
  border: 1px solid var(--brass-dim);
  padding: var(--s5);
  background: var(--surface);
}

.page__foot {
  border-block-start: 1px solid var(--line);
  padding-block-start: var(--s3);
}

/* On a page, screens are not stacked, so the hiding rule must not apply. */
.page .screen {
  display: flex;
}

/* --------------------------------------------------------------- Tally */

.tally {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

.tally__item {
  background: var(--surface);
  padding: var(--s3) var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.tally__value {
  font-family: var(--font-display);
  font-size: var(--t-heading);
  line-height: 1;
  color: var(--champagne);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- Table */

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-body);
}

.table th,
.table td {
  text-align: start;
  padding: var(--s2) var(--s3);
  border-block-end: 1px solid var(--line);
  vertical-align: top;
}

.table th {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
  font-weight: 400;
  white-space: nowrap;
  background: var(--surface);
}

.table a {
  color: var(--champagne);
}

.table__mono {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  white-space: nowrap;
}

.table__dim {
  color: var(--ash);
}

/* ---------------------------------------------------------------- Pager */

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  padding-block-start: var(--s4);
}

.pager__link {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--champagne);
}

.pager__status {
  min-width: 9rem;
  text-align: center;
}

.page code {
  font-family: var(--font-mono);
  color: var(--champagne);
}

/* ------------------------------------------------ Phone, component tier */

/* Like the totem block below, these live at the end of the file on
   purpose. A component override placed in a media query near the top
   loses to that component's own later rule at equal specificity, and it
   fails silently: `.paths { flex: 1 1 auto }` quietly beat an earlier
   `flex-shrink: 0` and left the career-paths screen unscrollable with its
   button below the fold. Token overrides can live at the top because
   nothing else writes them. Component overrides go here. */
@media (max-width: 640px) {
  /* A phone is not a kiosk. Centring a group taller than the viewport
     pushes its own submit button out of reach, so screens become
     ordinary scrolling pages at this width. */
  .screen {
    justify-content: flex-start;
    overflow-y: auto;
    scrollbar-width: none;
  }

  .screen::-webkit-scrollbar {
    display: none;
  }

  /* Children keep their natural height. As flex items they were shrinking
     to fit while their content spilled past the bottom, so the screen
     measured no overflow and never grew a scrollbar. */
  .screen > * {
    flex: 0 0 auto;
    min-height: auto;
  }

  /* Nested scrollers are redundant once the screen itself scrolls, and
     two of them trap the content in a short box. */
  .split__body,
  .paths {
    overflow: visible;
    mask-image: none;
  }

  /* Three columns inside a 4:5 card do not fit at 390px: the strengths
     spilled over the footer rule and collided with the fit reading. The
     elevation is the column to drop, because the portrait and the
     archetype are what the visitor actually keeps. */
  /* On a phone the width is the scarce dimension, and vmin IS the width,
     so `62vmin` sized the card at 242px and squeezed the meta column to
     106px. Sized from vw it uses the screen it actually has. */
  .card {
    --card-w: min(92vw, 60vh);
  }

  .card__body {
    grid-template-columns: 42% 1fr;
  }

  .card__tower {
    display: none;
  }
}

/* --------------------------------------------- Landscape, component tier */

@media (min-aspect-ratio: 1/1) {
  /* The card is a 4:5 portrait object, so on a landscape screen its
     height is the binding constraint, not its width. Sized from vmin it
     stood 775px tall in a 900px field and pushed the download and email
     buttons off the sheet. Sized from vh it always fits. */
  .card {
    --card-w: min(90vw, 48vh);
  }
}

/* ------------------------------------------------- Totem, component tier */

/* These must sit AFTER the components they adjust. Tokens can be set in a
   media query at the top of the file because nothing else writes them, but
   a component override up there loses to the component's own later rule at
   equal specificity, silently. That is why this block is down here.
 *
 * A totem has 1920px of height to spend. Thin controls floating in the
 * middle of it read as a phone layout that got stretched. */
@media (max-aspect-ratio: 4/5) {
  .screen {
    gap: var(--s4);
  }

  .choice {
    padding-block: var(--s4);
  }

  .question__options {
    gap: var(--s3);
  }

  .paths {
    gap: var(--s3);
  }

  .path {
    padding: var(--s5);
  }

  .block-row {
    padding-block: var(--s5);
  }

  /* Inputs get more weight on a totem, but not heading size: at 46ch the
     form could only show about eleven characters, so a real email address
     was clipped mid-word with no sign there was more. The form also takes
     the full sheet width here, which is what actually buys the room. */
  .form {
    max-width: var(--controls);
  }

  .field-row input,
  .field-row select {
    font-size: var(--t-body-l);
    min-height: calc(var(--tap) * 1.25);
  }

  .viewfinder {
    width: min(100%, 62vmin);
  }

  /* Centred, the archetype mark ran straight through the narrative and
     read as noise rather than as a drawn form. On a totem the type block
     sits mid-sheet, so the mark drops into the empty lower third: it
     stops colliding and it gives that space something to hold. */
  .reveal__mark {
    place-items: end center;
    padding-block-end: var(--s6);
  }

  .reveal__mark svg {
    width: min(88%, 72vmin);
    opacity: 0.16;
  }
}

/* ------------------------------------------------------- Reduced motion */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }

  .scanline,
  .pulse::after {
    display: none;
  }
}

/* ------------------------------------------------------------- Print */

/* The card is the only thing meant to leave the stand on paper. Every
   other screen is already display:none via `.screen:not(.is-current)`,
   so only the takeaway's own chrome (the eyebrow, the QR, the buttons,
   the finish action) needs clearing here, alongside the elevation rail
   and title block that sit outside the screen stack entirely. */
@media print {
  @page {
    size: 4in 5in;
    margin: 0;
  }

  /* `.sheet` is pinned to 100dvh with overflow:hidden, which the screen
     clips against fine but print does not: print ignores overflow and
     paginates the full box, so a 100dvh sheet spills onto a second,
     mostly blank page. Collapsing the chain back to auto height is what
     keeps this to the one sheet the card actually needs. */
  html,
  body,
  .sheet,
  .field {
    height: auto !important;
    min-height: 0 !important;
    overflow: visible !important;
    display: block !important;
    padding: 0 !important;
  }

  .sheet::before {
    display: none !important;
  }

  .elevation,
  .titleblock,
  .idle,
  .screen[data-screen="takeaway"] > .eyebrow,
  .screen[data-screen="takeaway"] > .actions,
  .takeaway > .stack {
    display: none !important;
  }

  .screen[data-screen="takeaway"],
  .takeaway,
  [data-slot="card-mount"] {
    display: block !important;
    position: static !important;
    inset: auto !important;
    margin: 0 !important;
    padding: 0 !important;
    min-height: 0 !important;
    background: none !important;
  }

  /* Browsers drop background colours and images from print output by
     default (the "background graphics" option is off unless a visitor
     turns it on), so without this the card would print as bare text on
     white, not the paper-and-brass card shown on screen. Forcing it here
     means what leaves the stand always matches what was on the glass. */
  .card,
  .card * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  .card {
    --card-w: 4in;
    margin: 0 auto !important;
  }
}
