@font-face {
  font-family: "Open Runde";
  src: url("fonts/OpenRunde-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Open Runde";
  src: url("fonts/OpenRunde-Semibold.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Open Runde";
  src: url("fonts/OpenRunde-Bold.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: "Material Symbols Rounded";
  src: url("fonts/MaterialSymbolsRounded.woff2?v=8") format("woff2");
  font-weight: 100 700;
  font-display: block;
}

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

html {
  color-scheme: light;
  -webkit-font-smoothing: antialiased;
}

body {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-ui);
  font-weight: var(--weight-ui-regular);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
  color: var(--neutral-10);
  text-wrap: pretty;
  background: var(--neutral-1);
}

h1,
h2,
p {
  margin: 0;
}

/* Icon supplied as an SVG (Material Symbols Rounded chevron): sized with the text, colored by it. */
.icon-svg {
  width: 1.25em;
  height: 1.25em;
  flex: none;
  fill: currentColor;
  /* Optical alignment: the chevron only fills the middle third of its box, so
     the empty box edges add about 0.4em of extra space on each side. Pull the
     box in by that amount: the visible gap to the label is the real gap, and
     the right padding matches the left. */
  margin-inline: -0.4em;
  transition: transform var(--motion-duration) var(--motion-easing);
}

/* Icons: Material Symbols Rounded. The look is set in this one rule.
   FILL 1 = filled, wght 700, GRAD 200, opsz 40. Icons in use are in the font
   subset (favorite, add, check, content_copy, qr_code_2, download, delete, edit_note, image, stop, celebration, check_circle, close, cloud_done, contact_mail, group, lock, quiz, videocam, mic, play_arrow, pause, replay_10, forward_10, volume_up, volume_off, fullscreen, fullscreen_exit); adding an icon means re-downloading the subset. */
.icon {
  font-family: "Material Symbols Rounded";
  font-weight: normal;
  font-style: normal;
  font-size: 1.25em;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  direction: ltr;
  flex: none;
  -webkit-font-feature-settings: "liga";
  font-feature-settings: "liga";
  font-variation-settings: "FILL" 1, "wght" 700, "GRAD" 200, "opsz" 40;
  user-select: none;
}

/* Wordmark */

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
  color: var(--neutral-10);
  text-decoration: none;
  border-radius: var(--radius-xs);
}

/* Buttons (Button component: primary, secondary, ghost) */

.button {
  --tint: var(--neutral-9);
  --edge: 0 0 0 0 transparent;
  --shadow-rest:
    0 1px 2px color-mix(in srgb, var(--tint) 8%, transparent),
    0 2px 5px color-mix(in srgb, var(--tint) 4%, transparent);
  --shadow-lift:
    0 2px 3px color-mix(in srgb, var(--tint) 8%, transparent),
    0 4px 8px color-mix(in srgb, var(--tint) 6%, transparent);
  --shadow-press: 0 1px 1px color-mix(in srgb, var(--tint) 8%, transparent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  border: 0;
  border-radius: var(--radius-s);
  padding: var(--space-s) var(--space-l);
  font-family: var(--font-ui);
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--tracking-l);
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--edge), var(--shadow-rest);
  transition:
    transform var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    background-color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .button:hover {
    transform: translateY(-1px);
    box-shadow: var(--edge), var(--shadow-lift);
  }
}

.button:active {
  transform: translateY(0) scale(0.97);
  box-shadow: var(--edge), var(--shadow-press);
}

.button:focus-visible {
  outline: 2px solid var(--cte-focus);
  outline-offset: 2px;
}

/* Button / primary (MinimalButton details in the brand yellow): a hairline
   ring, an inner highlight along the top edge, a soft drop shadow, and a
   chevron that nudges forward on hover. The ring is a deeper shade of the
   brand yellow (not black) and the shadow is tinted with golden brown. */
.button--primary {
  --tint: color-mix(in oklab, var(--color-1) 35%, var(--neutral-9));
  --edge:
    0 0 0 1px color-mix(in srgb, color-mix(in oklab, var(--color-1) 80%, var(--neutral-9)) 55%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 55%, transparent);
  --shadow-rest:
    0 1px 2px color-mix(in srgb, var(--tint) 22%, transparent),
    0 4px 8px color-mix(in srgb, var(--tint) 12%, transparent);
  --shadow-lift:
    0 2px 3px color-mix(in srgb, var(--tint) 24%, transparent),
    0 6px 12px color-mix(in srgb, var(--tint) 14%, transparent);
  --shadow-press: 0 1px 1px color-mix(in srgb, var(--tint) 22%, transparent);
  padding: var(--space-m) var(--space-l);
  border-radius: var(--radius-s);
  background: var(--color-1);
  color: var(--neutral-9);
}

@media (hover: hover) {
  .button--primary:hover {
    background: color-mix(in srgb, var(--color-1) 94%, var(--neutral-9));
  }
}

.button--primary:disabled {
  --edge: 0 0 0 0 transparent;
  background: var(--neutral-3);
  color: var(--neutral-6);
  box-shadow: none;
  transform: none;
  cursor: default;
}

.button--secondary {
  /* Flat: no shadow at rest, on hover or on press (the About button's look). */
  --shadow-rest: 0 0 0 0 transparent;
  --shadow-lift: 0 0 0 0 transparent;
  --shadow-press: 0 0 0 0 transparent;
  background: var(--neutral-3);
  color: var(--neutral-10);
}

.button--secondary:hover:not(:disabled) {
  background: var(--neutral-4);
}

.button--secondary:disabled {
  color: var(--neutral-6);
  transform: none;
  cursor: default;
}

/* Text link: a quiet action inside running content (send a new code, change
   the number). Not a button: no fill, no shadow. */
.link {
  padding: var(--space-xxs) var(--space-xs);
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--neutral-8);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  letter-spacing: var(--letter-spacing-s);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  transition:
    color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .link:hover:not(:disabled) {
    color: var(--neutral-10);
  }
}

.link:active:not(:disabled) {
  transform: scale(0.97);
}

.link:focus-visible {
  outline: 2px solid var(--cte-focus);
  outline-offset: 2px;
}

.link:disabled {
  color: var(--neutral-6);
  text-decoration: none;
  cursor: default;
}

@media (hover: hover) {
  .button:hover:not(:disabled) .icon-svg {
    transform: translateX(2px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .button,
  .icon-svg,
  .tl__body,
  .stage__pane {
    transition: none;
  }

  .tl__inner > *,
  .stage__pane {
    transform: none;
    filter: none;
  }

  .flow__screen {
    animation: none;
  }

  .field__wrap,
  .country {
    transition: none;
  }

  .code__slot.is-next.is-empty::after {
    animation: none;
  }

  .tip {
    transform: none;
    transition: opacity 150ms linear, visibility 0s linear 150ms;
  }
}

/* Page grid (see rules.md): one centered container, 12 columns.
   Every section uses the same outer edges, so the wordmark, headline,
   section titles and cards all start on one left line, and About, the
   sign-in and the last card all end on one right line. */

:root {
  --page-max: 1200px;
  --hero-max: 1440px;
  --grid-gap: var(--space-l);
  /* Fluid spacing: each value runs from its phone size (at 400px) to its
     desktop size (at 1200px) with clamp(), so no breakpoint has to step it. */
  --page-gutter: clamp(var(--space-m), 0.03rem + 3.875vw, var(--space-xxl));
  /* Vertical rhythm: space between sections, and between a section's
     title and its content. Both derive from the theme's spacing. */
  --section-gap: clamp(calc(var(--space-xxl) * 1.5), 2.1rem + 8.9vw, calc(var(--space-xxl) * 3));
  --section-inner: clamp(var(--space-xl), 1.4rem + 2vw, var(--space-xxl));
  /* How it works and the privacy panel share one inner layout: the same inset
     from the page container (the privacy panel's padding), and the same two
     columns (copy column + a 380px illustration column). */
  --inset: clamp(1.25rem, calc(6.3vw - 5px), calc(var(--space-xxl) * 1.5));
  --art-col: 380px;
  --tl-gap: clamp(var(--space-s), 0.5rem + 1vw, var(--space-m));

  /* Marks and soft fills on light surfaces are warm grey, never yellow: the brand
     yellow belongs to the buttons (the primary call to action) and nothing else. */
  --tint-strong: var(--neutral-8);
  --tint-soft: var(--neutral-3);

  /* Fluid type. Three heading levels, shared by every section so the page
     reads as one scale: display (How it works, privacy, About; the hero
     headline is a step above), section (smaller blocks), and item (timeline
     steps, privacy points). Line heights are
     unitless so they follow the size. */
  --type-display: clamp(var(--size-l), 1.1rem + 1.5vw, var(--size-xl));
  --type-section: clamp(1.375rem, 1.2rem + 0.5vw, var(--size-l));
  --type-item: clamp(1.125rem, 1rem + 0.4vw, 1.25rem);
}

.topbar,
.split,
.manual {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* Top bar: wordmark on the left edge, About on the right edge. */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-l);
}

/* Landing page: the top bar and the hero share one frame, wider than the
   1200px container and centered on the screen, so both margins are always
   equal. The sections below stay on the 1200px container, centered: How it
   works is a narrower block and the grey panel is a card, both on the page's
   center line. */
.landing .topbar,
.landing .split {
  max-width: var(--hero-max);
}

/* Hero: headline and sign-in on columns 1-6, preview on 7-12. It fills 80% of
   the first screen; both halves center on it. */
.split {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-template-rows: 1fr auto auto auto 1fr;
  column-gap: var(--grid-gap);
  min-height: 80svh;
  padding-block: var(--space-xxl);
}

.pitch__title {
  grid-column: 1 / span 6;
  grid-row: 2;
  margin: 0 0 var(--space-s);
  max-width: 14em;
  text-align: left;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  /* The page's biggest type, a step above the 36px section headings: up to
     40px, shrinking with the half-width column so it always holds its two
     lines and leaves air before the preview. Tracking tightens as the size
     grows. */
  font-size: min(calc(var(--size-xl) * 1.11), 3.1vw);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xxl);
  color: var(--neutral-10);
  text-wrap: balance;
}

/* Second line of the headline starts on its own line. */
.pitch__accent {
  display: block;
}

/* Quiet line under the headline: this is a concept, nothing is saved. */
.pitch__note {
  grid-column: 1 / span 6;
  grid-row: 3;
  margin: 0 0 var(--space-xxl);
  max-width: 360px;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

/* The same line on the friend's side, tucked under their video (pulled up
   from the step's gap). */
.rxconcept {
  margin: calc(var(--space-s) - var(--space-xl)) 0 0;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

@media (max-width: 600px) {
  .rxconcept {
    margin-top: calc(var(--space-s) - var(--space-m));
  }
}

/* And on the dashboard, under the grid of cards. */
.dash__concept {
  margin: var(--space-xl) 0 0;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

.pitch__note a,
.rxconcept a,
.dash__concept a,
.footer__concept a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  border-radius: var(--radius-xs);
}

.pitch__note a:focus-visible,
.rxconcept a:focus-visible,
.dash__concept a:focus-visible,
.footer__concept a:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Prototype preview: three screens stacked like Instagram's, read left to
   right as a capsule's life: pick the questions (setup), a friend answers on
   camera (the friend's side), the capsule fills up (the capsule page). Each
   screen copies the real one's look, scaled down; side screens tuck under the
   front one. Stickers are real pieces from other screens. */

/* The preview's column: grid columns 7-12. */
.split__preview {
  grid-column: 7 / -1;
  grid-row: 1 / -1;
  align-self: center;
  /* The preview scales to this column (cqi), not the viewport. */
  container-type: inline-size;
}

.mock {
  /* One scale for the whole picture. Every size below is a number times --u,
     so the preview scales as one piece with no breakpoint. On desktop it fills
     its column (570: room for the optical inset below), up to 1.3x, and never
     gets taller than the hero. */
  --u: clamp(0.5px, min(calc(100cqi / 570), calc((80svh - 2 * var(--space-xxl)) / 470)), 1.3px);
  --shadow:
    0 0 0 calc(1 * var(--u)) color-mix(in oklch, var(--neutral-9) 7%, transparent),
    0 calc(2 * var(--u)) calc(4 * var(--u)) color-mix(in oklch, var(--neutral-9) 6%, transparent),
    0 calc(12 * var(--u)) calc(24 * var(--u)) color-mix(in oklch, var(--neutral-9) 9%, transparent),
    0 calc(32 * var(--u)) calc(56 * var(--u)) color-mix(in oklch, var(--neutral-9) 11%, transparent);
  position: relative;
  width: calc(560 * var(--u));
  height: calc(470 * var(--u));
  /* Optical: the right card's 4deg tilt pokes its corner ~10px past the box,
     so the box steps in by that much and the card's visible edge lands on
     About's edge. */
  margin-inline: auto calc(10 * var(--u));
  /* hero-float.js floats and tilts the whole stack as one piece. */
  will-change: transform;
}

.mock__card {
  position: absolute;
  top: 50%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(10 * var(--u));
  padding: calc(16 * var(--u));
  border-radius: calc(29 * var(--u));
  overflow: hidden;
  background: var(--neutral-1);
  color: var(--neutral-10);
  text-align: left;
  box-shadow: var(--shadow);
}

.mock__card--center {
  z-index: 2;
  left: 50%;
  align-items: stretch;
  width: calc(240 * var(--u));
  height: calc(440 * var(--u));
  padding: 0;
  transform: translate(-50%, -50%);
}

.mock__card--left,
.mock__card--right {
  z-index: 1;
  width: calc(200 * var(--u));
  height: calc(340 * var(--u));
}

/* Mirrored: same distance from the edges, same tilt the other way. */
.mock__card--left {
  left: 0;
  transform: translateY(-50%) rotate(-4deg);
}

.mock__card--right {
  /* Less than the left card: the tiles may tuck a little under the front card. */
  padding-left: calc(36 * var(--u));
  right: 0;
  transform: translateY(-50%) rotate(4deg);
}

/* Screen titles (cstep__title, capsule name), scaled down */
.mock__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: calc(16 * var(--u));
  line-height: calc(19 * var(--u));
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

.mock__sub {
  margin-top: calc(-6 * var(--u));
  color: var(--neutral-8);
  font-size: calc(11 * var(--u));
  line-height: calc(14 * var(--u));
}

/* 1. Questions: the five-slot strip and the rows, as on setup */
.mock__slots {
  display: flex;
  gap: calc(4 * var(--u));
}

.mock__slots i,
.mock__qs i {
  display: grid;
  place-items: center;
  flex: none;
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  border-radius: calc(6 * var(--u));
  box-shadow: inset 0 0 0 calc(1.5 * var(--u)) var(--neutral-5);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: calc(10 * var(--u));
  font-style: normal;
  line-height: 1;
}

.mock__slots .is-on,
.mock__qs .is-on i {
  background: var(--neutral-8);
  color: var(--neutral-1);
  box-shadow: none;
}

.mock__qs {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  gap: calc(2 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
}

.mock__qs li {
  display: grid;
  grid-template-columns: calc(20 * var(--u)) minmax(0, 1fr);
  align-items: start;
  gap: calc(8 * var(--u));
  padding: calc(8 * var(--u));
  border-radius: calc(14 * var(--u));
  font-size: calc(11 * var(--u));
  line-height: calc(15 * var(--u));
}

.mock__qs li.is-on {
  background: var(--neutral-3);
}

/* The rows run the full width of the card, under the front one: the questions
   can be cut off, since the picture only has to say "a list of questions".
   The title wraps before the covered part so it stays readable. */
.mock__card--left .mock__qs {
  margin-right: calc(-16 * var(--u));
}

.mock__card--left .mock__title {
  max-width: calc(140 * var(--u));
}

/* Markers sit top left, centered on the question's first line (20 tall vs a
   15 line), not in the middle of a wrapped question. */
.mock__qs li > i {
  margin-top: calc(-2.5 * var(--u));
}

/* 2. The friend's camera, filling the screen: question on the picture, time
   top right, voice meter bottom left. */
.mock__cam {
  position: relative;
  display: grid;
  flex: 1;
  overflow: hidden;
  isolation: isolate;
  background: var(--neutral-6);
  color: var(--neutral-1);
}

/* The friend's self view, blurred and dimmed like the real one while
   answering (.rxcam.is-blurred), so the question reads on top. Bleeds past
   the edges so the blur has no pale rim. */
.mock__cam::before {
  content: "";
  position: absolute;
  inset: calc(-24 * var(--u));
  z-index: -1;
  background: url("img/hero-answer.jpg") center 30% / cover no-repeat;
  filter: blur(calc(10 * var(--u))) brightness(0.6);
}

.mock__cam > * {
  grid-area: 1 / 1;
}

.mock__chip {
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  margin: calc(10 * var(--u));
  padding: calc(5 * var(--u)) calc(8 * var(--u));
  border-radius: calc(10 * var(--u));
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  font-size: calc(11 * var(--u));
  line-height: calc(14 * var(--u));
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.mock__chip--time {
  align-self: start;
  justify-self: end;
}

.mock__chip--time i {
  width: calc(6 * var(--u));
  height: calc(6 * var(--u));
  border-radius: var(--radius-full);
  background: var(--error);
}

.mock__chip--voice {
  align-self: end;
  justify-self: start;
}

.mock__meter {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--u));
  height: calc(14 * var(--u));
}

.mock__meter i {
  width: calc(3 * var(--u));
  border-radius: var(--radius-full);
  background: var(--neutral-1);
}

.mock__meter i:nth-child(1),
.mock__meter i:nth-child(5) { height: 30%; }
.mock__meter i:nth-child(2),
.mock__meter i:nth-child(4) { height: 65%; }
.mock__meter i:nth-child(3) { height: 100%; }

/* The meter talks: the bars keep the diamond (tall in the middle, short at the
   ends) and each one swells and settles on its own beat, the way speech does,
   so it never reads as one linear sweep. Transform only. */
.mock__meter i {
  transform-origin: 50% 50%;
  animation: mock-talk var(--beat, 1.4s) ease-in-out var(--lag, 0s) infinite;
}

.mock__meter i:nth-child(1) { --beat: 1.3s; --lag: -0.2s; }
.mock__meter i:nth-child(2) { --beat: 1.7s; --lag: -0.9s; }
.mock__meter i:nth-child(3) { --beat: 1.1s; --lag: -0.5s; }
.mock__meter i:nth-child(4) { --beat: 1.9s; --lag: -1.3s; }
.mock__meter i:nth-child(5) { --beat: 1.5s; --lag: -0.7s; }

@keyframes mock-talk {
  0%, 100% { transform: scaleY(0.45); }
  20% { transform: scaleY(1); }
  40% { transform: scaleY(0.6); }
  62% { transform: scaleY(0.92); }
  80% { transform: scaleY(0.5); }
}

@media (prefers-reduced-motion: reduce) {
  .mock__meter i { animation: none; }
}

.mock__ask {
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(6 * var(--u));
  padding: calc(16 * var(--u));
  text-align: center;
  text-shadow:
    0 calc(1 * var(--u)) calc(2 * var(--u)) color-mix(in srgb, var(--neutral-10) 60%, transparent),
    0 calc(2 * var(--u)) calc(18 * var(--u)) color-mix(in srgb, var(--neutral-10) 55%, transparent);
}

.mock__qlabel {
  font-size: calc(11 * var(--u));
  line-height: calc(14 * var(--u));
  font-weight: var(--weight-ui-medium);
}

.mock__qtext {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: calc(21 * var(--u));
  line-height: 1.15;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

/* 3. The capsule page: people as squircle tiles, colored by status
   (--tile and --mark come from [data-status]). */
.mock__tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-self: stretch;
  gap: calc(6 * var(--u));
  margin: calc(4 * var(--u)) 0 0;
  padding: 0;
  list-style: none;
}

.mock__tiles li {
  display: flex;
  flex-direction: column;
  gap: calc(1 * var(--u));
  /* Squares, as on the capsule page. Whatever doesn't fit is clipped. */
  aspect-ratio: 1;
  overflow: hidden;
  padding: calc(7 * var(--u));
  border-radius: calc(18 * var(--u));
  background: var(--tile);
  color: var(--neutral-8);
  font-size: calc(8 * var(--u));
  line-height: calc(11 * var(--u));
  white-space: nowrap; /* "Adding answers" and "Invite received" stay on one line */
}

.mock__tiles b {
  color: var(--neutral-10);
  font-size: calc(11 * var(--u));
  line-height: calc(13 * var(--u));
  font-weight: var(--weight-ui-medium);
}

.mock__avatar {
  position: relative;
  display: grid;
  place-items: center;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  margin-bottom: auto;
  border-radius: calc(10 * var(--u));
  /* Always white, like the capsule page: the status lives in the tile's tint. */
  background: var(--neutral-1);
  color: var(--neutral-9);
}

.mock__avatar .keepsake {
  width: 90%;
  height: 90%;
}

/* Sealed: the keepsake stays, with a small lock in the corner. */
.mock__lock {
  position: absolute;
  right: calc(-3 * var(--u));
  bottom: calc(-3 * var(--u));
  display: grid;
  place-items: center;
  width: calc(14 * var(--u));
  height: calc(14 * var(--u));
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  box-shadow: 0 0 0 calc(1.5 * var(--u)) var(--tile);
}

.mock__lock .icon {
  font-size: calc(9 * var(--u));
}

@supports (corner-shape: squircle) {
  .mock__slots i,
  .mock__qs i,
  .mock__avatar {
    border-radius: 50%;
    corner-shape: squircle;
  }

  .mock__tiles li {
    border-radius: calc(26 * var(--u));
    corner-shape: squircle;
  }
}

/* Stickers: real pieces off other screens, tilted. hero-float.js floats
   them with the cards. */
.sticker {
  position: absolute;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--u));
  padding: calc(8 * var(--u)) calc(14 * var(--u));
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--neutral-10);
  font-size: calc(13 * var(--u));
  line-height: calc(18 * var(--u));
  font-weight: var(--weight-ui-medium);
  box-shadow: var(--shadow);
}

/* A dashboard capsule card's foot: time left and one dot per person. */
.sticker--card {
  top: calc(8 * var(--u));
  left: calc(20 * var(--u));
  align-items: flex-end;
  gap: calc(16 * var(--u));
  padding: calc(10 * var(--u)) calc(16 * var(--u));
  border-radius: calc(20 * var(--u));
  rotate: -5deg;
}

.sticker__time {
  display: flex;
  flex-direction: column;
  color: var(--neutral-8);
  font-size: calc(11 * var(--u));
  line-height: calc(14 * var(--u));
  font-weight: var(--weight-ui-regular);
}

.sticker__time b {
  color: var(--neutral-10);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: calc(18 * var(--u));
  line-height: calc(22 * var(--u));
  letter-spacing: var(--letter-spacing-xxl);
  font-variant-numeric: tabular-nums;
}

.sticker__dots {
  display: flex;
  gap: calc(5 * var(--u));
  padding-bottom: calc(3 * var(--u));
}

.sticker__dots i {
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-radius: var(--radius-full);
  background: var(--status);
}

@supports (corner-shape: squircle) {
  .sticker--card {
    border-radius: calc(28 * var(--u));
    corner-shape: squircle;
  }
}

/* The invitation video's takes: red hearts, the used one grey. */
.sticker--takes {
  right: calc(12 * var(--u));
  bottom: calc(26 * var(--u));
  rotate: 5deg;
}

.sticker__hearts {
  display: inline-flex;
  gap: calc(2 * var(--u));
}

.sticker__hearts .icon {
  color: var(--error);
  font-size: calc(18 * var(--u));
}

.sticker__hearts .is-lost {
  color: var(--neutral-4);
  transform: scale(0.85);
}

/* Sign-in column */

.signin {
  grid-column: 1 / span 6;
  grid-row: 4;
  width: 100%;
  /* Capped so the field and buttons don't stretch. On the left edge under the
     headline; centered when stacked. */
  max-width: 360px;
}

.signin__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.signin__body[hidden] {
  display: none;
}

.signin__action {
  width: 100%;
  padding-block: var(--space-m);
}

.signin__google {
  width: 1.25em;
  height: 1.25em;
  flex: none;
}

.signin__hint {
  position: relative;
  margin-bottom: calc(var(--space-s) * -1); /* cancels the column gap: the line box itself is the space above the field */
}

.signin__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  font-weight: var(--weight-ui-medium);
}

/* Info button: a small icon with a bigger hit area than it looks. */
.info {
  display: grid;
  place-items: center;
  padding: var(--space-xxs);
  margin: calc(var(--space-xxs) * -1) 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--neutral-7);
  cursor: pointer;
  transition:
    color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.info svg {
  width: var(--size-m);
  height: var(--size-m);
  fill: currentColor;
}

@media (hover: hover) {
  .info:hover {
    color: var(--neutral-10);
  }
}

.info:active {
  transform: scale(0.9);
}

.info[aria-expanded="true"] {
  color: var(--neutral-10);
}

.info:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 1px;
}

/* Info tip (tip.js): a small dark note placed next to its button, below it if
   there's room, above if not, kept 16px from the screen edges. It grows out of
   the button, fast, ease-out, and goes after 5 seconds. */
.tip {
  position: fixed;
  z-index: 50;
  top: 0;
  left: 0;
  width: max-content;
  max-width: min(18rem, calc(100vw - 2rem));
  padding: var(--space-s) var(--space-m);
  border-radius: var(--radius-s);
  /* Warm mid grey, not near-black; white on it is about 7.5:1. */
  background: var(--neutral-8);
  color: var(--neutral-1);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  font-weight: var(--weight-ui-regular);
  box-shadow: var(--shadow-m);
  text-align: left;
  text-wrap: pretty;
  opacity: 0;
  visibility: hidden;
  transform: translateY(calc(-1 * var(--space-xxs))) scale(0.96);
  transition:
    opacity 150ms var(--motion-easing),
    transform 150ms var(--motion-easing),
    visibility 0s linear 150ms;
}

.tip[data-side="above"] {
  transform: translateY(var(--space-xxs)) scale(0.96);
}

.tip.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

@media (prefers-reduced-motion: reduce) {
  .tip,
  .tip[data-side="above"] {
    transform: none;
  }
}

/* Legal line under the sign-in actions */
.signin__legal {
  margin-top: var(--space-xs);
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
  text-align: center;
}

.signin__legal a {
  color: var(--neutral-8);
  text-decoration: underline;
  text-underline-offset: 2px;
  border-radius: var(--radius-xs);
}

.signin__legal a:focus-visible {
  outline: 2px solid var(--cte-focus);
  outline-offset: 2px;
}

/* "or" with a hairline on each side */
.signin__or {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin-block: var(--space-xs);
  color: var(--neutral-6);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

.signin__or::before,
.signin__or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--neutral-4);
}

/* How it works: an icon, one bold instruction and one short note per step. */

.manual {
  padding-top: var(--section-gap);
  display: flex;
  flex-direction: column;
  gap: var(--section-inner);
}

.manual:last-of-type {
  padding-bottom: var(--section-gap);
}

.manual__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

/* How it works: progressive timeline (after Headspace). Timeline on
   columns 1-5, illustration stage on 7-12. One step is open at a time;
   steps auto-advance and the line under the open step fills like a timer. */

/* overflow-anchor: none stops the browser from anchoring the scroll position
   to a step inside the timeline. Otherwise, when that step closes, the browser
   scrolls the page to follow it, and the privacy section below jumps. */
.how {
  overflow-anchor: none;
  display: grid;
  /* Art on the left, the steps on the right. */
  grid-template-columns: minmax(0, var(--art-col)) minmax(0, 1fr);
  column-gap: var(--space-xxl);
  align-items: stretch;
  /* The step art sits on the brand yellow. Shadows on it are a warm
     amber-brown instead of grey, which would look dirty on yellow. */
  --stage-bg: var(--color-1);
  --stage-shadow: oklch(0.42 0.1 65);
  --stage-lift:
    0 0 0 1px color-mix(in oklch, var(--stage-shadow) 10%, transparent),
    0 1px 2px color-mix(in oklch, var(--stage-shadow) 14%, transparent),
    0 10px 28px color-mix(in oklch, var(--stage-shadow) 20%, transparent);
}

/* The "How it works" title sits on the page's left margin, like the wordmark
   and the hero headline. Its content (timeline, stage, note) is inset to the
   privacy copy's left edge and ends on the status card's right edge, so the
   title reads as the heading and everything under it lines up with the panel
   below. */
.manual--inset > :not(.manual__title) {
  margin-inline: var(--inset);
}

/* Desktop: the title, the art + steps, and the note are one block, centered on
   the page. Art and steps are equal columns (--art-col each), so the block has
   the same weight on both sides, and the title sits on its left edge, the art's
   edge. Narrower than the block, it shrinks and keeps the inset. */
@media (min-width: 901px) {
  .manual--inset {
    --how-w: calc(2 * var(--art-col) + var(--space-xxl));
    align-items: center;
  }

  .manual--inset > :not(.manual__title),
  .manual--inset > .manual__title {
    width: min(calc(100% - 2 * var(--inset)), var(--how-w));
    margin-inline: 0;
  }
}

.tl {
  grid-column: 2;
  grid-row: 1;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* While the script measures the tallest open state, nothing animates. */
.how.is-measuring * {
  transition: none !important;
}

.tl__step {
  --dot: var(--space-xl);
  position: relative;
  padding-bottom: clamp(var(--space-l), 1.06rem + 1.75vw, var(--space-xl));
}

.tl__step:last-child {
  padding-bottom: 0;
}

/* Track between this dot and the next one, centered under the dot. */
.tl__line {
  position: absolute;
  top: calc(var(--dot) + var(--space-xxs));
  bottom: var(--space-xxs);
  left: calc(var(--dot) / 2 - 1px);
  width: 2px;
  border-radius: var(--radius-full);
  background: var(--neutral-4);
  overflow: hidden;
}

.tl__step:last-child .tl__line {
  display: none;
}

.tl__fill {
  position: absolute;
  inset: 0;
  background: var(--neutral-10);
  transform: scaleY(0);
  transform-origin: top;
}

.tl__head {
  display: grid;
  grid-template-columns: var(--dot) minmax(0, 1fr);
  align-items: center;
  gap: var(--tl-gap);
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.tl__head:focus-visible {
  outline: 2px solid var(--cte-focus);
  outline-offset: 4px;
}

.tl__dot {
  display: grid;
  place-items: center;
  width: var(--dot);
  height: var(--dot);
  border-radius: var(--radius-full);
  background: var(--neutral-3);
  color: var(--neutral-7);
  font-size: var(--size-m);
  line-height: 1;
  transition:
    background-color var(--motion-large-duration) var(--motion-large-easing),
    color var(--motion-large-duration) var(--motion-large-easing),
    box-shadow var(--motion-large-duration) var(--motion-large-easing);
}

.tl__step.is-done .tl__dot,
.tl__step.is-open .tl__dot {
  background: var(--neutral-10);
  color: var(--neutral-1);
}

.tl__step.is-open .tl__dot {
  box-shadow: 0 0 0 4px var(--neutral-3);
}

.tl__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-m);
  color: var(--neutral-7);
  transition: color var(--motion-large-duration) var(--motion-large-easing);
}

.tl__step.is-open .tl__title,
.tl__head:hover .tl__title {
  color: var(--neutral-10);
}

/* Accordion body: rows animate from 0fr to 1fr so the height eases open.
   The text fades and settles slightly after the space opens, and leaves
   quickly on close, so the two never fight. */
.tl__body {
  display: grid;
  grid-template-rows: 0fr;
  margin-left: calc(var(--dot) + var(--tl-gap));
  transition: grid-template-rows var(--motion-large-duration) var(--motion-large-easing);
}

.tl__inner {
  min-height: 0;
  overflow: hidden;
}

.tl__inner > * {
  opacity: 0;
  transform: translateY(calc(var(--space-xxs) * -1));
  transition:
    opacity var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.tl__step.is-open .tl__body {
  grid-template-rows: 1fr;
}

.tl__step.is-open .tl__inner > * {
  opacity: 1;
  transform: none;
  transition-delay: 90ms;
}

.tl__text {
  max-width: 24em;
  padding-top: var(--space-s);
  color: var(--neutral-8);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

/* Illustration under the open step: phones only (main.js copies the stage
   pane in). */
.tl__art {
  display: none;
  margin-top: var(--space-m);
  padding: var(--space-l) var(--space-m);
  border-radius: var(--radius-l);
  background: var(--stage-bg);
}

/* Desktop stage: one pane per step, cross-faded with a slight blur so the
   swap reads as one smooth change. */
.stage {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  min-height: 420px;
  border-radius: var(--radius-xl);
  background: var(--stage-bg);
  overflow: hidden;
}

.stage__pane {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-l);
  opacity: 0;
  filter: blur(2px);
  transform: scale(0.98);
  transition:
    opacity var(--motion-large-duration) var(--motion-large-easing),
    filter var(--motion-large-duration) var(--motion-large-easing),
    transform var(--motion-large-duration) var(--motion-large-easing);
}

.stage__pane.is-active {
  opacity: 1;
  filter: none;
  transform: none;
}

/* Step art: small pieces of the real UI. Each part marked data-in builds in
   when its step opens: up 8px and in from 98%, ease-out, 70ms apart (--i).
   When the step closes they reset only after the pane has faded out, so
   nothing jumps while it is still visible, and they replay next time.
   --p orders the "picks" inside a piece (a question ticked, a dot turning
   green), which land after the piece itself is in. */
.art {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --reset: 0s var(--motion-large-duration);
  width: min(100%, 19rem);
  margin-inline: auto;
  color: var(--neutral-10);
  text-align: left;
}

.art [data-in],
.art[data-in] {
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition: opacity var(--reset), transform var(--reset);
}

:is(.stage__pane.is-active, .tl__step.is-open) :is(.art [data-in], .art[data-in]) {
  opacity: 1;
  transform: none;
  transition:
    opacity 400ms var(--ease-out) calc(120ms + var(--i, 0) * 70ms),
    transform 500ms var(--ease-out) calc(120ms + var(--i, 0) * 70ms);
}

/* A white card, lifted like the dashboard's */
.art--card {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  padding: var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  box-shadow: var(--stage-lift);
}

.art__title,
.art__name {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-l);
}

.art__name {
  font-size: var(--size-l);
  line-height: var(--line-l);
}

.art__sub {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* Squircle marks: avatars, question markers, slots */
.art__avatar,
.art__slots i,
.art__qs i {
  display: grid;
  place-items: center;
  flex: none;
  border-radius: var(--radius-xs);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-style: normal;
  line-height: 1;
}

@supports (corner-shape: squircle) {
  .art__avatar,
  .art__slots i,
  .art__qs i {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

/* 0. Friends */
.art__people {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

.art__people li {
  display: flex;
  align-items: center;
  gap: var(--space-s);
}

.art__avatar {
  width: 2.5rem;
  height: 2.5rem;
  background: var(--neutral-3);
  color: var(--neutral-9);
  font-size: var(--size-xs);
}

.art__who {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
  color: var(--neutral-8);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.art__who b {
  color: var(--neutral-10);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.art__copy {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
}

.art__more {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* 1. Questions: same strip and rows as setup. Picks land one by one. */
.art__slots {
  display: flex;
  gap: var(--space-xs);
}

.art__slots i,
.art__qs i {
  width: 1.75rem;
  height: 1.75rem;
  box-shadow: inset 0 0 0 1.5px var(--neutral-5);
  color: transparent;
  font-size: var(--size-s);
  transition:
    background-color var(--reset),
    color var(--reset),
    box-shadow var(--reset);
}

.art__qs {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.art__qs li {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-s);
  border-radius: var(--radius-m);
  font-size: var(--size-s);
  line-height: 1.4;
  transition: background-color var(--reset);
}

:is(.stage__pane.is-active, .tl__step.is-open) .art__slots i[style],
:is(.stage__pane.is-active, .tl__step.is-open) .art__qs i[style] {
  background: var(--neutral-8);
  color: var(--neutral-1);
  box-shadow: none;
  transition:
    background-color 200ms ease-out calc(700ms + var(--p) * 450ms),
    color 200ms ease-out calc(700ms + var(--p) * 450ms),
    box-shadow 200ms ease-out calc(700ms + var(--p) * 450ms);
}

:is(.stage__pane.is-active, .tl__step.is-open) .art__qs li:has(i[style]) {
  background: var(--neutral-3);
  transition: background-color 200ms ease-out calc(700ms + var(--p, 0) * 450ms);
}

.art__qs li:nth-child(1) { --p: 0; }
.art__qs li:nth-child(2) { --p: 1; }
.art__qs li:nth-child(4) { --p: 2; }

/* 2. The friend's camera: blurred self view, question on top */
.art--cam {
  position: relative;
  display: grid;
  overflow: hidden;
  isolation: isolate;
  aspect-ratio: 3 / 4;
  max-height: 22rem;
  border-radius: var(--radius-l);
  background: var(--neutral-6);
  color: var(--neutral-1);
  box-shadow: var(--stage-lift);
}

.art--cam::before {
  content: "";
  position: absolute;
  inset: -24px;
  z-index: -1;
  background: url("img/hero-answer.jpg") center 30% / cover no-repeat;
  filter: blur(14px) brightness(0.6);
}

.art--cam > * {
  grid-area: 1 / 1;
}

.art__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin: var(--space-m);
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-s);
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.art__chip--time {
  align-self: start;
  justify-self: end;
}

.art__chip--time i {
  width: var(--space-xs);
  height: var(--space-xs);
  border-radius: var(--radius-full);
  background: var(--error);
}

.art__chip--voice {
  align-self: end;
  justify-self: start;
}

.art__meter {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 1.25rem;
}

.art__meter i {
  width: 3px;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  transform: scaleY(0.3);
}

/* The voice meter talks while the step is open: constant motion, so linear-ish
   and looping, each bar on its own phase. */
:is(.stage__pane.is-active, .tl__step.is-open) .art__meter i {
  animation: art-voice 900ms ease-in-out infinite alternate;
}

.art__meter i:nth-child(2) { animation-delay: -300ms; }
.art__meter i:nth-child(3) { animation-delay: -600ms; }
.art__meter i:nth-child(4) { animation-delay: -150ms; }
.art__meter i:nth-child(5) { animation-delay: -450ms; }

@keyframes art-voice {
  from { transform: scaleY(0.25); }
  to { transform: scaleY(1); }
}

.art__ask {
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-l);
  text-align: center;
  text-shadow:
    0 1px 2px color-mix(in srgb, var(--neutral-10) 60%, transparent),
    0 2px 18px color-mix(in srgb, var(--neutral-10) 55%, transparent);
}

.art__qlabel {
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.art__qtext {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: 1.15;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

/* 3. Sealed: each person's dot turns green, then the lock settles in. */
.art--capsule {
  gap: var(--space-xxl);
}

.art__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
}

.art__lock {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-s);
  line-height: var(--line-s);
  opacity: 0;
  transform: scale(0.94);
  transform-origin: left center;
  transition: opacity var(--reset), transform var(--reset);
}

.art__lock .icon {
  font-size: 1rem;
}

:is(.stage__pane.is-active, .tl__step.is-open) .art__lock {
  opacity: 1;
  transform: none;
  transition:
    opacity 300ms var(--ease-out) 2000ms,
    transform 400ms var(--ease-out) 2000ms;
}

.art__dots {
  display: flex;
  gap: var(--space-xs);
}

.art__dots i {
  width: 0.875rem;
  height: 0.875rem;
  border-radius: var(--radius-full);
  background: var(--neutral-4);
  transition: background-color var(--reset);
}

:is(.stage__pane.is-active, .tl__step.is-open) .art__dots i {
  background: var(--color-4);
  transition: background-color 240ms ease-out calc(700ms + var(--p) * 300ms);
}

/* 4. Opened: the chest from the friend's Sealed screen, played the other
   way, and kept calmer than it (no overshoot, no dust, no sparkle), so the
   friend's slam stays the bigger moment. Closed and locked at rest;
   .is-playing (main.js, each time the step opens) runs one thing at a time:
     150ms   the shackle pops up, the lock wiggles once
     500ms   the lock drops away (ease-in: it falls)
     800ms   the lid lifts and tips back, easing to a stop
     900ms   the tapes rise a little inside, 60ms apart
   The chest sits in the middle of the stage, with room above it for the
   lid, so it's centered when open, not pushed to the bottom. */
.art--reveal {
  padding-top: 3.25rem; /* room for the lifted lid */
}

.art--reveal .chest {
  width: 12rem;
  margin: 0 auto;
}

/* The tapes always sit in the chest; only the friend's Sealed screen hides
   them (.chest__tapes is faded there), so show them here. */
.art--reveal .chest__tapes {
  opacity: 1;
}

.art--reveal .reveal__tape {
  transform-box: view-box;
}

.art--reveal .chest__lock {
  transform-origin: 100px 96px;
}

.art--reveal.is-playing .chest__shackle {
  animation: reveal-shackle 180ms cubic-bezier(0.23, 1, 0.32, 1) 150ms both;
}

.art--reveal.is-playing .chest__click {
  animation: reveal-shake 280ms cubic-bezier(0.77, 0, 0.175, 1) 200ms both;
}

.art--reveal.is-playing .chest__lock {
  animation: reveal-lock 320ms cubic-bezier(0.55, 0, 0.9, 0.35) 500ms both;
}

.art--reveal.is-playing .chest__lid {
  animation: reveal-lid 600ms cubic-bezier(0.23, 1, 0.32, 1) 800ms both;
}

.art--reveal.is-playing .reveal__tape {
  animation: reveal-rise 480ms cubic-bezier(0.23, 1, 0.32, 1) calc(900ms + var(--k) * 60ms) both;
}

@keyframes reveal-shackle {
  to { transform: translateY(-7px); }
}

@keyframes reveal-shake {
  0%, 100% { transform: rotate(0deg); }
  40% { transform: rotate(-6deg); }
  75% { transform: rotate(3deg); }
}

@keyframes reveal-lock {
  0% { opacity: 1; transform: translateY(0) rotate(0deg); }
  100% { opacity: 0; transform: translateY(24px) rotate(10deg); }
}

@keyframes reveal-lid {
  from { transform: translateY(0) rotate(0deg); }
  to { transform: translateY(-50px) rotate(-7deg); }
}

@keyframes reveal-rise {
  from { transform: translateY(14px); }
  to { transform: translateY(0); }
}

/* Reduced motion: no movement, it simply shows open with the tapes inside. */
@media (prefers-reduced-motion: reduce) {
  .art--reveal.is-playing * {
    animation-duration: 1ms !important;
    animation-delay: 0s !important;
  }
}

@supports (corner-shape: squircle) {
  .art--card,
  .art--cam {
    border-radius: var(--radius-xl);
    corner-shape: squircle;
  }
}

/* Reduced motion: no movement, everything simply there. */
@media (prefers-reduced-motion: reduce) {
  .art [data-in],
  .art[data-in],
  .art__lock {
    transform: none !important;
  }

  .art:not(.art--reveal) *,
  .art {
    transition-duration: 0s !important;
    transition-delay: 0s !important;
    animation: none !important;
  }
}

.manual__note {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

/* Trust: a light gray "vault" panel (theme neutral-3). Two promises on the
   left, a sealed capsule card on the right. */

.vault {
  --vault-bg: var(--neutral-3);
  --vault-muted: var(--neutral-8);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--art-col));
  align-items: center;
  gap: var(--section-inner);
  padding: clamp(var(--space-xl), 0.7rem + 4.9vw, var(--inset)) var(--inset);
  border-radius: clamp(var(--radius-l), 1.2rem + 1.6vw, var(--radius-xl));
  background: var(--vault-bg);
  color: var(--neutral-10);
}

.vault__copy {
  display: flex;
  flex-direction: column;
  gap: var(--section-inner);
}

.vault__title {
  max-width: 12em;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

.vault__points {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Icon and text on one top edge; the icon's box is nudged so the glyph
   lines up with the first line of the heading. */
.vault__point {
  display: grid;
  grid-template-columns: var(--space-xl) minmax(0, 1fr);
  gap: var(--tl-gap);
  align-items: start;
}

/* Icons are centered in a column as wide as the timeline's dots, so the two
   sections share one icon spine and one text edge. */
.vault__point > .icon {
  justify-self: center;
  font-size: var(--size-l);
  line-height: 1;
  margin-top: 1px;
}

.vault__point-title {
  margin: 0;
  font-weight: var(--weight-ui-medium);
  font-size: var(--type-item);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-m);
}

/* Same text style as the timeline's step text, so the two sections read alike. */
.vault__text {
  max-width: 24em;
  padding-top: var(--space-s);
  color: var(--vault-muted);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

/* The sealed capsule on the right is the dashboard's own card (.ccard), kept
   white, filling the art column. Under its name, its last routine check. */
.vault__card {
  width: 100%;
}

.vault__verified .icon {
  color: var(--success);
  font-size: 1.125rem;
}

/* Drawer (Vaul): the About story, sliding up from the bottom. */

.drawer__overlay {
  position: fixed;
  z-index: 100;
  inset: 0;
  background: var(--neutral-10-transparent);
}

.drawer {
  position: fixed;
  z-index: 101;
  right: 0;
  bottom: 0;
  left: 0;
  height: 97dvh;
  overflow: hidden;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  background: var(--neutral-2);
  color: var(--neutral-10);
  outline: 0;
}

.drawer__scroll {
  height: 100%;
  overflow-y: auto;
}

/* Close is a secondary button; this only positions it and squares up the padding. */
.drawer__close {
  position: absolute;
  z-index: 1;
  top: var(--space-l);
  right: var(--space-l);
  padding: var(--space-s);
}

.drawer__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-m);
  width: 100%;
  max-width: 560px;
  min-height: 100%;
  margin: 0 auto;
  padding: var(--space-xxl) var(--space-l);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

/* Vaul sets user-select: none on the whole drawer for mouse users. Turn it back
   on for the story, and (data-vaul-no-drag in the markup) stop a text selection
   from being read as a drag. */
.drawer__title,
.drawer__text {
  user-select: text;
}

.drawer__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

.drawer__text {
  margin: 0;
  color: var(--neutral-8);
}

.drawer__action {
  align-self: flex-start;
  margin-top: var(--space-s);
}

/* Under the story, before the button: who built it, each name a text link to
   their LinkedIn with the LinkedIn mark in front. Set like the story (same
   size, same grey) so it reads as its signature, with room on both sides.
   The marks are a light grey, so they don't outweigh the names. */
.drawer__credits {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--space-m);
  row-gap: var(--space-xs);
  margin-block: var(--space-l);
  color: var(--neutral-8);
  user-select: text;
}

.drawer__maker {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  border-radius: var(--radius-xs);
  color: var(--neutral-9);
  font-weight: var(--weight-ui-medium);
  text-decoration: underline;
  text-decoration-color: var(--neutral-5);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  white-space: nowrap;
  transition: color var(--motion-duration) var(--motion-easing), text-decoration-color var(--motion-duration) var(--motion-easing);
}

.drawer__maker-mark {
  flex: none;
  width: 0.9em;
  height: 0.9em;
  fill: var(--neutral-6);
  transition: fill var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .drawer__maker:hover {
    text-decoration-color: currentColor;
  }

  .drawer__maker:hover .drawer__maker-mark {
    fill: var(--neutral-9);
  }
}

.drawer__maker:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Onboarding flow (opens over the page after "Continue"). One question per
   screen in one centered column, no card around it, no progress bar. On phones
   the main action is pinned to the bottom of the screen. */

.flow {
  position: fixed;
  z-index: 90; /* under the About drawer (100) */
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--neutral-1);
}

.flow[hidden] {
  display: none;
}

/* Demo code notification (after iOS and macOS banners): a white card pinned top
   right, full width with the gutter on phones. App tile, sender and time, the
   message under it. Close is a small round button on the top-left corner, like
   macOS: it shows on hover or focus with a mouse, always on touch screens.
   Drops in from above; stays until closed. Named ping, not notice (taken). */
.ping {
  position: fixed;
  z-index: 1;
  top: var(--space-m);
  right: var(--page-gutter);
  width: min(360px, calc(100vw - 2 * var(--page-gutter)));
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-s) var(--space-m) var(--space-s) var(--space-s);
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  box-shadow: var(--shadow-m), 0 0 0 1px var(--neutral-4);
  animation: ping-in 400ms cubic-bezier(0.23, 1, 0.32, 1);
}

.ping[hidden] {
  display: none;
}

.ping__app {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-xs);
  background: var(--neutral-8);
  color: var(--neutral-1);
  font-size: var(--size-l);
  font-weight: var(--weight-ui-heavy);
  line-height: 1;
}

@supports (corner-shape: squircle) {
  .ping__app {
    border-radius: 30%;
    corner-shape: squircle;
  }
}

.ping__body {
  min-width: 0;
}

.ping__body p {
  margin: 0;
}

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

.ping__title {
  color: var(--neutral-10);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.ping__time {
  flex: none;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.ping__text {
  color: var(--neutral-9);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.ping__code {
  color: var(--neutral-10);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.ping__close {
  position: absolute;
  top: -8px;
  left: -8px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  box-shadow: 0 1px 3px #00000014, 0 0 0 1px var(--neutral-4);
  color: var(--neutral-8);
  cursor: pointer;
  transition:
    opacity 150ms ease-out,
    transform 150ms ease-out;
}

/* A bigger hit area than the 24px it draws. */
.ping__close::before {
  content: "";
  position: absolute;
  inset: -10px;
}

.ping__close svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.ping__close:active {
  transform: scale(0.92);
}

.ping__close:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

@media (hover: hover) and (pointer: fine) {
  .ping__close {
    opacity: 0;
    transform: scale(0.8);
  }

  .ping:hover .ping__close,
  .ping__close:focus-visible {
    opacity: 1;
    transform: none;
  }

  .ping__close:hover {
    background: var(--neutral-3);
  }
}

@keyframes ping-in {
  from {
    opacity: 0;
    transform: translateY(-16px) scale(0.98);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ping {
    animation-name: ping-fade;
  }

  @keyframes ping-fade {
    from {
      opacity: 0;
    }
  }
}

.flow__bar {
  flex: none;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: var(--space-l) var(--page-gutter);
}

/* Back sits top left; the wordmark stays centered whether it shows or not. */
.flow__back {
  grid-column: 1;
  justify-self: start;
  padding: var(--space-s);
}

.flow__back[hidden] {
  display: none;
}

.flow__back .icon-svg {
  margin-inline: 0;
}

.flow .wordmark {
  grid-column: 2;
}

@media (hover: hover) {
  .button.flow__back:hover:not(:disabled) .icon-svg {
    transform: translateX(-2px);
  }
}

.flow__main {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow-y: auto;
  padding: 0 var(--page-gutter) var(--space-xxl);
}

/* margin: auto centers the column on both axes, and falls back to the top when
   the content is taller than the screen. */
.flow__screen {
  width: 100%;
  max-width: 440px;
  container-type: inline-size; /* so the question can size itself to the column */
  margin: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  animation: flow-in var(--motion-large-duration) var(--motion-large-easing) both;
}

.flow__screen[hidden] {
  display: none;
}

@keyframes flow-in {
  from {
    opacity: 0;
    transform: translateY(var(--space-xs));
  }
}

.flow__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.flow__title {
  margin: 0;
  padding: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  /* Sized to the column (5.4cqi) so the longest question still fits on one
     line; short ones just sit a little smaller than they could. */
  font-size: clamp(1.25rem, 5.4cqi, 1.875rem);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

.flow__title:focus-visible {
  outline: 0;
}

.flow__text {
  color: var(--neutral-8);
}

.flow__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* What the user typed, shown in full in the sentence. */
.flow__contact {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
  overflow-wrap: anywhere;
}

/* A link inside a sentence: same size as the text, no padding. */
.link--inline {
  margin-left: var(--space-xs);
  padding: 0;
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  border-radius: var(--radius-xs);
}

/* Resend: a quiet line under the code. Counts down, then turns into a link. */
.flow__resend {
  margin-top: calc(var(--space-s) * -1);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.flow__resend .link {
  margin-left: calc(var(--space-xs) * -1);
}

.flow__time {
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

/* Large field: the name. */
.field__control--lg {
  padding-block: var(--space-m);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
}

/* Code: one real input (paste and one-time-code autofill keep working) laid
   over six single-digit slots. The input is invisible; the slots show what was
   typed, a soft digit where nothing is yet, and a ring on the next one. */
.code {
  position: relative;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-xs);
}

.code__input {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: transparent;
  caret-color: transparent;
  font-size: 16px; /* keeps iOS Safari from zooming into the field */
  opacity: 0;
  cursor: text;
}

.code__slot {
  display: grid;
  place-items: center;
  height: calc(var(--space-xxl) + var(--space-xs));
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  color: var(--neutral-10);
  font-size: var(--size-l);
  line-height: var(--line-l);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
  transition: box-shadow var(--motion-duration) var(--motion-easing);
}

.code__slot.is-empty {
  color: var(--neutral-5);
}

.code__slot.is-next {
  box-shadow: 0 0 0 2px var(--neutral-4);
}

/* The next empty slot shows a blinking cursor, like a field waiting for input. */
.code__slot.is-next.is-empty {
  position: relative;
  color: transparent;
}

.code__slot.is-next.is-empty::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2px;
  height: 1.25em;
  border-radius: var(--radius-full);
  background: var(--neutral-10);
  transform: translate(-50%, -50%);
  animation: caret-blink 1.1s step-end infinite;
}

@keyframes caret-blink {
  50% {
    opacity: 0;
  }
}

.code[data-invalid] .code__slot {
  box-shadow: inset 0 0 0 1px var(--error);
}

/* Phone field: the field splits in two. When the first character is a digit,
   a country pill opens on the left (its column grows from 0 while a gap
   opens), and the number keeps its own pill. --country-w is the pill's
   measured width, set from script. */
.field__wrap {
  --country-w: 0px;
  display: grid;
  grid-template-columns: var(--country-w) minmax(0, 1fr);
  column-gap: 0;
  transition:
    grid-template-columns var(--motion-large-duration) var(--motion-large-easing),
    column-gap var(--motion-large-duration) var(--motion-large-easing);
}

.field__wrap.is-phone {
  column-gap: var(--space-xs);
}

.country {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-large-duration) var(--motion-large-easing);
}

.field__wrap.is-phone .country {
  opacity: 1;
  pointer-events: auto;
}

.country__inner {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  height: 100%;
  padding: 0 var(--space-m);
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-m);
  line-height: var(--line-m);
  white-space: nowrap;
}

.country .icon-svg {
  margin-inline: 0;
  width: 1.25em;
  height: 1.25em;
  color: var(--neutral-7);
}

/* The native select sits on top, invisible: the system picker, keyboard and
   screen reader support come for free. */
.country select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.country:has(select:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Moment choices: real radios, drawn as soft rows. */
.options {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.options .flow__title {
  margin-bottom: var(--space-m);
}

.option {
  position: relative;
  display: block;
  cursor: pointer;
}

.option input {
  position: absolute;
  opacity: 0;
  inset: 0;
  margin: 0;
  cursor: inherit;
}

.option span {
  display: block;
  padding: var(--space-m) var(--space-l);
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  font-weight: var(--weight-ui-medium);
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .option:hover span {
    background: var(--neutral-4);
  }
}

.option input:checked + span {
  background: var(--neutral-1);
  box-shadow: inset 0 0 0 2px var(--neutral-10);
}

.option input:focus-visible + span {
  outline: 2px solid var(--cte-focus);
  outline-offset: 2px;
}

/* Text field component */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
}

.field__label {
  font-weight: var(--weight-ui-medium);
}

.field__control {
  width: 100%;
  padding: var(--space-s) var(--space-m);
  border: 0;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  color: var(--neutral-10);
  font: inherit;
  /* 16px keeps iOS Safari from zooming into the field */
  font-size: max(var(--size-s), 16px);
}

/* Focus ring per the latest Autocomplete input spec: 2px, neutral-4. */
.field__control:focus-visible {
  outline: 0;
  box-shadow: 0 0 0 2px var(--neutral-4);
}

/* Invalid state per the Text field spec: 1px error edge, fill stays neutral-3. */
.field__control[aria-invalid="true"] {
  box-shadow: inset 0 0 0 1px var(--error);
}

.field__error {
  color: var(--error);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

/* Dashboard (empty state). Layout after the Graphical dashboard: a top bar and
   a grid of large cards, in the slowvenir theme. */

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

.dash {
  min-height: 100svh;
  background: var(--neutral-1);
}

.dash__bar,
.dash__main {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.dash__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-l);
}

.dash__main {
  padding-block: var(--space-l) var(--section-gap);
}

/* Top right: the checklist progress and the account, side by side in one pill. */
.dash__create[hidden] {
  display: none;
}

.dash__account {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  padding: var(--space-xxs);
  border-radius: var(--radius-full);
  background: var(--neutral-3);
}

/* Progress: a badge with a segmented ring, one segment per checklist item,
   yellow when done (like story bars). */
.progress,
.avatar {
  position: relative;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--neutral-10);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .progress:hover,
  .avatar:hover {
    background: var(--neutral-4);
  }
}

.progress:active,
.avatar:active {
  transform: scale(0.95);
}

.progress:focus-visible,
.avatar:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.progress__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.progress__seg {
  fill: none;
  stroke: var(--neutral-5);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 29 71; /* one third of the ring (pathLength 100), minus a gap */
  transition: stroke var(--motion-large-duration) var(--motion-large-easing);
}

.progress__seg.is-done {
  stroke: var(--tint-strong);
}

.progress__count {
  position: relative;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-xs);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.avatar__face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--neutral-5);
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-s);
  line-height: 1;
}

.avatar__face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Grid of cards. Columns are as wide as the Graphical reference's cards
   (two across on a wide screen, one on a phone) without a breakpoint. New
   capsules join this grid after the create card. */
.dash__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr));
  gap: var(--space-l);
}

/* Three kinds of card share one size, corner and padding, and are told apart
   by how they are made: a capsule is a raised white card, a draft is a dotted
   outline (still in progress), and the last tile is a flat grey one with the
   one yellow button, the way to start a capsule. */
.dash__grid {
  --card-pad: var(--space-xl);
}

@media (max-width: 600px) {
  .dash__grid {
    --card-pad: var(--space-l);
  }
}

.dash__create[hidden] {
  display: none;
}

.dash__create {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-m);
  width: 100%;
  aspect-ratio: 4 / 3;
  padding: var(--card-pad);
  border: 0;
  border-radius: var(--radius-xl);
  background: var(--neutral-3);
  color: var(--neutral-10);
  font: inherit;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

@supports (corner-shape: squircle) {
  .dash__create,
  .draft {
    border-radius: calc(var(--radius-xl) * 1.4);
    corner-shape: squircle;
  }
}

@media (hover: hover) {
  .dash__create:hover {
    background: var(--neutral-4);
  }

  .dash__create:hover .dash__plus {
    transform: translateY(-1px);
    box-shadow: var(--edge), var(--shadow-lift);
  }
}

.dash__create:active {
  transform: scale(0.99);
}

.dash__create:active .dash__plus {
  transform: scale(0.97);
  box-shadow: var(--edge), var(--shadow-press);
}

.dash__create:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.dash__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
}

.dash__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-l);
  text-wrap: balance;
}

.dash__sub,
.dash__label {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-wrap: pretty;
}

/* The one yellow button, a squircle. */
.dash__plus {
  flex: none;
  width: 4rem;
  height: 4rem;
  padding: 0;
  border-radius: var(--radius-s);
}

@supports (corner-shape: squircle) {
  .dash__plus {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.dash__plus svg {
  width: 45%;
  height: 45%;
  fill: currentColor;
}

/* Where a draft is: six steps, the done ones filled. */
.dash__steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.dash__segs {
  display: flex;
  gap: var(--space-xxs);
}

.dash__segs i {
  width: 1.5rem;
  height: 0.375rem;
  border-radius: var(--radius-full);
  background: var(--neutral-4);
}

.dash__segs i.is-done {
  background: var(--neutral-8);
}

/* A draft: no fill, a dotted outline (it is still in progress). The whole card
   is a link; the three-dot menu sits above it. */
.draft {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-l);
  aspect-ratio: 4 / 3;
  padding: var(--card-pad);
  border-radius: var(--radius-xl);
  background: none;
  color: var(--neutral-10);
  transition: background-color var(--motion-duration) var(--motion-easing);
}

/* The dotted stroke: a border on its own layer so it follows the corners. */
.draft::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 2px dotted var(--neutral-5);
  border-radius: inherit;
  corner-shape: inherit;
  pointer-events: none;
}

@media (hover: hover) {
  .draft:hover {
    background: var(--neutral-3);
  }
}

.draft__link {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  corner-shape: inherit;
}

.draft__link:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.draft__head {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-m);
}

.draft__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  min-width: 0;
}

.draft__name {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-l);
  text-wrap: balance;
  overflow-wrap: anywhere;
}

.draft__sub {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* Three dots: a quiet round button, level with the name. */
.draft__more {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  margin: calc(var(--space-xs) * -1) calc(var(--space-xs) * -1) 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--neutral-8);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing);
}

.draft__more svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

@media (hover: hover) {
  .draft__more:hover {
    background: var(--neutral-4);
    color: var(--neutral-10);
  }
}

.draft__more[aria-expanded="true"] {
  background: var(--neutral-4);
  color: var(--neutral-10);
}

.draft__more:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.draft__menu {
  position: absolute;
  top: 100%;
  right: calc(var(--space-xs) * -1);
  z-index: 3;
  min-width: 11rem;
  padding: var(--space-xxs);
  border-radius: var(--radius-s);
  background: var(--neutral-1);
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--neutral-9) 8%, transparent),
    0 8px 24px color-mix(in oklch, var(--neutral-9) 14%, transparent);
}

.draft__menu[hidden] {
  display: none;
}

.draft__delete {
  display: block;
  width: 100%;
  padding: var(--space-s) var(--space-m);
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--error);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  text-align: start;
  cursor: pointer;
}

@media (hover: hover) {
  .draft__delete:hover {
    background: var(--neutral-3);
  }
}

.draft__delete:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -2px;
}

.draft__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-m);
}

/* Continue: a flat grey arrow, quiet next to the capsules. */
.draft__go {
  display: grid;
  place-items: center;
  flex: none;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  color: var(--neutral-10);
  transition: background-color var(--motion-duration) var(--motion-easing);
}

@supports (corner-shape: squircle) {
  .draft__go {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.draft__go svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

@media (hover: hover) {
  .draft:hover .draft__go {
    background: var(--neutral-4);
  }
}

/* Sheets: every bottom sheet is a Vaul drawer (the same one as About). The
   page that owns a sheet defines its content as a <template id="sheet-NAME">,
   and sheets.js shows it. */

.sheet__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
}

.sheet__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
}

.sheet__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.acct__list[hidden] {
  display: none;
}

.acct__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Header: title and a line of context on the left, progress badge on the right
   (after Spotify's "Getting started" panel). */
.acct__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
}

.acct__intro {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
}

.acct__sub {
  margin: 0;
  text-wrap: balance;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.acct__head .sheet__title {
  margin-right: auto;
}

/* Hide the checklist: a quiet text link at the bottom, on the left edge. */
.acct__dismiss {
  align-self: flex-start;
  margin-left: calc(var(--space-xs) * -1); /* its padding, so the text lines up with the rows */
}

.acct__count {
  flex: none;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-full);
  background: var(--tint-soft);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-m);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Rows reach the panel's padding edge, so the hover fill is roomy and the
   touch target is tall. Each row: an icon tile, a numbered name, one line. */
.acct__item {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-s);
  width: calc(100% + 2 * var(--space-s));
  margin-inline: calc(var(--space-s) * -1);
  padding: var(--space-s);
  border: 0;
  border-radius: var(--radius-m);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--motion-duration) var(--motion-easing);
}

div.acct__item {
  cursor: default;
}

@media (hover: hover) {
  button.acct__item:hover,
  a.acct__item:hover {
    background: var(--neutral-3);
  }

  /* The tile is the same gray as the hovered row, so it steps one shade darker
     to keep its shape. */
  button.acct__item:hover .acct__tile,
  a.acct__item:hover .acct__tile {
    background: var(--neutral-4);
  }
}

.acct__item:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -2px;
}

.acct__tile {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  color: var(--neutral-8);
  font-size: var(--size-l);
  transition:
    background-color var(--motion-large-duration) var(--motion-large-easing),
    color var(--motion-large-duration) var(--motion-large-easing);
}

/* Done: the tile keeps its shape, tinted yellow, with a yellow check; the text
   quiets down. */
.acct__check {
  display: none;
  color: var(--tint-strong);
  font-size: var(--size-l);
}

.acct__item.is-done .acct__tile {
  background: var(--tint-soft);
}

.acct__item.is-done .acct__glyph {
  display: none;
}

.acct__item.is-done .acct__check {
  display: block;
}

.acct__item.is-done .acct__name,
.acct__item.is-done .acct__desc {
  color: var(--neutral-6);
}

.acct__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
}

.acct__name {
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

.acct__desc {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .progress,
  .avatar,
  .dash__create,
  .progress__seg,
  .acct__tile {
    transition: none;
  }
}

/* Vaul sheet (shared by the dashboard and the account page). A bottom sheet on
   every screen size: on a wide screen it is a centered column, not a full-width
   bar. The overlay is the About drawer's. */
.vsheet {
  position: fixed;
  z-index: 101;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  width: min(100%, 30rem);
  max-height: 92dvh;
  margin-inline: auto;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  background: var(--neutral-1);
  color: var(--neutral-10);
  outline: 0;
}

.vsheet__handle {
  flex: none;
  width: 2.5rem;
  height: 0.25rem;
  margin: var(--space-s) auto 0;
  border-radius: var(--radius-full);
  background: var(--neutral-5);
}

.vsheet__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  overflow-y: auto;
  padding: var(--space-m) var(--space-l) calc(var(--space-l) + env(safe-area-inset-bottom));
}

.vsheet__body [hidden] {
  display: none;
}

.sheet__text {
  margin: 0;
  color: var(--neutral-8);
}

.sheet__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.sheet__resend {
  margin: calc(var(--space-s) * -1) 0 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.sheet__resend .link {
  margin-left: calc(var(--space-xs) * -1);
}

.sheet__avatar {
  align-self: center;
  width: 6rem;
  height: 6rem;
}

.button--danger {
  --tint: var(--error);
  background: var(--error);
  color: var(--neutral-1);
}

@media (hover: hover) {
  .button--danger:hover {
    background: color-mix(in srgb, var(--error) 90%, var(--neutral-10));
  }
}

/* Account subpages (settings/*.html) reuse the sign-up step layout (.flow). */
.flow__back {
  text-decoration: none;
}

.photo__preview {
  position: relative;
  align-self: center;
  width: min(12rem, 60vw);
  aspect-ratio: 1;
}

.photo__preview .profile__face {
  font-size: var(--size-xxl);
}

.flow__actions .link {
  align-self: center;
}

.link--danger {
  color: var(--error);
}

@media (hover: hover) {
  .link--danger:hover:not(:disabled) {
    color: color-mix(in srgb, var(--error) 85%, var(--neutral-10));
  }
}

/* Desktop: account subpages read like a settings page, not a centered prompt
   (after Sprig, Unify and Meetup on Mobbin): top-aligned, everything on one left
   edge, buttons as wide as their label, the photo next to nothing but its
   actions. Phones keep the sign-up step layout (action pinned to the bottom). */
/* All account pages share one column, so the back arrow sits on the same
   left edge as the content on every page, at every width. */
:root {
  --account-col: 36rem;
}

body[data-page] .flow__bar {
  width: 100%;
  max-width: calc(var(--account-col) + 2 * var(--page-gutter));
  margin-inline: auto;
}

body[data-page] .flow__screen {
  max-width: var(--account-col);
}

@media (min-width: 601px) {
  body[data-page] .flow__screen {
    margin: 0 auto;
    padding-top: var(--space-xl);
  }

  body[data-page] .flow__actions {
    flex-direction: row;
    align-items: center;
    gap: var(--space-m);
  }

  body[data-page] .flow__actions .signin__action {
    width: auto;
  }

  body[data-page] .flow__actions .link {
    align-self: center;
  }

  body[data-page] .photo__preview {
    align-self: flex-start;
    width: 8rem;
  }

  body[data-page] .photo__preview .profile__face {
    font-size: var(--size-xl);
  }
}

/* Confirmation after a change, bottom center, gone after a few seconds. */
.toast {
  position: fixed;
  z-index: 50;
  bottom: calc(var(--space-l) + env(safe-area-inset-bottom));
  left: 50%;
  max-width: calc(100% - 2 * var(--page-gutter));
  margin: 0;
  padding: var(--space-s) var(--space-m);
  border-radius: var(--radius-s);
  background: var(--neutral-9);
  color: var(--neutral-1);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  box-shadow: var(--shadow-m);
  transform: translateX(-50%);
  animation: toast-in var(--motion-duration) var(--motion-easing);
  transition:
    opacity var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.toast.is-leaving {
  opacity: 0;
  transform: translate(-50%, var(--space-xs));
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translate(-50%, var(--space-xs));
  }
}

/* Sign-in method: the current method, shown as a quiet panel. */
.method {
  display: grid;
  grid-template-columns: var(--space-l) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-m);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
}

.method__mark {
  display: grid;
  place-items: center;
}

.method__mark[hidden] {
  display: none;
}

.method__icon {
  width: var(--space-l);
  height: var(--space-l);
  fill: var(--neutral-10);
}

.method__icon--google {
  width: 1.25rem;
  height: 1.25rem;
}

.method__body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.method__name {
  font-weight: var(--weight-ui-medium);
}

.method__value {
  overflow: hidden;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row:disabled {
  cursor: default;
  opacity: 0.6;
}

/* Account page (Settings), after Cash App's account page: a big profile at the
   top, then plain rows with an icon, a label and a chevron. One centered column
   on every screen size. */

.acctpage {
  min-height: 100svh;
  background: var(--neutral-1);
}

.acctpage__bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  max-width: calc(var(--account-col) + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-l) var(--page-gutter);
}

.acctpage__back {
  justify-self: start;
  padding: var(--space-s);
  text-decoration: none;
}

.acctpage__back .icon-svg {
  margin-inline: 0;
}

@media (hover: hover) {
  .button.acctpage__back:hover .icon-svg {
    transform: translateX(-2px);
  }
}

.acctpage__heading {
  margin: 0;
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

.acctpage__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  width: 100%;
  max-width: calc(var(--account-col) + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-m) var(--page-gutter) var(--section-gap);
}

.profile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xxs);
}

.profile__avatar {
  position: relative;
  display: block;
  width: 6rem;
  height: 6rem;
  margin-bottom: var(--space-s);
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  cursor: pointer;
  transition: transform var(--motion-duration) var(--motion-easing);
}

.profile__avatar:active {
  transform: scale(0.97);
}

.profile__avatar:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 3px;
}

.profile__face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--neutral-5);
  color: var(--neutral-10);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-xl);
  line-height: 1;
}

.profile__face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The edit badge sits on the avatar's lower right, with a white ring so it
   reads as its own thing. */
.profile__badge {
  position: absolute;
  right: 0;
  bottom: 0;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-full);
  background: var(--neutral-10);
  color: var(--neutral-1);
  box-shadow: 0 0 0 3px var(--neutral-1);
}

.profile__badge svg {
  width: 1rem;
  height: 1rem;
  fill: currentColor;
}

.profile__name {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  overflow-wrap: anywhere;
  text-wrap: balance;
}

.profile__contact {
  margin: 0;
  color: var(--neutral-8);
  overflow-wrap: anywhere;
}

.acctpage__section {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
}

.rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Rows reach past the column edge by their padding, so the icons line up with
   the name above and the hover fill is roomy. */
.row {
  display: grid;
  grid-template-columns: var(--space-l) minmax(0, 1fr) var(--space-l);
  align-items: center;
  gap: var(--space-m);
  width: calc(100% + 2 * var(--space-s));
  margin-inline: calc(var(--space-s) * -1);
  padding: var(--space-m) var(--space-s);
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .row:hover {
    background: var(--neutral-3);
  }
}

.row:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -2px;
}

.row__icon {
  display: grid;
  place-items: center;
  width: var(--space-l);
  height: var(--space-l);
  color: var(--neutral-10);
  font-size: var(--size-l);
}

.row__icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.row__body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.row__label {
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

.row__value {
  overflow: hidden;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row__chev {
  width: var(--space-l);
  height: var(--space-l);
  fill: var(--neutral-7);
}

.row--danger .row__label,
.row--danger .row__icon {
  color: var(--error);
}

/* Promo rows at the top (what is still missing from the checklist) reuse the
   checklist row; this adds the chevron column. */
.acct__item--go {
  grid-template-columns: 3rem minmax(0, 1fr) var(--space-l);
}

.acct__item--go .row__chev {
  fill: var(--neutral-7);
}

/* Wide screens: the checklist and the account menu drop down from the top-right
   pill instead of rising as a sheet. Same content as the sheets. */
.dash__account {
  position: relative;
}

.dropdown {
  position: absolute;
  z-index: 60;
  top: calc(100% + var(--space-xs));
  right: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  width: 24rem;
  max-width: calc(100vw - 2 * var(--page-gutter));
  /* The title's line height adds air above its letters: 4px less on top. */
  padding: calc(var(--space-l) - var(--space-xxs)) var(--space-l) var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  box-shadow: var(--shadow-m);
  transform-origin: top right;
  animation: dropdown-in 160ms var(--motion-easing);
}

.dropdown--account {
  width: 18rem;
}

@keyframes dropdown-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--space-xxs) * -1)) scale(0.97);
  }
}

@media (prefers-reduced-motion: reduce) {
  .dropdown {
    animation: none;
  }
}

/* Who is signed in, at the top of the account sheet. */
.who {
  display: flex;
  align-items: center;
  gap: var(--space-m);
}

.who__face {
  flex: none;
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--neutral-5);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: 1;
}

.who__face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.who__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Name and contact each stay on one line; a long one ends in an ellipsis. */
.who__name,
.who__contact {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.who__name {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.who__contact {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* ---------- Capsule creation (create.html) ----------
   Duolingo's pacing (a close button, a thin progress bar, one decision per
   screen, the main button always at the bottom) with Cash App's restraint (big
   type, soft fills, no outlines). */

body.creating {
  min-height: 100svh;
}

.cbar {
  position: sticky;
  z-index: 20;
  top: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-m);
  width: 100%;
  max-width: calc(var(--create-col) + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-m) var(--page-gutter);
  background: var(--neutral-1);
}

:root {
  --create-col: 36rem;
}

.cbar__btn {
  padding: var(--space-s);
  text-decoration: none;
}

.cbar__btn .icon-svg {
  margin-inline: 0;
}

.cbar__btn[hidden] {
  /* keep the track in the same place on the first step */
  display: inline-flex;
  visibility: hidden;
}

.cbar__track {
  grid-column: 2;
  height: 0.75rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--neutral-3);
}

.cbar__fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--color-1);
  /* a lighter stripe along the top, like Duolingo's bar */
  box-shadow: inset 0 3px 0 color-mix(in srgb, white 45%, transparent);
  transform: scaleX(0.14);
  transform-origin: left;
  transition: transform var(--motion-large-duration) var(--motion-large-easing);
}

.cbar__saved {
  position: absolute;
  right: var(--page-gutter);
  bottom: calc(var(--space-xxs) * -1);
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  opacity: 0;
  transition: opacity var(--motion-duration) var(--motion-easing);
}

.cbar__saved.is-on {
  opacity: 1;
}

.create {
  width: 100%;
  max-width: calc(var(--create-col) + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-l) var(--page-gutter) 0;
}

.cstep {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  min-height: calc(100svh - 6rem);
  animation: flow-in var(--motion-large-duration) var(--motion-large-easing) both;
}

.cstep[hidden] {
  display: none;
}

.cstep__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.cstep__head[hidden] {
  display: none; /* flex would otherwise win over the hidden attribute */
}

.cstep__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

.cstep__title:focus-visible {
  outline: 0;
}

.cstep__text {
  margin: 0;
  color: var(--neutral-8);
  text-wrap: pretty;
}

.cstep__hint {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  text-wrap: pretty;
}

.cstep__more {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  animation: flow-in var(--motion-large-duration) var(--motion-large-easing) both;
}

.cstep__more[hidden] {
  display: none;
}

.field__optional {
  color: var(--neutral-7);
  font-weight: var(--weight-ui-regular);
}

.field__area {
  resize: vertical;
  min-height: 5rem;
  line-height: var(--line-m);
}

select.field__control {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--neutral-8) 50%), linear-gradient(135deg, var(--neutral-8) 50%, transparent 50%);
  background-position: calc(100% - 20px) 50%, calc(100% - 15px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  padding-right: var(--space-xxl);
}

/* The main button sits at the bottom of the screen, always in reach. */
.cfoot {
  position: sticky;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-s);
  margin-top: auto;
  padding: var(--space-m) 0 calc(var(--space-l) + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--neutral-1) 75%, color-mix(in srgb, var(--neutral-1) 0%, transparent));
}

.cfoot__go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 100%;
  padding-block: var(--space-m);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.cfoot__go[hidden],
.cfoot__alt[hidden] {
  display: none;
}

.cfoot__alt {
  align-self: center;
}

.cfoot__note {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-align: center;
}

.cfoot__note[hidden] {
  display: none;
}

/* Choice tiles: soft fill; the picked one gets a darker grey fill and a stroke. */
.choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-s);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.choices--dates {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 10rem), 1fr));
}

.choice {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-xxs);
  min-height: 4rem;
  padding: var(--space-m) var(--space-l);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.choice input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: inherit;
}

@media (hover: hover) {
  .choice:not(:has(input:checked)):hover {
    background: var(--neutral-4);
  }
}

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

.choice:has(input:checked) {
  background: var(--neutral-8);
  color: var(--neutral-1);
}

.choice:has(input:checked) .choice__sub {
  color: color-mix(in srgb, var(--neutral-1) 70%, transparent);
}

.choice:has(input:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.choice__label {
  font-weight: var(--weight-ui-medium);
}

.choice__sub {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* People: a big number (Cash App), seats, and a chunky slider. */
.count {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-s);
  padding-top: var(--space-l);
}

.count__num {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: clamp(4.5rem, 3rem + 6vw, 7rem);
  line-height: 1;
  letter-spacing: var(--letter-spacing-xxl);
  font-variant-numeric: tabular-nums;
}

.count__unit {
  color: var(--neutral-8);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--size-l);
  line-height: var(--line-l);
}

.seats {
  display: flex;
  justify-content: center;
  gap: var(--space-xs);
}

.seat {
  display: grid;
  place-items: center;
  width: clamp(2.25rem, 1.5rem + 2vw, 3rem);
  aspect-ratio: 1;
  border-radius: var(--radius-full);
  background: var(--neutral-3);
  color: var(--neutral-5);
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.seat svg {
  width: 60%;
  height: 60%;
  fill: currentColor;
}

.seat.is-on {
  background: var(--tint-soft);
  color: var(--neutral-10);
}

.slider {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding-top: var(--space-s);
}

.slider__input {
  --fill: 50%;
  width: 100%;
  height: 2.75rem; /* tall hit area for touch; the track is drawn thinner */
  margin: 0;
  background: transparent;
  appearance: none;
  cursor: pointer;
}

.slider__input::-webkit-slider-runnable-track {
  height: 0.75rem;
  border-radius: var(--radius-full);
  background: linear-gradient(to right, var(--neutral-8) var(--fill), var(--neutral-4) var(--fill));
}

.slider__input::-moz-range-track {
  height: 0.75rem;
  border-radius: var(--radius-full);
  background: linear-gradient(to right, var(--neutral-8) var(--fill), var(--neutral-4) var(--fill));
}

.slider__input::-webkit-slider-thumb {
  width: 2rem;
  height: 2rem;
  margin-top: -0.625rem;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  box-shadow: 0 0 0 1px var(--neutral-4), 0 2px 6px color-mix(in srgb, var(--neutral-10) 18%, transparent);
  appearance: none;
  transition: transform var(--motion-duration) var(--motion-easing);
}

.slider__input::-moz-range-thumb {
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  box-shadow: 0 0 0 1px var(--neutral-4), 0 2px 6px color-mix(in srgb, var(--neutral-10) 18%, transparent);
}

.slider__input:active::-webkit-slider-thumb {
  transform: scale(1.1);
}

.slider__input:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 4px;
  border-radius: var(--radius-s);
}

.slider__ends {
  display: flex;
  justify-content: space-between;
  color: var(--neutral-7);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
}

/* Years until it opens: the svsd theme's Slider (Base UI). Label, readout, then a
   chunky track (control size xl) whose fill and thumb have the theme's small
   radius. Five stops only, each with its number under it. The fill is a soft warm
   gray, because yellow is for the buttons. */
.years {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  min-width: 0;
}

/* The readout: the years, then the word for how it will feel in a soft chip.
   Two shapes side by side, so they share a center line (not a baseline). */
/* The head: the readout on the left, the bottle on the right edge (the track's
   right edge), both on one center line. */
.years__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  margin-bottom: var(--space-xs);
}

.years__read {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-s);
  min-width: 0;
}

/* The wine bottle (src/years-slider.jsx, Wine): its own palette, like the
   chest on the friend's side. With the years it gets more special, not older:
   the wine goes from a clear warm rose-red to a rich jewel ruby, saturation
   climbing with the years (never dusty or grey, never near-black or brick), its level drops a little (--level, in the
   drawing's units), the label stays bright (white to a warm cream, never a
   yellowed "old paper"), and the neck finishes climb in one warm family:
   cork, pewter, copper, sealing wax, gold. Everything stays warm, matching the
   page's warm neutrals; no cool color anywhere on the bottle. The glass never changes. Premium here means
   cleaner at the top, not busier. */
.wine {
  --glass: #8fb582;
  /* Vibrance climbs with the years: quiet at Fresh, richest at Priceless
     (OKLCH: lightness steps down as chroma steps up). */
  --wine: oklch(0.66 0.15 20);
  --level: 42px;
  --paper: #ffffff;
  flex: none;
  width: 4.75rem;
  height: 7.125rem;
  overflow: visible;
  transition: opacity 200ms ease, filter 200ms ease;
}

/* Even steps: lightness -0.05, chroma +0.02 and the hue a touch toward berry
   each stop, so every year reads as one deliberate step richer. */
.wine--1 { --wine: oklch(0.61 0.17 16); --level: 43.5px; --paper: #fffdf9; }
.wine--2 { --wine: oklch(0.56 0.19 12); --level: 45px;   --paper: #fffaf2; }
.wine--3 { --wine: oklch(0.51 0.21 8);  --level: 47px;   --paper: #fff8ec; }
.wine--4 { --wine: oklch(0.46 0.23 4);  --level: 49px;   --paper: #fff6e6; }

.wine.is-unset {
  opacity: 0.45;
  filter: grayscale(1);
}

/* It grows a little taller with the years (--size, 92% at 1 year to 106% at
   10, from its base so it stands on the same spot); its shape changes too,
   drawn in years-slider.jsx (SHAPES). A transition, so a fast drag just
   retargets it; a touch of overshoot as it settles. */
.wine { --size: 0.92; }
.wine--1 { --size: 0.96; }
.wine--2 { --size: 1; }
.wine--3 { --size: 1.03; }
.wine--4 { --size: 1.06; }

.wine__size {
  transform: scale(var(--size));
  transform-box: view-box;
  transform-origin: 40px 115px;
  transition: transform 520ms cubic-bezier(0.34, 1.3, 0.64, 1);
}

.wine__bottle {
  transform-box: fill-box;
  transform-origin: 50% 100%; /* it rocks on its base (the spring sets the angle) */
  will-change: transform;
}

.wine__glass { fill: var(--glass); }

/* The fill line moves with the level; the wine turns around the middle of its
   own surface, so it can stay level while the bottle rocks. */
.wine__liquid {
  transform: translateY(var(--level));
  transition: transform 500ms cubic-bezier(0.65, 0, 0.35, 1);
}

/* The slosh (set every frame by the spring in years-slider.jsx) turns the
   wine around the middle of its surface. */
.wine__slosh {
  transform-box: view-box;
  transform-origin: 40px 0;
}

/* Seen through green glass: a whisper of the green, so it stays juicy. */
.wine__wine {
  fill: color-mix(in srgb, var(--wine) 96%, #1f3a1c);
  transition: fill 400ms ease;
}

.wine__surface {
  fill: color-mix(in srgb, var(--wine) 55%, white);
  transition: fill 400ms ease;
}

.wine__shade { fill: #000000; opacity: 0.22; }

.wine__rim,
.wine__shine,
.wine__base {
  fill: none;
  stroke-linecap: round;
}

.wine__rim { stroke: #ffffff; stroke-width: 0.9; opacity: 0.28; }
.wine__shine { stroke: #ffffff; stroke-width: 3; opacity: 0.5; }
.wine__shine--neck { stroke-width: 2; opacity: 0.4; }
.wine__base { stroke: #000000; stroke-width: 2; opacity: 0.25; }

.wine__ground { fill: var(--neutral-3); }
.wine__contact { fill: var(--neutral-6); opacity: 0.35; }
.wine__cork { fill: #d9a066; }

.wine__label {
  fill: var(--paper);
  transition: fill 400ms ease;
}

.wine__ink { fill: #dccfb3; }

.wine__year {
  fill: #5c4a32;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: 8.2px; /* "2026" stays clear of the gold frame, with room each side */
  letter-spacing: -0.02em;
}

/* Priceless (10 years): the year in gold script, like a hand-lettered fine
   label. System fonts only (Snell Roundhand on Apple, then Apple Chancery,
   Segoe Script on Windows, then any cursive), so nothing extra loads. */
.wine--4 .wine__year {
  fill: #6e4b10; /* deep gold-brown: dark enough to read on the cream label (about 7:1) */
  font-family: "Snell Roundhand", "Apple Chancery", "Segoe Script", cursive;
  font-weight: 700;
  font-size: 9px; /* script runs wide: this keeps it clear of the gold frame */
  letter-spacing: 0;
}

/* Its rule under the year turns gold too, so the label is one metal. */
.wine.wine--4 rect.wine__red {
  fill: var(--wine-gold-dark, #cf9a25);
}

/* Aged's foil: warm pewter, clearly apart from the red wine under it (the
   class names are the drawing's). The rule under the year (also .wine__red,
   a rect) takes the wine's own color instead, so the label follows the wine. */
.wine path.wine__red { fill: oklch(0.76 0.02 75); }
.wine__red-dark { fill: oklch(0.64 0.025 70); }
.wine rect.wine__red { fill: var(--wine); transition: fill 400ms ease; }
.wine__gold { fill: #f5c64a; }
.wine__gold-light { fill: #ffe3a0; }
.wine__gold-dark { fill: #cf9a25; }
/* Rare's sealing wax: an orange-leaning red, so it parts from the berry wine. */
.wine__wax { fill: oklch(0.56 0.19 27); }
/* Vintage's foil: copper with a gold band, warm like the rest, clear against
   the green glass and a white page (the class names are the drawing's). */
.wine__black { fill: oklch(0.63 0.11 48); }
.wine__black-dark { fill: oklch(0.53 0.1 44); }
.wine__black-shine { fill: #ffffff; opacity: 0.35; }
.wine__wax-shine { fill: #ffffff; opacity: 0.3; }
.wine__wax-shade { fill: #000000; opacity: 0.2; }
.wine__glint { fill: #ffffff; }

/* Priceless is the cleanest: gold foil alone on the neck (the wax drips from
   Rare step aside), and three gold sparkles instead of nine bits of glitter. */
.wine--4 .wine__wax,
.wine--4 .wine__wax-shade,
.wine--4 .wine__wax-shine,
.wine circle.wine__glitter,
.wine path.wine__glitter--light {
  display: none;
}

.wine__edge {
  fill: none;
  stroke: #d9a43a;
  stroke-width: 0.9;
}

/* Vintage's neck collar: paper like the label (it ages with it), gold edges. */
.wine__collar {
  fill: var(--paper);
  transition: fill 400ms ease;
}

.wine__collar-edge {
  fill: none;
  stroke: #d9a43a;
  stroke-width: 0.8;
}

/* Dust settles on the top surfaces: along both shoulders, and later the top. */
.wine__dust {
  fill: none;
  stroke: #d6c9ad;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 0.3 1.7 0.2 2.6; /* specks, not a line, so it doesn't read as shine */
  opacity: 0.85;
}

.wine__dust-top { fill: #d6c9ad; opacity: 0.9; }

/* The lifting corner: the underside shows, with a shadow beneath. */
.wine__curl { fill: #d8c391; }
.wine__curl-shadow { fill: #000000; opacity: 0.18; }

/* A detail arriving pops in from 60% with a touch of overshoot, one after
   another (--i). Leaving is quicker and plain: fast where the system responds. */
.wine__part {
  opacity: 0;
  transform: scale(0.6);
  transform-box: fill-box;
  transform-origin: center;
  transition:
    opacity 140ms ease-out,
    transform 140ms ease-out;
}

.wine__part.is-on {
  opacity: 1;
  transform: none;
  transition:
    opacity 200ms cubic-bezier(0.23, 1, 0.32, 1) calc(var(--i) * 60ms),
    transform 360ms cubic-bezier(0.34, 1.56, 0.64, 1) calc(var(--i) * 60ms);
}

/* Priceless: glitter around the bottle. Each piece twinkles slowly on its own
   beat (--i), so the shimmer never pulses all at once. Only at 10 years. */
.wine__glitter--gold { fill: #f0b63c; }
.wine__glitter--light { fill: #ffd97a; }

.wine__glitter {
  transform-box: fill-box;
  transform-origin: center;
}

.wine__part.is-on .wine__glitter {
  animation: wine-twinkle 2.4s ease-in-out calc(500ms + var(--i) * 370ms) infinite;
}

@keyframes wine-twinkle {
  0%,
  100% {
    transform: none;
    opacity: 1;
  }

  50% {
    transform: scale(0.55) rotate(25deg);
    opacity: 0.45;
  }
}

/* Priceless: the glint flashes once as it arrives, then rests. */
.wine__glint {
  transform-box: fill-box;
  transform-origin: center;
}

.wine__part.is-on .wine__glint {
  animation: wine-glint 700ms ease-in-out 320ms;
}

@keyframes wine-glint {
  50% {
    transform: scale(1.35) rotate(45deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .wine__part,
  .wine__part.is-on {
    transform: none;
    transition: opacity 200ms ease;
  }

  .wine__liquid,
  .wine__size {
    transition: none;
  }

  .wine__part.is-on .wine__glint,
  .wine__part.is-on .wine__glitter {
    animation: none;
  }
}

/* The word rolls inside the chip (it clips), every word stacked in one cell.
   The hidden sizer is the longest word, so the chip's width never moves. */
.years__age {
  display: inline-grid;
  justify-items: center;
  overflow: hidden;
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-xs);
  background: var(--tint-soft);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  white-space: nowrap;
}

@supports (corner-shape: squircle) {
  .years__age {
    border-radius: var(--radius-s);
    corner-shape: squircle;
  }
}

.years__age > * {
  grid-area: 1 / 1;
}

.years__age-size {
  visibility: hidden;
}

/* In: up from below (or down from above going back), a little blur blending
   the two words, ease-out so it lands at once. Out: faster, the other way.
   Both under 300ms, since the slider is dragged across quickly. */
.years__age-word.is-in {
  animation: age-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

.years__age-word.is-out {
  animation: age-out 160ms cubic-bezier(0.23, 1, 0.32, 1) forwards;
}

@keyframes age-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--dir) * 70%));
    filter: blur(3px);
  }
}

@keyframes age-out {
  to {
    opacity: 0;
    transform: translateY(calc(var(--dir) * -70%));
    filter: blur(3px);
  }
}

/* Reduced motion: no movement, just a quick crossfade. */
@media (prefers-reduced-motion: reduce) {
  .years__age-word.is-in {
    animation-name: age-fade-in;
  }

  .years__age-word.is-out {
    animation-name: age-fade-out;
  }

  @keyframes age-fade-in {
    from {
      opacity: 0;
    }
  }

  @keyframes age-fade-out {
    to {
      opacity: 0;
    }
  }
}

.years__value {
  display: block;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-section);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-l);
  font-variant-numeric: tabular-nums;
}

.years.is-unset .years__value {
  color: var(--neutral-6);
}

.years__control {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 2rem; /* room for the thumb sticking out */
  touch-action: none;
  cursor: pointer;
}

.years__track {
  position: relative;
  width: 100%;
  height: calc(var(--size-xl) / 2);
  border-radius: var(--radius-xs);
  background: var(--neutral-3);
}

.years__indicator {
  border-radius: var(--radius-xs);
  background: var(--neutral-5);
}

/* The thumb is a square squircle, not squished: a little bigger than the track,
   so it sticks out above and below it. White with a soft edge. */
.years__thumb {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 0.625rem;
  background: var(--neutral-1);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--neutral-10) 8%, transparent),
    0 2px 6px color-mix(in srgb, var(--neutral-10) 16%, transparent);
  outline: 0;
  transition: transform 120ms var(--motion-easing);
}

@supports (corner-shape: squircle) {
  .years__track,
  .years__indicator,
  .years__thumb {
    corner-shape: squircle;
  }
}

.years__thumb:active {
  transform: scale(0.96);
}

.years__thumb:has(:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.years__stops {
  position: relative;
  height: var(--line-s);
}

.years__stops button {
  position: absolute;
  top: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--neutral-7);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transform: translateX(-50%);
  transition: color var(--motion-duration) var(--motion-easing);
}

.years__stops button.is-on {
  color: var(--neutral-8);
}

/* The stop you're on reads as the answer: darkest, and a step heavier. */
.years__stops button.is-picked {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-heavy);
}

/* The date step has two parts, how long and what that means (the date and
   price tiles): a wider gap between them than inside either. */
[data-step="when"] .opens {
  margin-top: var(--space-l);
}

/* Questions. */
.qsum {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-m);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.qsum__count {
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.qsum__time {
  color: var(--neutral-8);
}

.qlist {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.q {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-s) var(--space-xs) var(--space-s) var(--space-s);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
}

.q.is-dragging {
  opacity: 0.5;
}

.q__grip {
  display: grid;
  width: 1.25rem;
  color: var(--neutral-6);
  cursor: grab;
}

.q__grip svg {
  width: 100%;
  fill: currentColor;
}

.q__num {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  font-size: var(--size-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.q__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  min-width: 0;
}

.q__text {
  font-weight: var(--weight-ui-medium);
  text-wrap: pretty;
}

.q__tag {
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.q__tag--custom {
  align-self: flex-start;
  padding: 0 var(--space-xs);
  border-radius: var(--radius-full);
  background: var(--tint-soft);
  color: var(--neutral-9);
  font-weight: var(--weight-ui-medium);
}

.q__tools {
  display: flex;
}

.q__tool {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--neutral-8);
  font-size: var(--size-s);
  cursor: pointer;
}

.q__tool svg {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentColor;
}

.q__tool--up svg {
  transform: rotate(180deg);
}

@media (hover: hover) {
  .q__tool:hover:not(:disabled) {
    background: var(--neutral-4);
    color: var(--neutral-10);
  }
}

.q__tool:disabled {
  color: var(--neutral-5);
  cursor: default;
}

.q__tool:focus-visible {
  outline: 2px solid var(--neutral-9);
}

.qadd {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.qadd__row {
  display: flex;
  gap: var(--space-xs);
}

.qadd__row .field__control {
  flex: 1;
  min-width: 0;
}

.qlib {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  padding-top: var(--space-s);
}

.qlib__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.qlib__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.qlib__items {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.qlib__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 1.5rem;
  align-items: center;
  gap: var(--space-m);
  width: calc(100% + 2 * var(--space-s));
  margin-inline: calc(var(--space-s) * -1);
  padding: var(--space-s);
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

@media (hover: hover) {
  .qlib__item:hover:not(:disabled) {
    background: var(--neutral-3);
  }
}

.qlib__item:disabled {
  color: var(--neutral-6);
  cursor: default;
}

.qlib__item:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -2px;
}

.qlib__mark {
  display: grid;
  place-items: center;
  color: var(--neutral-8);
}

.qlib__mark svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

.qlib__item.is-on .qlib__mark {
  color: var(--tint-strong);
  font-size: var(--size-m);
}

/* Invitation video. */
.rec__prompt {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--tint-soft);
}

.rec__prompt p {
  margin: 0;
  font-weight: var(--weight-ui-medium);
  text-wrap: pretty;
}

.rec__label {
  color: var(--neutral-8);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
}

.rec {
  position: relative;
  display: grid;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-l);
  background: var(--neutral-10);
  color: var(--neutral-1);
}

.rec__video {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rec__video[hidden],
.rec__idle[hidden],
.rec__count[hidden],
.rec__badge[hidden] {
  display: none;
}

/* The live preview is mirrored, like a mirror; the recording is shown as it was filmed. */
.rec__video--live {
  transform: scaleX(-1);
}

.rec__video--play {
  transform: none;
  cursor: pointer;
}

.rec__idle {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-m);
  padding: var(--space-l);
  background: var(--neutral-9);
  text-align: center;
}

.rec__idle p {
  margin: 0;
  max-width: 22em;
  color: color-mix(in srgb, var(--neutral-1) 80%, transparent);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.rec__count {
  grid-area: 1 / 1;
  place-self: center;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: 6rem;
  line-height: 1;
  text-shadow: 0 2px 12px color-mix(in srgb, var(--neutral-10) 50%, transparent);
}

.rec__badge {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin: var(--space-m);
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.rec__badge i {
  width: var(--space-xs);
  height: var(--space-xs);
  border-radius: var(--radius-full);
  background: var(--error);
  animation: caret-blink 1.1s step-end infinite;
}

.rec__controls {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 4.5rem;
}

.rec__controls [hidden] {
  display: none;
}

/* The shutter: a white ring with a red center, like a camera app. */
.rec__shutter {
  position: relative;
  width: 4.5rem;
  height: 4.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  box-shadow: inset 0 0 0 4px var(--neutral-10), 0 0 0 1px var(--neutral-4);
  cursor: pointer;
  transition: transform var(--motion-duration) var(--motion-easing);
}

.rec__shutter::after {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: var(--radius-full);
  background: var(--error);
  transition:
    inset var(--motion-duration) var(--motion-easing),
    border-radius var(--motion-duration) var(--motion-easing);
}

.rec__shutter.is-recording::after {
  inset: 22px;
  border-radius: var(--radius-xs);
}

.rec__shutter:active {
  transform: scale(0.95);
}

.rec__shutter:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 3px;
}

/* The invitation video step (setup.html#invite): keep the recorder as the one
   visual focus. Its preflight information begins inside the frame, then remains
   available from the title row. */
.create:has(> .cstep--split:not([hidden])) {
  max-width: calc(var(--page-max) + 2 * var(--page-gutter));
}

.cstep--split {
  justify-content: center;
}

.vstage {
  width: 100%;
}

.vmain {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  width: 100%;
  max-width: 58rem;
  margin-inline: auto;
  min-width: 0;
}

.vmain__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-m);
}

.vinstructions-open {
  align-self: center;
  padding: var(--space-xs) var(--space-s);
}

.vinstructions-open[hidden] {
  display: none;
}

/* A slightly taller frame gives the inline instructions room to breathe before
   it becomes the camera. */
@media (min-width: 601px) {
  .vrec {
    aspect-ratio: 16 / 10;
  }
}

@media (max-width: 600px) {
  .vmain__head {
    gap: var(--space-s);
  }

  .vinstructions-open {
    padding-inline: var(--space-s);
  }
}

/* Over the camera while recording: the time (top left) and a bar filling over
   the minute (bottom). */
/* Hearts, like lives in a game: red for each take left, grey once one is spent. */
.vrec__hearts {
  display: inline-flex;
  gap: var(--space-xxs);
  margin-inline-end: var(--space-xs);
  vertical-align: -0.2em;
}

.vrec__hearts .icon {
  color: var(--error);
  font-size: 1.25rem;
  transition:
    color 200ms ease-out,
    transform 200ms var(--motion-easing);
}

.vrec__hearts .icon.is-lost {
  color: var(--neutral-4);
  transform: scale(0.85);
}

/* A heart's slot: the grey heart stays in it, the breaking halves sit on top. */
.vheart {
  position: relative;
  display: inline-grid;
}

.vheart > .icon {
  grid-area: 1 / 1;
}

/* The two halves of a breaking heart, cut along a jagged crack. Each turns
   from the bottom of the crack, so they hinge apart before they fall. */
.vrec__hearts .vheart__half {
  color: var(--error);
  pointer-events: none;
  transform-origin: 50% 90%;
  transition: none;
}

.vheart__half--left {
  clip-path: polygon(0 0, 54% 0, 44% 32%, 57% 55%, 46% 78%, 50% 100%, 0 100%);
}

.vheart__half--right {
  clip-path: polygon(54% 0, 100% 0, 100% 100%, 50% 100%, 46% 78%, 57% 55%, 44% 32%);
}

.vrec__time {
  z-index: 1;
}

/* The voice meter and pickers, bottom left on the camera (the friend's side's
   chips, .rxchip / .rxdev). The time is top left, so both marks share the
   camera's left edge at the same 16px inset. */
.vrec__dock {
  position: relative;
  z-index: 1;
}

/* One cell, exactly the frame's size. Without it the cell takes the webcam's
   own shape (often 4:3, taller than the 16:10 frame) and whatever sits on the
   bottom edge (the time bar, the meter, the pickers) is cut off. */
.rec.vrec {
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
}

.vrec__dock:not(:has(> :not([hidden]))) {
  display: none;
}

.vrec .rxdevices[hidden] {
  display: none;
}

.vrec__bar {
  grid-area: 1 / 1;
  align-self: end;
  z-index: 1;
  height: 4px;
  background: color-mix(in srgb, var(--neutral-1) 25%, transparent);
}

.vrec__bar[hidden] {
  display: none;
}

.vrec__bar span {
  display: block;
  height: 100%;
  background: var(--error);
  transform: scaleX(0);
  transform-origin: left;
}

/* Camera off: light and friendly (white to grey), not a dark box. */
.vrec .vrec__idle {
  gap: var(--space-s);
  background: var(--neutral-3);
  color: var(--neutral-10);
}

.vrec .vrec__idle p {
  color: var(--neutral-8);
}

.vrec .vrec__idle .vrec__idle-title {
  margin-top: var(--space-xs);
  color: var(--neutral-10);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.3;
}

.vrec .vrec__idle .button {
  margin-top: var(--space-s);
}

.vrec__cam {
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  border-radius: var(--radius-m);
  background: var(--neutral-1);
  color: var(--neutral-10);
  font-size: 2rem;
  box-shadow: var(--shadow-m);
}

@supports (corner-shape: squircle) {
  .vrec__cam {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

/* 3, 2, 1: the preview dims, "Recording in" over a big number. */
.vrec__count {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  text-align: center;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  background: color-mix(in srgb, var(--neutral-10) 40%, transparent);
  color: var(--neutral-1);
}

.vrec__count[hidden] {
  display: none;
}

.vrec__count-label {
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.vrec__count-num {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: 6rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* The take ends: a soft white flash over the last frame, which then dims and
   blurs behind a small wave loader, "That's a wrap" and what's happening. */
.vrec__saving {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  padding: var(--space-l);
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  color: white;
  text-align: center;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  animation: vrec-flash 600ms cubic-bezier(0.23, 1, 0.32, 1);
}

.vrec__saving[hidden] {
  display: none;
}

@keyframes vrec-flash {
  from {
    background-color: color-mix(in srgb, white 70%, transparent);
    -webkit-backdrop-filter: blur(0);
    backdrop-filter: blur(0);
  }
}

.vrec__saving > :not(.vloader) {
  animation: vrec-saving-in 400ms 120ms cubic-bezier(0.23, 1, 0.32, 1) backwards;
}

.vrec__saving-title {
  margin: var(--space-xs) 0 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.3;
}

.vrec__saving-text {
  margin: 0;
  color: color-mix(in srgb, white 80%, transparent);
  font-size: var(--size-s);
  line-height: var(--line-s);
  animation-delay: 220ms;
}

@keyframes vrec-saving-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* Saving: a line that morphs between a circle and an infinity loop. */
/* Trace (loading-dev): the line laps the square once every 1.2s, easing in
   and out of each lap. Perimeter of the square: 4 × 9.5 + 2π × 4 ≈ 63.13. */
.vloader {
  width: 96px;
  height: 96px;
  color: white;
}

.vloader__run {
  animation: vloader-trace 1200ms ease-in-out infinite;
}

@keyframes vloader-trace {
  to {
    stroke-dashoffset: -63.13;
  }
}

@media (prefers-reduced-motion: reduce) {
  .vloader__run {
    animation: none;
  }
}

/* Voice meter, bottom left on the recording row: five bars that rise with your
   voice, in one flat gray. */
.vmeter {
  display: flex;
  flex: none;
  align-items: center; /* every bar grows from the same middle line */
  gap: 4px;
  width: 3rem;
  height: 2rem;
}

.vmeter[hidden] {
  display: none;
}

.vmeter i {
  flex: 1;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--neutral-6);
  transform: scaleY(0.16);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .vrec__saving,
  .vrec__saving > :not(.vloader) {
    animation: none;
  }
}

/* Play button over the recorded take. */
.vrec__play {
  position: absolute;
  inset: 50% auto auto 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 4.5rem;
  height: 4.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: white;
  color: var(--neutral-9);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--neutral-10) 8%, transparent),
    0 2px 4px color-mix(in srgb, var(--neutral-10) 18%, transparent),
    0 8px 20px color-mix(in srgb, var(--neutral-10) 22%, transparent);
  cursor: pointer;
  transform: translate(-50%, -50%);
  transition: transform 160ms var(--ease-out, ease-out);
}

/* Hidden by fading and settling back a little, not by vanishing. */
.vrec__play {
  transition: opacity 160ms ease-out, transform 160ms cubic-bezier(0.23, 1, 0.32, 1), visibility 0s;
}

.vrec__play[hidden] {
  display: grid;
  visibility: hidden;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.92);
  pointer-events: none;
  transition-duration: 120ms, 120ms, 0s;
  transition-delay: 0s, 0s, 120ms;
}

.vrec__play:active {
  transform: translate(-50%, -50%) scale(0.97);
}

.vrec__play .icon {
  font-size: 2.5rem;
}

/* Our player bar over the bottom of the take (after Paramount+ and Netflix): the
   scrubber with the times at its ends, then play in the middle, volume and full
   screen on the right. It fades away while the take plays. */
.vscrub {
  position: absolute;
  inset: auto 0 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding: var(--space-xxl) var(--space-m) var(--space-s);
  background: linear-gradient(to top, color-mix(in srgb, var(--neutral-10) 75%, transparent), transparent);
  color: white;
  transition: opacity 200ms ease-out;
}

.vscrub[hidden] {
  display: none;
}

.vrec.is-idle .vscrub {
  opacity: 0;
  pointer-events: none;
}

.vrec.is-idle {
  cursor: none;
}

.vscrub__line,
.vscrub__row {
  display: flex;
  align-items: center;
  gap: var(--space-s);
}

.vscrub__row {
  justify-content: space-between;
}

.vscrub__side {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-xs);
}

.vscrub__vol {
  display: flex;
  align-items: center;
}

.vscrub__toggle,
.vscrub__btn {
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  cursor: pointer;
}

.vscrub__toggle {
  width: 2.5rem;
  height: 2.5rem;
}

.vscrub__btn {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-full);
  background: transparent;
  color: white;
}

@media (hover: hover) {
  .vscrub__btn:hover {
    background: color-mix(in srgb, white 18%, transparent);
  }
}

.vscrub__toggle:active,
.vscrub__btn:active {
  transform: scale(0.94);
}

.vscrub__btn .icon {
  font-size: 1.75rem;
}

.vscrub__pause,
.vscrub__toggle.is-playing .vscrub__play,
.vscrub__off,
.vscrub__btn.is-off .vscrub__on {
  display: none;
}

.vscrub__toggle.is-playing .vscrub__pause,
.vscrub__btn.is-off .vscrub__off {
  display: block;
}

.vscrub__time {
  flex: none;
  min-width: 2.5ch;
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px color-mix(in srgb, var(--neutral-10) 50%, transparent);
}

.vscrub__range {
  --p: 0%;
  flex: 1;
  min-width: 0;
  height: 1.5rem;
  margin: 0;
  appearance: none;
  background: transparent;
  cursor: pointer;
}

/* The volume slider opens out beside the speaker on hover or focus (mouse only). */
.vscrub__range--vol {
  display: none;
}

@media (hover: hover) {
  .vscrub__range--vol {
    display: block;
    flex: none;
    width: 0;
    opacity: 0;
    transition: width 200ms ease-out, opacity 200ms ease-out;
  }

  .vscrub__vol:hover .vscrub__range--vol,
  .vscrub__vol:focus-within .vscrub__range--vol {
    width: 5rem;
    margin-right: var(--space-xs);
    opacity: 1;
  }
}

/* The scrubber: a thick white squircle track and thumb. */
.vscrub__range::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 4px;
  background: linear-gradient(to right, white var(--p), color-mix(in srgb, white 30%, transparent) var(--p));
}

.vscrub__range::-moz-range-track {
  height: 8px;
  border-radius: 4px;
  background: color-mix(in srgb, white 30%, transparent);
}

.vscrub__range::-moz-range-progress {
  height: 8px;
  border-radius: 4px;
  background: white;
}

.vscrub__range::-webkit-slider-thumb {
  width: 14px;
  height: 22px;
  margin-top: -7px;
  appearance: none;
  border: 0;
  border-radius: 6px;
  background: white;
  box-shadow: 0 1px 4px color-mix(in srgb, var(--neutral-10) 45%, transparent);
  transition: transform 120ms ease-out;
}

.vscrub__range::-moz-range-thumb {
  width: 14px;
  height: 22px;
  border: 0;
  border-radius: 6px;
  background: white;
}

@supports (corner-shape: squircle) {
  .vscrub__range::-webkit-slider-runnable-track,
  .vscrub__range::-webkit-slider-thumb {
    corner-shape: squircle;
  }
}

.vscrub__range:active::-webkit-slider-thumb {
  transform: scale(1.15);
}

.vscrub__range:focus-visible,
.vscrub__toggle:focus-visible,
.vscrub__btn:focus-visible {
  outline: 2px solid white;
  outline-offset: 2px;
}

/* Full screen: the camera box fills the screen, the take is shown whole. */
.vrec:fullscreen {
  width: 100vw;
  height: 100vh;
  aspect-ratio: auto;
  border-radius: 0;
  background: black;
}

.vrec:fullscreen .rec__video--play {
  object-fit: contain;
}

/* Take label above the camera. */
.vtake {
  margin: 0;
}

/* While recording the invitation, only the camera and its bar stay. The title
   and take label step out of the layout and the header out of the flow, so
   the camera grows into the room they leave (up to what fits the screen's
   height) and sits in the middle. The recorder's View Transition turns that
   into one move: the camera and the buttons glide and grow, and glide back
   and shrink when it stops. Phones keep the camera full width; the room goes
   to centering it. */
body[data-recording] :is(.vmain__head, .vtake) {
  display: none;
}

body[data-recording] .cbar--steps {
  position: fixed;
  inset: 0 0 auto;
  visibility: hidden;
}

body[data-recording] .cstep--split {
  min-height: calc(100svh - var(--space-l));
}

@media (min-width: 601px) {
  body[data-recording] .vmain {
    /* 16:10 camera, its height capped by the screen minus the bar and margins. */
    max-width: max(58rem, min(72rem, calc((100svh - 10rem) * 1.6)));
  }
}

.vrec {
  view-transition-name: vcam;
}

.vbar__actions {
  view-transition-name: vacts;
}

/* On-screen movement, so ease-in-out; a touch longer than the 240ms dissolve
   because it travels further. The camera and buttons keep their own size while
   the box changes (no stretching), and what's inside crossfades. */
::view-transition-group(vcam),
::view-transition-group(vacts) {
  animation-duration: 400ms;
  animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
}

::view-transition-old(vacts),
::view-transition-new(vacts) {
  width: auto;
  height: 100%;
  object-fit: none;
  object-position: right center;
}

/* One bar under the camera: the buttons, on the camera's right edge (the
   meter and pickers live on the camera itself). Phones: buttons full width. */
.vbar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-height: 3.5rem;
}

.vbar__take {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  color: var(--neutral-10);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
}

.vbar__hint {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-wrap: pretty;
}

.vbar__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-s);
}

.vbar .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  padding-inline: var(--space-l);
  white-space: nowrap;
}

.vbar .button[hidden] {
  display: none;
}

/* The red dot and square on the record and stop buttons. */
.vbar__rec,
.vbar__stop {
  width: 0.75rem;
  height: 0.75rem;
  background: var(--error);
}

.vbar__rec {
  border-radius: var(--radius-full);
}

.vbar__stop {
  border-radius: 2px;
}

.vrec__error {
  max-width: 24em;
}

@media (max-width: 600px) {
  /* Portrait on phones, so the instructions remain readable inside the frame. */
  .rec.vrec {
    aspect-ratio: 4 / 5;
  }

  .vbar__actions {
    flex: 1;
  }

  .vbar__actions {
    flex-direction: column-reverse; /* the main button on top */
  }

  .vbar .button {
    width: 100%;
    padding-block: var(--space-m);
  }
}

/* Recording preflight lives inside the video frame, so reading it feels like
   the first camera state rather than a detour. */
.vinstructions-panel {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  overflow: auto;
  padding: var(--space-xl);
  background: var(--neutral-10-transparent);
  color: var(--neutral-10);
  overscroll-behavior: contain;
  -webkit-backdrop-filter: blur(14px) saturate(0.85);
  backdrop-filter: blur(14px) saturate(0.85);
}

.vinstructions-panel[hidden] {
  display: none;
}

.vinstructions-panel:focus {
  outline: 0;
}

.vinstructions-panel[data-mode="required"] {
  background: var(--neutral-3);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.instruction-panel__body {
  display: flex;
  flex: 0 1 36rem;
  flex-direction: column;
  gap: var(--space-l);
  width: 100%;
  max-width: 36rem;
  max-height: 100%;
  margin: auto;
  padding: var(--space-xl);
  overflow: auto;
  box-sizing: border-box;
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  box-shadow: var(--border-shadow-s), var(--shadow-l);
  animation: instruction-panel-in var(--motion-large-duration) var(--motion-large-easing) both;
}

@supports (corner-shape: squircle) {
  .instruction-panel__body {
    corner-shape: squircle;
  }
}

.instruction-panel__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xxs);
}

.instruction-panel__title {
  margin: 0;
  font-family: var(--font-brand);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
  font-weight: var(--weight-brand-heavy);
  text-wrap: balance;
}

.instruction-panel__intro {
  margin: 0;
  color: var(--neutral-8);
  text-wrap: pretty;
}

.vtips {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  margin: 0;
  padding: 0;
  list-style: none;
}

.vtips li {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  align-items: start;
  gap: var(--space-s);
}

.vtips__icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
  color: var(--neutral-8);
  font-size: 1.25rem;
}

@supports (corner-shape: squircle) {
  .vtips__icon {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.vtips__icon svg {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentColor;
}

.vtips__title {
  margin: 0 0 var(--space-xxs);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
  text-wrap: balance;
}

.vtips__text {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-wrap: pretty;
}

.instruction-panel__action.button--secondary {
  --tint: var(--neutral-10);
  align-self: flex-end;
  min-width: 10rem;
  margin-top: auto;
  padding-block: var(--space-m);
  background: var(--neutral-10);
  color: var(--neutral-1);
  box-shadow: var(--shadow-s);
}

.instruction-panel__action[hidden] {
  display: none;
}

@media (hover: hover) {
  .instruction-panel__action.button--secondary:hover:not(:disabled) {
    background: var(--neutral-9);
    box-shadow: var(--shadow-m);
  }
}

@keyframes instruction-panel-in {
  from {
    opacity: 0;
    transform: translateY(0.4rem);
  }
}

@media (max-width: 600px) {
  .vinstructions-panel {
    padding: var(--space-s);
  }

  /* The first, required read: the frame grows to fit it instead of keeping
     the camera's 4:5, so nothing scrolls inside and "Got it, turn on camera"
     is always on screen. With the camera on, the frame is 4:5 again (the
     panel reopened from Show instructions still lays over the camera). */
  .rec.vrec:has(> .vinstructions-panel[data-mode="required"]:not([hidden])) {
    aspect-ratio: auto;
  }

  .vrec > .vinstructions-panel[data-mode="required"] {
    position: relative;
    inset: auto;
    grid-area: 1 / 1;
  }
}

/* Short phones (an iPhone SE): the same read, tighter, so the button still
   fits on screen without scrolling. The title already says what the intro
   line says, so it goes. */
@media (max-width: 600px) and (max-height: 740px) {
  .vinstructions-panel[data-mode="required"] .instruction-panel__intro {
    display: none;
  }

  .vinstructions-panel[data-mode="required"] .instruction-panel__body {
    gap: var(--space-s);
  }

  .vinstructions-panel[data-mode="required"] .vtips {
    gap: var(--space-s);
  }

  .instruction-panel__body {
    gap: var(--space-m);
    padding: var(--space-m);
  }

  .instruction-panel__action.button--secondary {
    width: 100%;
  }

  .vinstructions-panel .vtips {
    gap: var(--space-m);
  }
}

@media (prefers-reduced-motion: reduce) {
  .instruction-panel__body {
    animation: none;
  }
}

/* "Record again" confirmation: a centered dialog on wide screens (Cancel left, the
   destructive action on the right), the same content as a Vaul sheet on phones
   (the destructive action on top, full width). */
.confirm {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.confirm__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
}

.confirm .button {
  width: 100%;
}

.confirm-dialog {
  width: min(26rem, calc(100% - var(--page-gutter) * 2));
  padding: var(--space-l);
  border: 0;
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  color: var(--neutral-10);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--neutral-10) 6%, transparent), 0 16px 48px color-mix(in srgb, var(--neutral-10) 22%, transparent);
}

.confirm-dialog::backdrop {
  background: var(--neutral-10-transparent);
}

/* In and out: it settles in from slightly smaller and fades, and leaves a touch faster. */
.confirm-dialog {
  opacity: 0;
  transform: scale(0.97);
  transition: opacity 120ms ease-out, transform 120ms ease-out, overlay 120ms allow-discrete, display 120ms allow-discrete;
}

.confirm-dialog[open] {
  opacity: 1;
  transform: none;
  transition-duration: 200ms;
  transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}

@starting-style {
  .confirm-dialog[open] {
    opacity: 0;
    transform: scale(0.97);
  }
}

.confirm-dialog::backdrop {
  background: transparent;
  transition: background-color 120ms ease-out, overlay 120ms allow-discrete, display 120ms allow-discrete;
}

.confirm-dialog[open]::backdrop {
  background: var(--neutral-10-transparent);
  transition-duration: 200ms;
}

@starting-style {
  .confirm-dialog[open]::backdrop {
    background: transparent;
  }
}

@media (min-width: 701px) {
  .confirm-dialog .confirm__actions {
    flex-direction: row-reverse; /* the destructive action on the right */
    justify-content: flex-start;
  }

  .confirm-dialog .button {
    width: auto;
    padding-inline: var(--space-l);
  }
}

@media (prefers-reduced-motion: reduce) {
  .confirm-dialog,
  .confirm-dialog::backdrop {
    transform: none;
    transition-duration: 1ms;
  }
}

/* The recorder changing state (View Transitions): one quick dissolve, with a
   strong ease-out so the new state is already there when you look. */
::view-transition-group(*) {
  animation-duration: 240ms;
  animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none;
  }
}

/* People. */
.facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
  list-style: none;
}

.facts li {
  position: relative;
  padding-left: var(--space-l);
  color: var(--neutral-9);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.facts li::before {
  content: "";
  position: absolute;
  top: 0.4em;
  left: 0.25rem;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--radius-full);
  background: var(--tint-strong);
}

.slots {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

.slot {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.slot__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.slot__head [hidden] {
  display: none;
}

.slot__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
}

.slot .field {
  margin-top: 0;
}

.slot__note-toggle,
.slots__add {
  align-self: flex-start;
  margin-left: calc(var(--space-xs) * -1);
}

.slot__note-toggle[hidden],
.slots__add[hidden],
.slot [data-note][hidden] {
  display: none;
}

/* Reveal. */
.reveal__preview {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
  text-wrap: balance;
}

.reveal__preview:empty {
  display: none;
}

#custom-date[hidden] {
  display: none;
}

/* Review. */
.review {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.review__row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-m);
  padding-block: var(--space-m);
}

.review__label {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-m);
}

.review__value {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  min-width: 0;
  margin: 0;
}

.review__value strong {
  font-weight: var(--weight-ui-medium);
  overflow-wrap: anywhere;
}

.review__sub {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  overflow-wrap: anywhere;
}

.review__missing {
  color: var(--error);
}

.review__edit {
  margin: 0;
}

.review__video {
  width: 100%;
  max-width: 16rem;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-s);
  background: var(--neutral-10);
  object-fit: cover;
}

.notice {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--tint-soft);
  color: var(--neutral-10);
  text-decoration: none;
  transition: transform var(--motion-duration) var(--motion-easing);
}

.notice[hidden] {
  display: none;
}

.notice:active {
  transform: scale(0.99);
}

.notice:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.notice__title {
  font-weight: var(--weight-ui-medium);
}

.notice__title::after {
  content: " →";
}

.notice__text {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

@media (max-width: 600px) {
  .rec {
    aspect-ratio: 3 / 4;
  }

  .review__row {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .review__label {
    grid-column: 1 / -1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cstep,
  .cstep__more {
    animation: none;
  }

  .cbar__fill,
  .seat,
  .choice {
    transition: none;
  }
}

/* ---------- Setting up a capsule (setup.html, pay.html) ---------- */

/* Small pill options. The picked one gets a darker grey fill and a stroke. */
.pills-field {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.pills-field legend {
  margin-bottom: var(--space-xs);
  padding: 0;
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: var(--space-xs) var(--space-m);
  border-radius: var(--radius-full);
  background: var(--neutral-3);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.pill > input[type="radio"] {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: inherit;
}

@media (hover: hover) {
  .pill:not(:has(input[type="radio"]:checked)):hover {
    background: var(--neutral-4);
  }
}

.pill:active {
  transform: scale(0.97);
}

/* Picked is one look for every pill on the site: it lifts off the grey row,
   white with black text and a tight shadow hugging its edge (small blur, a
   touch of spread, no stroke), so it reads as a soft rim, not a drop. */
.pill:has(input[type="radio"]:checked),
.pill--button.is-picked {
  background: var(--neutral-1);
  color: var(--neutral-10);
  box-shadow: 0 0 1px 1px #00000014;
}

.pill:has(input[type="radio"]:checked) .pill__input::placeholder {
  color: var(--neutral-7);
}

.pill:has(input[type="radio"]:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* "Something else" becomes a text field in the same spot. */
.pill--other.is-typing {
  padding-block: 0;
  cursor: text;
}

.pill--other.is-typing > input[type="radio"] {
  pointer-events: none;
}

.pill__label[hidden],
.pill__input[hidden] {
  display: none;
}

.pill__input {
  position: relative;
  width: 12rem;
  max-width: 60vw;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  outline: 0;
}

.field__help {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
  text-wrap: pretty;
}

.field__area--tall {
  min-height: 9rem;
}

.field__count {
  margin: 0;
  align-self: flex-end;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-variant-numeric: tabular-nums;
}

.hold-note {
  margin: 0;
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--tint-soft);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.hold-note[hidden],
#custom-field[hidden],
.opens[hidden] {
  display: none;
}

/* When it opens and what it costs: two tiles with the same weight. */
.opens {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-s);
}

.opens__tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding: var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.opens__label {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.opens__value {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-section);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-l);
  font-variant-numeric: tabular-nums;
}

.opens__sub {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* The sentence on the "It's set up" screen. */
.opens__line {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
  letter-spacing: var(--letter-spacing-m);
  text-wrap: balance;
}

.opens__line strong {
  font-weight: var(--weight-brand-heavy);
}

.opens__wait {
  color: var(--neutral-8);
}

@media (max-width: 600px) {
  .opens {
    grid-template-columns: minmax(0, 1fr);
  }
}

.next-up {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.next-up__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.next-up__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  counter-reset: next;
  list-style: none;
}

.next-up__list li {
  position: relative;
  padding-left: var(--space-xl);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  counter-increment: next;
}

.next-up__list li::before {
  content: counter(next);
  position: absolute;
  top: -1px;
  left: 0;
  display: grid;
  place-items: center;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: var(--radius-full);
  background: var(--tint-soft);
  color: var(--neutral-10);
  font-size: var(--size-xs);
  font-weight: var(--weight-ui-medium);
}

.next-up__list strong {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
}

a.cfoot__go {
  text-decoration: none;
}

/* Setup header: Instagram-story bars, one per step, with the step's name under
   them. Back and close sit on the page's edges (where the profile picture is on
   the dashboard); the bars match the content column. */
.cbar--steps {
  grid-template-columns: 1fr minmax(0, var(--create-col)) 1fr;
  max-width: calc(var(--page-max) + 2 * var(--page-gutter));
}

.cbar--steps #back {
  justify-self: start;
}

.cbar--steps #close {
  justify-self: end;
}

.shead {
  position: relative;
  grid-column: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  width: 100%;
}

.shead__name {
  color: var(--neutral-8);
  font-weight: var(--weight-ui-medium);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.sbars {
  display: grid;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column; /* one bar per step, however many there are */
  gap: var(--space-xxs);
  width: 100%;
}

.sbar {
  height: 0.625rem;
  overflow: hidden;
  border-radius: calc(var(--radius-xs) / 2); /* a softly rounded bar, not a pill */
  background: var(--neutral-4);
  /* a slight inner shade, so the empty track reads as a groove */
  box-shadow: inset 0 1px 2px color-mix(in srgb, var(--neutral-10) 8%, transparent);
}

/* The filled part has the primary button's texture, in black: a light line
   along the top edge and a darker one along the bottom. */
.sbar::after {
  content: "";
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--neutral-10);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, white 28%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--neutral-10) 60%, transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--motion-large-duration) var(--motion-large-easing);
}

.sbar.is-on::after {
  transform: scaleX(1);
}

@media (max-width: 600px) {
  .cbar--steps {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
}

/* Name ideas: quiet hints under the field, a step below the purpose pills. */
.ideas {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-xs) var(--space-l);
  margin: var(--space-xs) 0 0;
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.ideas[hidden] {
  display: none;
}

.ideas__label {
  color: var(--neutral-8);
  font-weight: var(--weight-ui-medium);
}

.ideas > span:last-child {
  display: contents;
}

.idea {
  padding: 0;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--neutral-8);
  font: inherit;
  text-decoration: underline dotted;
  text-decoration-color: var(--neutral-5);
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .idea:hover {
    color: var(--neutral-10);
  }
}

.idea:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

#name-blank[hidden] {
  display: none;
}

.suggest {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  padding-top: var(--space-xxs);
}

.suggest[hidden],
#name-field[hidden],
#note-field[hidden] {
  display: none;
}

.pill--button {
  min-height: 2.25rem;
  padding: var(--space-xxs) var(--space-s);
  border: 0;
  color: var(--neutral-9);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.pill--button:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* How it works: a story told as a timeline, one icon per moment. The 7-day
   part is set in yellow so it can't be skimmed past. */
.story {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.story__step {
  position: relative;
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  gap: var(--space-m);
  padding-bottom: var(--space-l);
}

/* The line that joins the icons. */
.story__step:not(:last-child)::before {
  content: "";
  position: absolute;
  top: 3rem;
  bottom: 0;
  left: calc(1.5rem - 1px);
  width: 2px;
  border-radius: var(--radius-full);
  background: var(--neutral-4);
}

.story__step--key:not(:last-child)::before {
  background: var(--color-1);
}

.story__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-full);
  background: var(--neutral-3);
  color: var(--neutral-9);
  font-size: var(--size-l);
}

.story__step--key .story__icon {
  background: var(--color-1);
  color: var(--neutral-10);
}

.story__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding-top: var(--space-xxs);
}

.story__when {
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
  letter-spacing: var(--letter-spacing-xs);
}

.story__step--key .story__when {
  color: var(--tint-strong);
}

.story__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: var(--line-l);
  letter-spacing: var(--letter-spacing-l);
}

.story__text {
  margin: 0;
  color: var(--neutral-8);
  text-wrap: pretty;
}

/* The day picker: Cally (cally on npm), themed through its parts. One soft
   panel; the picked day is a dark warm grey, like the picked markers. */
.opens__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  margin: var(--space-s) 0 0 calc(var(--space-xs) * -1);
}

.opens__links [hidden] {
  display: none;
}

/* Reset to the default day: a small round button in the panel's bottom right. */
.opens__reset {
  position: absolute;
  right: var(--space-m);
  bottom: var(--space-m);
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--neutral-9);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.opens__reset[hidden] {
  display: none;
}

.opens__reset svg {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentColor;
}

@media (hover: hover) {
  .opens__reset:hover {
    background: var(--neutral-4);
  }
}

.opens__reset:active {
  transform: scale(0.94) rotate(-30deg);
}

.opens__reset:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* The calendar drops down under the links, over what's below. */
.day-pop {
  position: absolute;
  z-index: 15;
  top: calc(100% + var(--space-xs));
  left: 0;
  width: min(19rem, calc(100vw - 2 * var(--page-gutter)));
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  box-shadow: var(--shadow-m);
  transform-origin: top left;
  animation: dropdown-in 160ms var(--motion-easing);
}

.day-pop[hidden] {
  display: none;
}

.day-pop .cal {
  background: none;
}

/* Squircle corners where the browser can draw them. */
@supports (corner-shape: squircle) {
  .day-pop,
  .cal,
  .cal__nav {
    corner-shape: squircle;
  }

  .day-pop,
  .cal {
    border-radius: var(--radius-xl);
  }

  .cal__nav {
    border-radius: 50%;
  }

  .cal calendar-month::part(day) {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.cal {
  --cal-cell: 2.5rem; /* one size for day cells and the arrow buttons */
  display: block;
  padding: var(--space-m);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
  --color-accent: var(--neutral-8);
  --color-text-on-accent: var(--neutral-10);
}

/* One spine: the arrows' centers sit on the first and last day columns, the
   month and year on the middle one, all on one horizontal line. */
.cal::part(header) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: calc((100% / 7 - var(--cal-cell)) / 2);
  margin-bottom: var(--space-xs);
}

.cal::part(heading) {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
}

/* The heading: the month big, the year small right under it, tight together.
   The calendar's own month heading above the days is hidden (we show it here). */
.cal__title {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.cal__month {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.15;
}

.cal__year {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.cal calendar-month::part(heading) {
  display: none;
}

.cal__nav {
  display: grid;
  place-items: center;
  width: var(--cal-cell);
  height: var(--cal-cell);
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--neutral-10);
  cursor: pointer;
}

.cal__nav svg {
  width: 1.25rem;
  height: 1.25rem;
  fill: currentColor;
}

.cal::part(button) {
  border: 0;
  background: none;
  padding: 0;
}

.cal::part(button disabled),
.cal::part(disabled) {
  opacity: 0.3;
  cursor: default;
}

.cal calendar-month {
  width: 100%;
}

.cal calendar-month::part(table) {
  width: 100%;
}

.cal calendar-month::part(th) {
  padding-bottom: var(--space-xs);
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
}

.cal calendar-month::part(day) {
  width: var(--cal-cell);
  max-width: 100%;
  aspect-ratio: 1;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--neutral-10);
  font: inherit;
  font-size: var(--size-s);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.cal calendar-month::part(day):hover {
  background: var(--neutral-4);
}

.cal calendar-month::part(selected) {
  background: var(--neutral-8);
  color: var(--neutral-1);
  font-weight: var(--weight-ui-medium);
}

.cal calendar-month::part(disallowed) {
  color: var(--neutral-5);
  cursor: default;
}

.cal calendar-month::part(outside) {
  color: var(--neutral-6);
}

.cal calendar-month::part(day):focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 1px;
}

/* A little tighter on phones: a narrower pop-up and smaller cells. */
@media (max-width: 600px) {
  .day-pop {
    width: min(17rem, calc(100vw - 2 * var(--page-gutter)));
  }

  .cal {
    --cal-cell: 2.25rem;
    padding: var(--space-s);
  }

  .cal__month {
    font-size: var(--size-m);
  }

  .cal calendar-month::part(day) {
    font-size: var(--size-xs);
  }
}

/* The 7 days, drawn: seven day cells and a lock. */
.week {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: var(--space-xxs);
  max-width: 24rem;
  margin-top: var(--space-s);
}

.week__day {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: var(--radius-xs);
  background: var(--tint-soft);
  color: var(--neutral-9);
  font-size: var(--size-xs);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.week__day--lock {
  background: var(--neutral-10);
  color: var(--color-1);
  font-size: var(--size-s);
}

.story__next {
  margin: 0;
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
  color: var(--neutral-9);
}

/* How it works, written like an old manual: an icon, a plain line, a short
   note, one color. */
.manual-steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

.manual-steps li {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--space-m);
  align-items: start;
}

.manual-steps__icon {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background: var(--neutral-3);
  color: var(--neutral-10);
  font-size: var(--size-l);
}

.manual-steps__icon svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

/* Item title: the one size between the page title and body text, shared
   across the setup pages (and the landing page's timeline steps). */
.manual-steps__title {
  margin: 0 0 var(--space-xxs);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
  letter-spacing: var(--letter-spacing-m);
  text-wrap: balance;
}

.manual-steps__text {
  margin: 0;
  color: var(--neutral-8);
  text-wrap: pretty;
}

/* The promise before moving on. */
.commit {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  align-items: start;
  gap: var(--space-s);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--neutral-3);
  font-weight: var(--weight-ui-regular);
  line-height: 1.45;
  text-wrap: pretty;
  cursor: pointer;
}

/* The box (1.75rem) is taller than a line of text (1.45em), so the text steps
   down by half the difference: its first line sits on the box's middle, and a
   second line (phones) wraps below without moving the box. */
.commit > span {
  padding-top: calc((1.75rem - 1.45em) / 2);
}

/* The same marker as the question rows: a thin ring that fills dark warm grey
   with a white check, in place of the browser's own black square. */
.commit input {
  appearance: none;
  width: 1.75rem;
  height: 1.75rem;
  margin: 0;
  border-radius: var(--radius-xs);
  background: var(--neutral-1) center / 1.25rem no-repeat;
  box-shadow: inset 0 0 0 1.5px var(--neutral-5);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing);
}

@supports (corner-shape: squircle) {
  .commit input {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.commit input:checked {
  background-color: var(--neutral-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='white' d='M9.55 17.65 4.6 12.7l1.4-1.4 3.55 3.55 8.45-8.45 1.4 1.4z'/%3E%3C/svg%3E");
  box-shadow: none;
}

.commit input:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Picking the questions: one list, a row per question. A picked row is a soft
   grey fill, and its circle shows the order.
   Each rule has one home: "Write your own" counts its 2, the strip of
   circles pinned at the top counts the 5. */
/* The line under the heading, with the info button at its end. */
.qnote .info {
  display: inline-grid; /* sits at the end of the line, not on its own */
  vertical-align: -0.25em;
}

.qpick-field {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.qpick {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* An airy list: rows have no fill and no edge until they are picked, only room
   around them. "Write your own" is a row like the others, its circle holding a
   plus, and opens into a field in place. */
.qpicker {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.qown[hidden] {
  display: none;
}

.qown__open {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-s);
  width: 100%;
  padding: var(--space-m);
  border: 0;
  border-radius: var(--radius-m);
  background: transparent;
  outline: 0;
  color: var(--neutral-10);
  font: inherit;
  font-weight: var(--weight-ui-regular);
  text-align: left;
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    opacity var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

.qown__open[hidden] {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .qown__open:hover {
    background: var(--neutral-3);
  }
}

.qown__open:active {
  transform: scale(0.99);
}

.qown__open:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.qown__plus {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--neutral-5);
}

.qown__plus svg {
  width: 1.125rem;
  height: 1.125rem;
  fill: var(--neutral-10);
}

@media (hover: hover) and (pointer: fine) {
  .qown__open:hover .qown__plus {
    box-shadow: inset 0 0 0 1.5px var(--neutral-6);
  }
}

.qown__left {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-regular);
  font-variant-numeric: tabular-nums;
}

.qown__form {
  display: flex;
  gap: var(--space-xs);
  animation: flow-in var(--motion-duration) var(--motion-easing) both;
}

.qown__form[hidden] {
  display: none;
}

.qown__form .field__control {
  flex: 1;
  min-width: 0;
  min-height: 3.5rem;
  border-radius: var(--radius-s);
}

.qown__form .button {
  border-radius: var(--radius-s);
}

.qrow {
  position: relative;
  border-radius: var(--radius-m);
  background: transparent;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    opacity var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

.qrow__label {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-m);
  font-weight: var(--weight-ui-regular);
  line-height: 1.45;
  cursor: pointer;
}

/* The real checkbox stays in the page for the keyboard and screen readers. */
.qrow__box {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

.qrow:has(.qrow__box:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* The empty circle, then the order number once picked. Same look as the
   circles in the strip at the top, so the two read as one thing. */
.qrow__mark,
.qslots i,
.qown__plus {
  border-radius: var(--radius-xs);
}

/* A soft squircle, not a circle: a true superellipse where the browser can
   draw one, a rounded square everywhere else. */
@supports (corner-shape: squircle) {
  .qrow__mark,
  .qslots i,
  .qown__plus {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.qrow__mark,
.qslots i {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  box-shadow: inset 0 0 0 1.5px var(--neutral-5);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-s);
  font-style: normal;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing);
}

.qrow__mark {
  background: transparent;
}

/* Delete, on your own questions only: hidden until you point at the row (or tab to
   it). Touch has no hover, so there it is always there, quietly. */
.qrow--own .qrow__label {
  padding-right: calc(var(--space-m) + 2.5rem);
}

.qrow__del {
  position: absolute;
  top: 50%;
  right: var(--space-s);
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--neutral-7);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-50%);
  transition:
    opacity 160ms ease-out,
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) and (pointer: fine) {
  .qrow:hover .qrow__del,
  .qrow:focus-within .qrow__del {
    opacity: 1;
    pointer-events: auto;
  }

  .qrow__del:hover {
    background: var(--neutral-4);
    color: var(--neutral-10);
  }
}

@media (hover: none), (pointer: coarse) {
  .qrow__del {
    opacity: 1;
    pointer-events: auto;
  }
}

.qrow__del:active {
  transform: translateY(-50%) scale(0.92);
}

.qrow__del:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.qrow__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xxs);
  min-width: 0;
  text-wrap: pretty;
}

.qrow__tag {
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
  font-weight: var(--weight-ui-regular);
  text-wrap: pretty;
}

.qrow.is-on {
  background: var(--neutral-3);
}

/* Picked (after Family and Apple Maps): the empty ring fills in with a warm
   dark grey and the number turns white. Greys only, no stroke. */
.qrow.is-on .qrow__mark,
.qslots i.is-on {
  background: var(--neutral-8);
  color: var(--neutral-1);
  box-shadow: none;
}

.qrow.is-locked {
  opacity: 0.45;
}

.qrow.is-locked .qrow__label {
  cursor: not-allowed;
}

@media (hover: hover) and (pointer: fine) {
  .qrow:not(.is-on):not(.is-locked):hover {
    background: var(--neutral-3);
  }
}

.qrow:not(.is-locked):has(.qrow__label:active) {
  transform: scale(0.99);
}

/* The strip: five circles and what's left, pinned just under the header while
   the list scrolls. 1 to 3 are needed (a darker ring), 4 and 5 are optional
   (a lighter ring and number). */
.qbar {
  position: sticky;
  z-index: 2;
  top: var(--cbar-h, 0px);
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding-block: var(--space-s) var(--space-m);
  background: var(--neutral-1);
}

.qbar__text {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-regular);
}

.qslots {
  display: flex;
  flex: none;
  gap: var(--space-xxs);
}

.qslots i {
  color: var(--neutral-7);
}

.qslots i.is-extra:not(.is-on) {
  box-shadow: inset 0 0 0 1.5px var(--neutral-4);
  color: var(--neutral-6);
}

/* A short note just under the strip, in and out. */
.qtoast {
  position: absolute;
  top: 100%;
  left: 0;
  margin: 0;
  padding: var(--space-xs) var(--space-m);
  border-radius: var(--radius-full);
  background: var(--neutral-9);
  color: var(--neutral-1);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  white-space: nowrap;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transform: translateY(calc(-1 * var(--space-xxs)));
  transition:
    opacity var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);
}

.qtoast.is-on {
  opacity: 1;
  transform: none;
}

/* Friends: a dedicated people builder, deliberately unlike the question
   picker. The white composer stays first (and sticky while the roster grows),
   with familiar contact rows collecting underneath. */
.qpick[hidden] {
  display: none;
}

.friends-builder {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.friends-add {
  view-transition-name: fadd;
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
  padding: var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.friends-add__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
}

.friends-add__head > strong {
  font-family: var(--font-brand);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-brand-heavy);
}

.friends-add__count {
  align-self: center;
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--neutral-8);
  font-family: var(--font-data);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-data-medium);
  font-variant-numeric: tabular-nums;
}

.fadd {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-m);
}

.fadd[hidden] {
  display: none;
}

.fadd__fields {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: var(--space-s);
  width: 100%;
}

.fadd .field {
  margin-top: 0;
}

/* Both labels sit in a row as tall as the Email / Phone switch and are centered in
   it, so "Their name" and "Contact" share one middle line and both inputs start
   on the same line. */
.fadd .field > .field__label,
.fcontact__label-row {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
}

.fcontact__label-row {
  justify-content: space-between;
  gap: var(--space-s);
}

.contact-kind {
  display: inline-flex;
  flex: none;
  padding: var(--space-xxs);
  border-radius: var(--radius-full);
  background: var(--neutral-1);
}

.contact-kind button {
  min-height: 1.75rem;
  padding: 0 var(--space-s);
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--neutral-8);
  font: inherit;
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing);
}

.contact-kind button[aria-pressed="true"] {
  background: var(--neutral-8);
  color: var(--neutral-1);
  box-shadow: var(--shadow-s);
}

.contact-kind button:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.fadd .field__control {
  min-height: 3.5rem;
  border-radius: var(--radius-s);
  background: var(--neutral-1);
}

.fadd .country {
  border-radius: var(--radius-s);
  background: var(--neutral-1);
}

/* Each person's keepsake on their row is a button: tap it to swap. A soft
   squircle that gives a little when pressed and tilts its keepsake on hover
   (and while its picker is open). */
button.friend-card__avatar {
  padding: 0;
  border: 0;
  cursor: pointer;
  transition:
    transform 160ms ease-out,
    background-color 150ms ease;
}

button.friend-card__avatar .keepsake {
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1);
}

button.friend-card__avatar:active {
  transform: scale(0.94);
}

button.friend-card__avatar:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

button.friend-card__avatar[aria-expanded="true"] .keepsake {
  transform: rotate(-6deg) scale(1.06);
}

@media (hover: hover) and (pointer: fine) {
  button.friend-card__avatar:hover .keepsake {
    transform: rotate(-6deg) scale(1.06);
  }
}

/* The picker: a small white card next to the keepsake tapped, all seven in a
   row (4 and 3 on phones), each with one word under it: its name, or the name
   of who has it (picking that one swaps). It grows from what was tapped. */
.kpop {
  position: fixed;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-s);
  border-radius: var(--radius-m);
  background: var(--neutral-1);
  box-shadow: var(--shadow-m), 0 0 0 1px var(--neutral-4);
  animation: kpop-in 170ms cubic-bezier(0.23, 1, 0.32, 1);
}

.kpop[hidden] {
  display: none;
}

@keyframes kpop-in {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
}

/* Title: who it's for. Note (only when some are taken): what picking one does. */
.kpop__head {
  /* The icons set the picker's width; a long name never stretches it. It
     takes the width that's there (width 0, at least 100%) and ends in "…". */
  width: 0;
  min-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0;
  padding: 0 var(--space-xxs);
  color: var(--neutral-10);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.kpop__note {
  width: 0;
  min-width: 100%; /* same: the note wraps inside the icons' width */
  margin: 0;
  padding: var(--space-xs) var(--space-xxs) 0;
  border-top: 1px solid var(--neutral-3);
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.kpop__grid {
  align-items: start; /* the ones with an owner line are taller; all start level */
  display: grid;
  grid-template-columns: repeat(7, 3.25rem);
  gap: 2px;
}

.kpop__item {
  display: grid;
  justify-items: center;
  gap: 2px;
  min-width: 0;
  padding: var(--space-xs) 2px var(--space-xxs);
  border: 0;
  border-radius: var(--radius-s);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition:
    background-color 150ms ease,
    transform 160ms ease-out;
}

.kpop__item .keepsake {
  width: 2.5rem;
  height: 2.5rem;
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* The one they have: soft grey behind it (greys only). */
.kpop__item.is-on {
  background: var(--neutral-3);
}

/* Under each icon, the first name of whoever has it (an empty line when it's
   free, so every icon sits at the same height). Nothing is faded. */
.kpop__owner {
  display: block;
  min-height: var(--line-xxs);
  max-width: 100%;
  overflow: hidden;
  color: var(--neutral-8);
  font-size: var(--size-xxs);
  line-height: var(--line-xxs);
  font-weight: var(--weight-ui-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The person you're choosing for: their icon shaded, their name dark and bold. */
.kpop__item.is-on .kpop__owner {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-heavy);
}

.kpop__item:active {
  transform: scale(0.95);
}

.kpop__item:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -2px;
}

@media (hover: hover) and (pointer: fine) {
  .kpop__item:not(.is-on):hover {
    background: var(--neutral-2);
  }

  .kpop__item:not(.is-on):hover .keepsake {
    transform: rotate(-6deg);
  }
}

@media (max-width: 600px) {
  .kpop__grid {
    grid-template-columns: repeat(4, 3.5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .kpop {
    animation-name: kpop-fade;
  }

  @keyframes kpop-fade {
    from {
      opacity: 0;
    }
  }
}

.fadd__submit {
  min-width: 6rem;
}

.fadd__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-s);
}

/* The add button is black, so it can't be mistaken for one of the white fields. */
.fadd__submit.button--secondary {
  background: var(--neutral-10);
  color: var(--neutral-1);
}

@media (hover: hover) and (pointer: fine) {
  .fadd__submit.button--secondary:hover:not(:disabled) {
    background: var(--neutral-9);
  }
}

.friends-add__full {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: var(--neutral-1);
  color: var(--neutral-8);
  font-weight: var(--weight-ui-regular);
  text-wrap: pretty;
}

.friends-add__full[hidden] {
  display: none;
}

.friends-add__full .icon {
  flex: none;
  color: var(--success);
}

/* The people list uses the same edges as the add card above it: the cards line up
   with the card, and the heading's text lines up with the avatars. */
.friends-roster {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  padding: 0;
}

.friends-roster[hidden] {
  display: none;
}

.friends-roster__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-m);
  padding-inline: var(--space-m);
}

/* "Your people" with the one hint under it: how keepsakes change. */
.friends-roster__title {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.friends-roster__hint {
  margin: 0;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.friends-roster__head h2 {
  margin: 0;
  font-family: var(--font-brand);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-brand-heavy);
}

.friends-roster__head span {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
}

.friends-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.friend-card {
  position: relative;
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-m);
  border-radius: var(--radius-m);
  background: transparent;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

/* Keepsakes (keepsakes.js): each person's little illustration, filling their
   avatar square with a bit of room around it. */
.keepsake {
  display: block;
  width: 90%;
  height: 90%;
}

.friend-card__avatar {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-s);
  background: var(--neutral-3); /* light, so every keepsake's edge reads */
  color: var(--neutral-9);
  font-family: var(--font-brand);
  font-size: var(--size-s);
  line-height: 1;
  font-weight: var(--weight-brand-heavy);
  text-transform: uppercase;
}

@supports (corner-shape: squircle) {
  .friend-card__avatar {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.friend-card__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.friend-card__name {
  font-weight: var(--weight-ui-regular);
  overflow-wrap: anywhere;
}

.friend-card__contact {
  overflow: hidden;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.friend-card__actions {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
}

.friend-card__edit {
  min-height: 2.25rem;
  padding: var(--space-xxs) var(--space-s);
  border: 0;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--neutral-8);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

.friend-card__remove {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--neutral-8);
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

@media (hover: hover) and (pointer: fine) {
  .friend-card:hover {
    background: var(--neutral-3);
  }

  .friend-card__remove:hover,
  .friend-card__edit:hover {
    background: var(--neutral-4);
    color: var(--neutral-10);
  }
}

.friend-card__edit:active,
.friend-card__remove:active {
  transform: scale(0.92);
}

.friend-card__edit:focus-visible,
.friend-card__remove:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

@media (max-width: 600px) {
  .friends-add {
    padding: var(--space-m);
  }

  .fadd__fields {
    grid-template-columns: 1fr;
  }

  .fadd__submit {
    width: 100%;
  }

  .fadd__actions {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .qrow,
  .qown__open,
  .qrow__mark,
  .qslots i,
  .qtoast {
    transition: none;
  }

  .qown__form {
    animation: none;
  }

  .qtoast {
    transform: none;
  }

  .qrow:has(.qrow__label:active),
  .qown__open:active {
    transform: none;
  }

  .friend-card,
  .friend-card__edit,
  .friend-card__remove {
    transition: none;
  }

  .contact-kind button {
    transition: none;
  }

  .friend-card__edit:active,
  .friend-card__remove:active {
    transform: none;
  }
}

/* Payment. */
.cbar--simple {
  grid-template-columns: 1fr auto 1fr;
}

.cbar__heading {
  font-weight: var(--weight-ui-medium);
}

.order {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  padding: var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.order__row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-m);
  font-weight: var(--weight-ui-medium);
}

.order__price,
.order__total span:last-child {
  font-variant-numeric: tabular-nums;
}

.order__detail {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.order__total {
  margin-top: var(--space-s);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
}

.card-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.card-form legend {
  margin-bottom: var(--space-xs);
  padding: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
}

.card-form .field {
  margin-top: 0;
}

.card-form__row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-s);
}

.card-number {
  position: relative;
}

.card-number .field__control {
  padding-right: var(--space-xxl);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

.card-number__chip {
  position: absolute;
  top: 50%;
  right: var(--space-m);
  color: var(--neutral-7);
  transform: translateY(-50%);
}

.pay__demo {
  text-align: center;
}

/* Payment page: card on the left, the order and Pay on the right (sticky);
   on phones the order comes first and Pay sits at the bottom. */
.paypage {
  min-height: 100svh;
  background: var(--neutral-1);
}

.paypage__bar {
  width: 100%;
  max-width: calc(var(--page-max) + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-m) var(--page-gutter);
}

.paypage__back {
  display: inline-flex;
  padding: var(--space-s);
  text-decoration: none;
}

.paypage__back .icon-svg {
  margin-inline: 0;
}

.checkout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 22rem;
  grid-template-areas:
    "title title"
    "card summary"
    "card pay";
  align-items: start;
  gap: var(--space-l) var(--space-xxl);
  width: 100%;
  max-width: calc(52rem + 2 * var(--page-gutter));
  margin-inline: auto;
  padding: var(--space-m) var(--page-gutter) var(--section-gap);
}

.checkout__title {
  grid-area: title;
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
}

.checkout__title:focus-visible {
  outline: 0;
}

.summary {
  grid-area: summary;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-l);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.summary__label {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
}

.summary__name {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.summary__lines {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.summary__lines li,
.summary__total {
  display: flex;
  justify-content: space-between;
  gap: var(--space-m);
}

.summary__lines li {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.summary__lines li > span:last-child {
  color: var(--neutral-10);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.summary__total {
  align-items: baseline;
  margin-top: var(--space-s);
  padding-top: var(--space-s);
  box-shadow: inset 0 1px 0 var(--neutral-4); /* a hairline above the total */
  font-weight: var(--weight-ui-medium);
}

.summary__total > span:last-child {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

/* The breakdown lines in the summary: a hairline above them, and a small
   note under a line where it helps ("$2.00 a year until it opens"). */
.summary__breakdown {
  margin-top: var(--space-xs);
  padding-top: var(--space-s);
  box-shadow: inset 0 1px 0 var(--neutral-4);
}

.summary__item {
  display: flex;
  flex-direction: column;
}

.summary__note {
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.summary__tax {
  margin: 0;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  text-align: right;
}

/* The price and its info button on one line: a small grey squircle after the
   number, centered on it. */
.opens__pricerow {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.info--tile {
  flex: none;
  width: 2rem;
  height: 2rem;
  margin: 0;
  padding: 0;
  border-radius: var(--radius-xs);
  background: var(--neutral-4);
  color: var(--neutral-8);
}

@supports (corner-shape: squircle) {
  .info--tile {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

@media (hover: hover) {
  .info--tile:hover {
    background: var(--neutral-5);
  }
}

.info--tile[aria-expanded="true"] {
  background: var(--neutral-5);
  color: var(--neutral-10);
}

.info--tile svg {
  width: 1.125rem;
  height: 1.125rem;
}

/* The price breakdown: a light grey note (tip.js), lines on the left and
   amounts on the right, then the total. */
/* Light note: white, lifted off the page with a soft layered shadow (no
   outline), so it never blends into the grey tiles under it. */
.tip--light {
  background: var(--neutral-1);
  color: var(--neutral-9);
  box-shadow:
    0 2px 6px color-mix(in srgb, var(--neutral-10) 6%, transparent),
    0 12px 32px color-mix(in srgb, var(--neutral-10) 12%, transparent);
}

.pricetip {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  width: min(18rem, calc(100vw - 2rem));
  padding: var(--space-m);
  border-radius: var(--radius-s);
}

@supports (corner-shape: squircle) {
  .pricetip {
    border-radius: var(--radius-m);
    corner-shape: squircle;
  }
}

.pricetip__title {
  margin: 0;
  font-weight: var(--weight-ui-medium);
  color: var(--neutral-10);
}

.pricetip__lines {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.pricetip__lines li,
.pricetip__total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-m);
}

.pricetip__lines li > span:last-child,
.pricetip__total span:last-child {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.pricetip__label {
  display: flex;
  flex-direction: column;
}

.pricetip__note {
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.pricetip__total {
  padding-top: var(--space-s);
  box-shadow: inset 0 1px 0 var(--neutral-4); /* a hairline above the total */
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
}

.pricetip__tax {
  margin: 0;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

.cardpay {
  grid-area: card;
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.cardpay .field {
  margin-top: 0;
}

.cardpay__title {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-medium);
  font-size: var(--type-item);
  line-height: 1.3;
}

.cardpay__icon {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background: var(--neutral-3);
}

.cardpay__icon svg {
  width: 1.25rem;
  height: 1.25rem;
  fill: var(--neutral-10);
}

/* Number, expiry and code read as one field: joined by a thin white gap, with
   the outer corners rounded. */
.cardgroup {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.cardgroup legend {
  margin-bottom: var(--space-xs);
  padding: 0;
}

.cardgroup__fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px;
  overflow: hidden;
  border-radius: var(--radius-s);
}

.cardgroup__fields .field__control {
  border-radius: 0;
  font-variant-numeric: tabular-nums;
}

.cardgroup__number {
  grid-column: 1 / -1;
  letter-spacing: 0.04em;
}

.cardpay__zip {
  max-width: 12rem;
}

/* After paying: a page of its own, one confirmation centered on the screen,
   then the capsule page. */
.paidpage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 100svh;
  background: var(--neutral-1);
}
.paid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
  max-width: 26rem;
  padding: var(--space-xxl) var(--page-gutter);
  text-align: center;
}

.paid[hidden] {
  display: none;
}

.paid__mark {
  display: grid;
  place-items: center;
  width: 5rem;
  height: 5rem;
  margin-bottom: var(--space-s);
  border-radius: var(--radius-l);
  background: color-mix(in oklch, var(--color-4) 28%, var(--neutral-1));
  color: var(--neutral-9);
  font-size: 2.5rem;
  animation: paid-pop 480ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@supports (corner-shape: squircle) {
  .paid__mark {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.paid__mark .icon {
  font-size: inherit;
}

@keyframes paid-pop {
  from {
    opacity: 0;
    transform: scale(0.6);
  }
}

@media (prefers-reduced-motion: reduce) {
  .paid__mark {
    animation: none;
  }
}

.paid__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xxl);
  text-wrap: balance;
}

.paid__title:focus {
  outline: none;
}

.paidpage__redirect {
  position: absolute;
  inset: auto 0 0;
  padding: var(--space-l) var(--page-gutter) calc(var(--space-xl) + env(safe-area-inset-bottom));
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-align: center;
}

.paybar {
  grid-area: pay;
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.paybar__go {
  width: 100%;
  padding-block: var(--space-m);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.paybar__note {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xxs);
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  text-align: center;
}

@media (max-width: 760px) {
  .checkout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "title"
      "summary"
      "card"
      "pay";
    gap: var(--space-xl);
    max-width: calc(27.5rem + 2 * var(--page-gutter));
    padding-bottom: 0;
  }

  .paybar {
    position: sticky;
    bottom: 0;
    padding: var(--space-m) 0 calc(var(--space-l) + env(safe-area-inset-bottom));
    background: linear-gradient(to top, var(--neutral-1) 80%, color-mix(in srgb, var(--neutral-1) 0%, transparent));
  }
}

.shead[hidden] {
  visibility: hidden;
}

/* The capsule page (the capsule's dashboard). Every fact sits in one place:
   the head has the name, the grey card the clock and the open date, and each
   person is a tile colored by where they are. */
.capage {
  min-height: 100svh;
}

.capage__main {
  display: flex;
  flex-direction: column;
  gap: var(--section-inner);
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding: var(--space-m) var(--page-gutter) var(--section-gap);
}

.capage .acctpage__bar {
  max-width: var(--page-max);
}

.capage__main[hidden] {
  display: none;
}

/* The head: the name and when it opens on the left, the clock on the right,
   both centered on one horizontal spine. */
.capage__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-m) var(--space-xl);
}

.capage__title {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
}

.capage__opens {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.capage__opens strong {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
}

.capage__wait::before {
  content: " · ";
}

.capage__name {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xxl);
  overflow-wrap: anywhere;
  text-wrap: balance;
}

/* One column, one left and right edge: the clock band on top, then the people
   across the full width. Seven people plus the Add tile make an even 4 by 2. */
.cgrid {
  display: flex;
  flex-direction: column;
  gap: var(--section-inner);
}

.cpeople {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

/* The legend sits under the title, on the same left edge as the tiles. */
.cpeople__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);
}

.cpeople__title {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-section);
  line-height: 1.2;
  margin-block-start: -0.125em; /* optical: the line box adds space above the capitals */
  letter-spacing: var(--letter-spacing-l);
}

/* Status as the usual traffic light, in the brand's own colors: invited is
   quiet grey, answering is the brand yellow, sealed is the brand green. */
[data-status="invited"] {
  --status: var(--neutral-5);
  --tile: var(--neutral-3);
  --mark: var(--neutral-1);
}

[data-status="processing"] {
  --status: var(--color-1);
  --tile: color-mix(in oklch, var(--color-1) 22%, var(--neutral-1));
  --mark: var(--color-1);
}

[data-status="sealed"] {
  --status: var(--color-4);
  --tile: color-mix(in oklch, var(--color-4) 22%, var(--neutral-1));
  --mark: var(--color-4);
}

.ckey {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xxs) var(--space-m);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

.ckey li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}

.ckey__dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--radius-full);
  background: var(--status);
}

/* People as squircle tiles: the tile and avatar carry the status, so the
   state reads before any text does. */
.ctiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ctile {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  min-width: 0;
  min-height: 12.5rem;
  padding: var(--space-m);
  border-radius: var(--radius-l);
  background: var(--tile, var(--neutral-3));
  color: var(--ink, var(--neutral-10));
  transition: background-color var(--motion-large-duration) var(--motion-large-easing);
}

.ctile__avatar {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius-s);
  /* Always white: the keepsakes are colorful, so the status lives in the tile's
     tint, its label and the lock, never behind the keepsake (yellow behind the
     ticket, or green behind the film, made them disappear). */
  background: var(--neutral-1);
  color: var(--ink, var(--neutral-9));
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-m);
  line-height: 1;
  letter-spacing: var(--letter-spacing-s);
  text-transform: uppercase;
  transition: background-color var(--motion-large-duration) var(--motion-large-easing);
}

/* Sealed: they keep their keepsake, with a small lock in the corner. */
.ctile__lock {
  position: absolute;
  right: -4px;
  bottom: -4px;
  display: grid;
  place-items: center;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--ink, var(--neutral-9));
  box-shadow: 0 0 0 2px var(--tile, var(--neutral-3));
}

.ctile__lock .icon {
  font-size: 0.875rem;
}

@supports (corner-shape: squircle) {
  .ctile {
    border-radius: var(--radius-xl);
    corner-shape: squircle;
  }

  .ctile__avatar {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.ctile__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ctile__name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-weight: var(--weight-ui-medium);
  overflow-wrap: anywhere;
}

.ctile__status {
  color: var(--ink-soft, var(--neutral-8));
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* Copy and QR: flat white controls, one radius with the buttons. */
.ctile__actions {
  display: flex;
  gap: var(--space-xs);
  margin-top: auto;
}

.ctile__copy,
.ctile__qr {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-height: 2.5rem;
  border: 0;
  border-radius: var(--radius-s);
  background: var(--neutral-1);
  color: var(--neutral-10);
  font: inherit;
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  letter-spacing: var(--tracking-l);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    transform 160ms var(--motion-easing);
}

.ctile__copy {
  flex: 1;
  min-width: 0;
  padding: 0 var(--space-s) 0 var(--space-xs);
}

.ctile__qr {
  flex: none;
  width: 2.5rem;
}

.ctile__copy .icon,
.ctile__qr .icon {
  font-size: 1.25rem;
}

.ctile__copy.is-copied {
  background: var(--neutral-8);
  color: var(--neutral-1);
}

@media (hover: hover) and (pointer: fine) {
  .ctile__copy:hover,
  .ctile__qr:hover {
    background: color-mix(in oklch, var(--neutral-1) 70%, transparent);
  }

  .ctile__copy.is-copied:hover {
    background: var(--neutral-8);
  }
}

.ctile__copy:active,
.ctile__qr:active {
  transform: scale(0.97);
}

.ctile__copy:focus-visible,
.ctile__qr:focus-visible,
.ctile__addbtn:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* The add tile: an empty slot, so an outline instead of a fill. The whole
   tile is the button. */
.ctile--add {
  padding: 0;
  background: none;
  box-shadow: inset 0 0 0 1.5px var(--neutral-4);
}

.ctile__addbtn {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  flex: 1;
  padding: var(--space-m);
  border: 0;
  border-radius: inherit;
  corner-shape: inherit;
  background: none;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: background-color var(--motion-duration) var(--motion-easing), transform 160ms var(--motion-easing);
}

.ctile--add .ctile__avatar {
  background: var(--neutral-3);
}

.ctile--add .ctile__avatar .icon {
  font-size: 1.5rem;
}

@media (hover: hover) and (pointer: fine) {
  .ctile__addbtn:hover {
    background: var(--neutral-3);
  }

  .ctile__addbtn:hover .ctile__avatar {
    background: var(--neutral-1);
  }
}

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

/* Prototype only: step people forward or back. */
.cpeople__demo {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  color: var(--neutral-7);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.cpeople__demo .link:disabled {
  color: var(--neutral-5);
  text-decoration: none;
  cursor: default;
}

/* The clock: no card, just type, right-aligned so the last number and its
   label end exactly on the page's right edge (the same edge the tiles end on). */
.timer {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-xs);
  color: var(--neutral-10);
  text-align: end;
}

.timer__label {
  color: var(--neutral-8);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
}

.timer__digits {
  display: flex;
  gap: var(--space-l);
}

.timer__digits[hidden] {
  display: none;
}

/* Every unit has one fixed width, wide enough for its widest two digits, so
   the card never changes size as the numbers roll or "6 days" becomes "10". */
.timer__unit {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  flex: none;
  align-items: flex-end;
  width: calc(var(--size-l) * 1.5);
}

.timer__num {
  white-space: nowrap;
  margin-inline-end: -0.04em; /* optical: big numerals carry side space that pushes them off the label's edge */
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: 1;
  letter-spacing: var(--letter-spacing-xxl);
  font-variant-numeric: tabular-nums;
}

.timer__name {
  color: var(--neutral-8);
  font-size: var(--size-xxs);
  line-height: var(--line-xxs);
}

/* A person's QR code (dialog on wide screens, sheet on phones). */
.cqr {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.cqr__code {
  display: grid;
  place-items: center;
  width: min(100%, 17rem);
  aspect-ratio: 1;
  margin: var(--space-xs) auto;
  padding: var(--space-s);
  border-radius: var(--radius-l);
  background: var(--neutral-1);
  color: var(--neutral-10);
  box-shadow: 0 0 0 1px color-mix(in oklch, var(--neutral-10) 8%, transparent);
}

.cqr__code svg {
  width: 100%;
  height: 100%;
}

.cqr__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
}

.cqr__actions .button {
  width: 100%;
}

.cqr__actions .button .icon {
  font-size: 1.25rem;
}

/* Adding a person (dialog on wide screens, sheet on phones). One column on
   white: the fields are soft grey fills, one primary action, Cancel under it. */
.cadd {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.cadd__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
}

.cadd__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.cadd .field {
  margin-top: 0;
}

.cadd .field__control,
.cadd .country {
  min-height: 3.25rem;
  border-radius: var(--radius-s);
  background: var(--neutral-3);
}

.cadd__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
}

.cadd__actions .button {
  width: 100%;
}

.cadd-dialog {
  width: min(28rem, calc(100% - var(--page-gutter) * 2));
}

.cqr-dialog {
  width: min(24rem, calc(100% - var(--page-gutter) * 2));
}

@media (max-width: 900px) {
  .ctiles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* On a phone the clock takes the full width, numbers spread edge to edge. */
@media (max-width: 700px) {
  /* Stacked under the name, so it goes back to the left edge. */
  .timer {
    align-items: flex-start;
    text-align: start;
  }

  .timer__unit {
    align-items: flex-start;
  }

  .timer__num {
    margin-inline: -0.04em 0;
  }
}

@media (max-width: 600px) {
  .ctiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ctile,
  .ctile__addbtn {
    min-height: 11rem;
    padding: var(--space-s);
  }

  .ctile--add {
    padding: 0;
  }

  .ctile__avatar {
    width: 3rem;
    height: 3rem;
  }

  .ctile__copy {
    padding-inline: var(--space-xs);
  }
}

@media (max-width: 600px) {
  .card-form__row {
    grid-template-columns: 1fr 1fr;
  }

  .card-form__row .field:last-child {
    grid-column: 1 / -1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .opens {
    animation: none;
  }
}

/* Capsules on the dashboard: three things only. The name, then along the bottom
   edge the time left until it seals (left) and the people (right). Both blocks
   stand on one baseline: a big element over a small label, so the labels line
   up. The size and corners match the create card. Once sealed the card takes
   the same green wash as a sealed person. */
.ccard {
  /* A capsule is a raised white card: a hairline ring and layered warm shadows
     lift it off the page, where the draft is a flat outline. Sealed takes a
     soft green wash. */
  --card: var(--neutral-1);
  --ink: var(--neutral-10);
  --ink-soft: var(--neutral-8);
  --dot-idle: var(--neutral-5);
  --lift:
    0 0 0 1px color-mix(in oklch, var(--neutral-9) 7%, transparent),
    0 1px 2px color-mix(in oklch, var(--neutral-9) 6%, transparent),
    0 8px 24px color-mix(in oklch, var(--neutral-9) 9%, transparent);
  box-shadow: var(--lift);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-l);
  aspect-ratio: 4 / 3;
  padding: var(--card-pad, var(--space-xl));
  border-radius: var(--radius-xl);
  background: var(--card);
  color: var(--ink);
  text-decoration: none;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    box-shadow var(--motion-duration) var(--motion-easing),
    transform var(--motion-duration) var(--motion-easing);;
}

.ccard.is-sealed {
  --card: color-mix(in oklch, var(--color-4) 22%, var(--neutral-1));
}

@supports (corner-shape: squircle) {
  .ccard {
    border-radius: calc(var(--radius-xl) * 1.4);
    corner-shape: squircle;
  }
}

@media (hover: hover) {
  a.ccard:hover {
    transform: translateY(-2px);
    box-shadow:
      0 0 0 1px color-mix(in oklch, var(--neutral-9) 9%, transparent),
      0 2px 4px color-mix(in oklch, var(--neutral-9) 6%, transparent),
      0 14px 32px color-mix(in oklch, var(--neutral-9) 12%, transparent);
  }

  a.ccard.is-sealed:hover {
    --card: color-mix(in oklch, var(--color-4) 30%, var(--neutral-1));
  }
}

a.ccard:active {
  transform: scale(0.99);
  box-shadow: var(--lift);
}

a.ccard:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

.ccard__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-m);
}

.ccard__title {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
}

.ccard__opens {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.ccard__name {
  display: -webkit-box;
  margin: calc(var(--space-xxs) * -1) 0 0; /* optical: the line box adds space above the capitals */
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xxl);
  text-wrap: balance;
  overflow-wrap: anywhere;
}

.ccard__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-m);
}

.ccard__time,
.ccard__crowd {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  margin: 0;
  min-width: 0;
}

.ccard__crowd {
  align-items: flex-end;
}

.ccard__big {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  height: 2rem; /* the number's row height, so both blocks stand on the same line */
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-l);
  line-height: 1;
  letter-spacing: var(--letter-spacing-xxl);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ccard__big .icon {
  font-size: 1.5rem;
}

.ccard__label {
  color: var(--ink-soft);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

/* The people: one dot each, in the color of where they are (grey invited,
   yellow answering, green sealed), so the row reads as progress. */
.ccard__dots {
  display: flex;
  align-items: center;
  height: 2rem; /* the same as the time row, so both blocks stand on one line */
  gap: var(--space-xs);
}

.ccard__dot {
  --status: var(--dot-idle);
  width: 0.875rem;
  height: 0.875rem;
  border-radius: var(--radius-full);
  background: var(--status);
  transition: background-color var(--motion-large-duration) var(--motion-large-easing);
}

.ccard__dot[data-status="processing"] {
  --status: var(--color-1);
}

.ccard__dot[data-status="sealed"] {
  --status: var(--color-4);
}

.cap__status {
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-full);
  background: var(--tint-soft);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  font-weight: var(--weight-ui-medium);
}

/* Stacked layout for tablets and phones. Only the structure changes here
   (columns collapse); sizes and spacing already flow through clamp(). */

@media (max-width: 900px) {
  /* One column, in source order: headline, preview, sign-in, all centered
     on the page axis. */
  .split {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    align-content: start;
    row-gap: var(--space-xxl);
    padding-block: var(--space-l) 0;
  }

  .pitch__title,
  .pitch__note,
  .split__preview,
  .signin {
    grid-column: 1 / -1;
    grid-row: auto;
    margin: 0;
  }

  /* Stays tucked under the headline, not a full row gap away. */
  .pitch__note {
    justify-self: center;
    margin-top: calc(var(--space-s) - var(--space-xxl));
    text-align: center;
  }

  .pitch__title {
    justify-self: center;
    text-align: center;
    /* Grows on tablets so it still leads the preview; phones keep 24px. */
    font-size: clamp(var(--type-display), 5vw, 2.75rem);
  }

  .signin {
    justify-self: center;
  }

  /* Fits the screen width, centered, no bleed. */
  .mock {
    --u: clamp(0.5px, calc(100cqi / 560), 1px);
    margin-inline: auto;
  }

  .vault {
    grid-template-columns: minmax(0, 1fr);
  }

  .tl,
  .stage {
    grid-column: 1 / -1;
  }

  .stage {
    display: none;
  }

  .tl__art {
    display: block;
  }
}

/* Phones: the onboarding column fills the screen and its main action sits at
   the bottom, in thumb reach. */
@media (max-width: 600px) {
  .flow__main {
    padding-bottom: var(--space-l);
  }

  .flow__screen {
    min-height: 100%;
    margin: 0 auto;
  }

  .flow__actions {
    margin-top: auto;
  }
}

/* ---------- The friend's side (answer.html) ----------
   Same frame as setup: story bars, one thing per screen, the button pinned
   at the bottom. Their video, cards one at a time, the camera shared by
   practice and the questions, the sacrifice, sealed. */

/* The creator's face sits inline, right after their name in the title. Blank
   until there are photos; an <img> inside fills it. */
.nowrap {
  white-space: nowrap;
}

/* Their face sits right against their name, so the two read as one: a gap
   tighter than a word space (the word space comes after the face instead),
   and centered on the capitals rather than resting on the baseline. */
.rxface {
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-inline-start: 0.12em;
  overflow: hidden;
  border-radius: 0.32em;
  background: var(--neutral-4);
  vertical-align: -0.13em;
}

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

@supports (corner-shape: squircle) {
  .rxface {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

/* Their video: the white Play to start (Replay at the end), then the
   project's player bar (.vscrub, setup's), which fades while it plays. */
.rxv {
  position: relative;
  display: grid;
  overflow: hidden;
  aspect-ratio: 3 / 2; /* until the video's own shape is known */
  /* Never taller than about half the screen, so the step (title, video, the
     pinned footer note) always fits; on a short screen the picture trims a
     little top and bottom (object-fit: cover) instead of running under it. */
  max-height: 56svh;
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.rxv__video {
  /* Pinned to the frame, so it never sets the grid's height: the Play button
     always centers on the frame you see, before and after the video loads. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--neutral-10);
  cursor: pointer;
}

.rxv__video[hidden],
.rxv__none[hidden],
.rxv__play[hidden] {
  display: none;
}

.rxv__none {
  grid-area: 1 / 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-m);
  padding: var(--space-l);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  text-align: center;
}

.rxv__none p {
  max-width: 24em;
  margin: 0;
  text-wrap: balance; /* short centered note: even lines, no "one yet." left alone */
}

.rxv__play {
  grid-area: 1 / 1;
  place-self: center;
  position: relative;
  z-index: 2; /* over the pinned video, under the bar (3) */
}

/* The video's one button: the primary button's build (hairline ring, top
   highlight, soft lift, press), in white instead of yellow, so it reads on
   any frame of the video without competing with the page's one yellow
   action. Local to the video, not a site-wide variant (rule 7). */
.button.rxv__play {
  --tint: var(--neutral-10);
  --edge:
    0 0 0 1px color-mix(in srgb, var(--neutral-10) 10%, transparent),
    inset 0 1px 0 color-mix(in srgb, white 80%, transparent);
  --shadow-rest:
    0 1px 2px color-mix(in srgb, var(--tint) 22%, transparent),
    0 6px 16px color-mix(in srgb, var(--tint) 24%, transparent);
  --shadow-lift:
    0 2px 3px color-mix(in srgb, var(--tint) 24%, transparent),
    0 8px 20px color-mix(in srgb, var(--tint) 28%, transparent);
  --shadow-press: 0 1px 1px color-mix(in srgb, var(--tint) 22%, transparent);
  padding: var(--space-m) var(--space-l);
  background: var(--neutral-1);
  color: var(--neutral-10);
}

@media (hover: hover) {
  .button.rxv__play:hover {
    background: var(--neutral-2);
  }
}

.rxv__play .icon {
  font-size: 1.25rem;
}

.rxv__play .icon-svg {
  width: 1.125rem;
  height: 1.125rem;
}

.rxv__play [hidden] {
  display: none;
}

.rxv.is-idle .vscrub {
  opacity: 0;
  pointer-events: none;
}

/* Phones: one slim row over the bottom of the video, play or pause, the
   scrubber with time left, then sound and full screen. No 10s jumps (the
   scrubber does it), no volume slider (the phone's own buttons), a shorter
   fade, smaller buttons. */
@media (max-width: 600px) {
  .rxv .vscrub {
    flex-direction: row;
    align-items: center;
    gap: var(--space-xxs);
    padding: var(--space-l) var(--space-xs) var(--space-xxs);
    background: linear-gradient(to top, color-mix(in srgb, var(--neutral-10) 65%, transparent), transparent);
  }

  .rxv .vscrub__row,
  .rxv .vscrub__side,
  .rxv .vscrub__vol {
    display: contents;
  }

  .rxv #rxv-toggle { order: 1; }
  .rxv .vscrub__line { order: 2; flex: 1; min-width: 0; gap: var(--space-xs); }
  .rxv #rxv-mute { order: 3; }
  .rxv #rxv-full { order: 4; }

  .rxv #rxv-back,
  .rxv #rxv-fwd {
    display: none;
  }

  .rxv .vscrub__toggle,
  .rxv .vscrub__btn {
    width: 2.25rem;
    height: 2.25rem;
  }

  .rxv .vscrub__btn .icon {
    font-size: 1.375rem;
  }
}

.rxv.is-idle {
  cursor: none;
}

.rx-pop {
  animation: done-pop 480ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

/* How it works: small dots for the cards, then one card in the middle. */
.rxdots {
  display: flex;
  justify-content: center;
  gap: var(--space-xs);
}

.rxdots i {
  width: 2rem;
  height: 0.375rem;
  border-radius: var(--radius-full);
  background: var(--neutral-4);
  transition: background-color var(--motion-large-duration) var(--motion-large-easing);
}

.rxdots i.is-on {
  background: var(--neutral-8);
}

.rxfoot {
  display: flex;
  gap: var(--space-s);
}

.rxfoot .cfoot__go {
  flex: 1;
  width: auto;
}

.rxfoot__back {
  flex: none;
  padding-inline: var(--space-m);
}

.rxfoot__back .icon-svg {
  margin-inline: 0;
}

/* Flipping through the cards, nothing moves but the content: each card is
   anchored to the top (not centered, which made a longer card ride up), the
   art box is one height for all four, and every title fits on one line, so
   the drawing, the title and the body copy start on the same lines every time
   with the same gaps between them. A longer card only grows downward.
   The title gets a wider line (28rem) than the body copy (24rem, a measure
   that wraps evenly); on screens narrower than that, its size follows the
   width so the longest ("One take for each question.", about 13.2em) still
   fits on one line. */
.rxcard {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-m);
  width: 100%;
  max-width: 28rem;
  margin: clamp(1.5rem, 9svh, 5.5rem) auto auto;
  text-align: center;
}

.rxcard .cstep__title {
  font-size: min(var(--type-display), calc((100vw - 2 * var(--page-gutter)) / 13.6));
  white-space: nowrap;
}

.rxcard > :is(.cstep__text, .rxlines) {
  max-width: 24rem;
}

.rxcard--from-right {
  animation: rxcard-right var(--motion-large-duration) var(--motion-large-easing) both;
}

.rxcard--from-left {
  animation: rxcard-left var(--motion-large-duration) var(--motion-large-easing) both;
}

@keyframes rxcard-right {
  from {
    opacity: 0;
    transform: translateX(var(--space-xxl));
  }
}

@keyframes rxcard-left {
  from {
    opacity: 0;
    transform: translateX(calc(var(--space-xxl) * -1));
  }
}

.rxcard__art {
  display: grid;
  place-items: center;
  width: 5rem;
  height: 5rem;
  margin-bottom: var(--space-s);
  border-radius: var(--radius-l);
  background: var(--neutral-3);
  color: var(--neutral-10);
  font-size: 2.25rem;
}

.rxlines {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
  color: var(--neutral-8);
  text-wrap: pretty;
}

.rxlines p {
  margin: 0;
  text-wrap: balance;
}

.rxlines strong {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-heavy);
}

/* A small icon in the middle of a sentence: no box, the text's own color, so it
   reads as part of the words. Its box is one line tall, so lines stay even. */
.rxi {
  display: inline-grid;
  place-items: center;
  width: 1.1em;
  height: 1em; /* inside the line, so it never stretches it */
  color: inherit;
  font-size: var(--size-m);
  vertical-align: -0.17em; /* its middle on the middle of the capital letters */
}

.rxi .icon {
  font-size: 1.15em;
}

.rxi svg {
  width: 1.1em;
  height: 1.1em;
  fill: currentColor;
}

.rxcard__art .icon {
  font-size: 1em; /* same size as the clock drawing */
}

.rxcard__art svg {
  width: 2.25rem;
  height: 2.25rem;
  fill: currentColor;
}

@supports (corner-shape: squircle) {
  .rxcard__art {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

/* The "Encrypted and sealed" card: a yellow padlock (answer.js, LOCK), drawn
   in Duolingo's style. No box behind it: it floats on its own over a soft
   shadow. Its own palette, the brand yellow (an exception, see rules.md).
   The story, once, as the card appears: open (the shackle up), the shackle
   snaps shut (falling, so it speeds up), the body gives on impact and springs
   back, three click lines flash; then it stays still, so it never pulls the
   eye from the words. Reduced motion: shown locked. */
.rxcard__art--lock {
  width: 6rem;
  height: 8rem;
  background: none;
}

.rxcard__art .rxlock {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.rxlock__metal { fill: #ffce00; }
.rxlock__shade { fill: #f2b600; }
.rxlock__shine { fill: #ffffff; opacity: 0.55; }
.rxlock__hole { fill: #8a5a00; }

/* The shackle is silver: a cool grey with a lighter streak along its curve. */
.rxlock__shackle {
  fill: none;
  stroke: #b9bec6;
  stroke-width: 6.5;
  stroke-linecap: round;
  animation: rxlock-shut 560ms both;
}

.rxlock__shackle-shine {
  fill: none;
  stroke: #eef0f3;
  stroke-width: 1.8;
  stroke-linecap: round;
  animation: rxlock-shut 560ms both; /* moves with the shackle */
}

.rxlock__clicks path {
  fill: none;
  stroke: #e0a100;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.rxlock__clicks {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: rxlock-click 420ms 470ms ease-out both;
}

.rxlock__body {
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: rxlock-give 420ms 460ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.rxlock__shadow {
  fill: #000000;
  opacity: 0.1;
}

/* Up and open, a beat to see it, then it drops shut: ease-in for the fall,
   a hair past closed, settle. */
@keyframes rxlock-shut {
  0%,
  50% {
    transform: translateY(-9px);
    animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
  }

  82% {
    transform: translateY(1.2px);
    animation-timing-function: ease-out;
  }

  100% {
    transform: none;
  }
}

@keyframes rxlock-give {
  0% {
    transform: none;
  }

  30% {
    transform: scale(1.06, 0.92);
  }

  100% {
    transform: none;
  }
}

@keyframes rxlock-click {
  0% {
    opacity: 0;
    transform: scale(0.6);
  }

  35% {
    opacity: 1;
    transform: scale(1);
  }

  100% {
    opacity: 0;
    transform: scale(1.15);
  }
}

@media (prefers-reduced-motion: reduce) {
  .rxlock__shackle,
  .rxlock__clicks,
  .rxlock__body {
    animation: none;
  }
}

/* "One take for each question": a clapperboard (answer.js, CLAP) in the same
   style and motion as the lock, black and white only: a black board with a
   white 1 and TAKE, classic stripes. The arm claps shut once, then it's still. */
.rxcard__art--clap {
  width: 7rem;
  height: 8rem;
  background: none;
}

.rxcard__art .rxclap {
  width: 100%;
  height: 100%;
  overflow: visible;
  /* It sits on the page, not in it: a close shadow under it and a wide soft
     one, so its black and white never blend into a white page. */
  filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.14)) drop-shadow(0 8px 14px rgb(0 0 0 / 0.12));
}

/* Black and white only: charcoal, white, and a soft grey for depth. */
.rxclap__dark { fill: #2f2b2a; }
.rxclap__stripe { fill: #ffffff; }
.rxclap__hinge { fill: #b9bec6; }

.rxclap__board-shade { fill: #1d1a19; }
.rxclap__shine { fill: #ffffff; opacity: 0.14; }

.rxclap__one,
.rxclap__take {
  fill: #ffffff;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  text-anchor: middle;
}

.rxclap__one {
  font-size: 15px;
}

.rxclap__take {
  font-size: 5.6px;
  letter-spacing: 0.16em;
}

/* Raised, a beat, then it claps down (falling, so ease-in), a hair past shut,
   a small bounce, settled. */
.rxclap__arm {
  transform-box: view-box;
  transform-origin: 13px 24.5px;
  animation: rxclap-snap 640ms both;
}

@keyframes rxclap-snap {
  0%,
  45% {
    transform: rotate(-26deg);
    animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
  }

  70% {
    transform: rotate(1.5deg);
    animation-timing-function: ease-out;
  }

  84% {
    transform: rotate(-3deg);
  }

  100% {
    transform: none;
  }
}

.rxclap__board {
  transform-box: fill-box;
  transform-origin: center bottom;
  animation: rxlock-give 420ms 450ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.rxclap__clicks path {
  fill: none;
  stroke: #2f2b2a;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.rxclap__clicks {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: left bottom;
  animation: rxlock-click 420ms 460ms ease-out both;
}

@media (prefers-reduced-motion: reduce) {
  .rxclap__arm,
  .rxclap__board,
  .rxclap__clicks {
    animation: none;
  }
}

/* "No mirror, on purpose": a hand mirror (answer.js, MIRROR), the same size
   and style as the lock, its frame in the same yellow. The glass starts clear
   with a face reflected in it; after a beat the mist creeps in from the left,
   the face blurs away and the glass pales, until it's all frosted. Then still.
   Reduced motion: shown frosted. */
.rxcard__art--mirror {
  width: 6rem;
  height: 8rem;
  background: none;
}

.rxcard__art .rxmirror {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.rxmirror__glass {
  fill: #cfe7f4;
  animation: rxmirror-pale 900ms 720ms ease-out both;
}

.rxmirror__rim-shine {
  fill: none;
  stroke: #ffffff;
  stroke-width: 1.5;
  stroke-linecap: round;
  opacity: 0.6;
}

/* The reflected face: crisp at first, then it fades as a blurred copy takes
   its place, under the mist. */
.rxmirror__face circle,
.rxmirror__face-soft circle {
  fill: #5d7180;
}

.rxmirror__face path,
.rxmirror__face-soft path {
  fill: none;
  stroke: #5d7180;
  stroke-width: 1.9;
  stroke-linecap: round;
}

.rxmirror__face {
  animation: rxmirror-unclear 700ms 750ms ease-out both;
}

.rxmirror__face-soft {
  opacity: 0;
  animation: rxmirror-soften 700ms 750ms ease-out both;
}

.rxmirror__shine {
  fill: none;
  stroke: #ffffff;
  stroke-width: 2.6;
  stroke-linecap: round;
  animation: rxmirror-unclear 700ms 750ms ease-out both;
}

.rxmirror__fog circle {
  fill: #ffffff;
}

.rxmirror__fog {
  opacity: 0;
  transform-box: view-box;
  transform-origin: 16px 31px;
  animation: rxmirror-fog 1000ms 700ms cubic-bezier(0.23, 1, 0.32, 1) both;
}


@keyframes rxmirror-pale {
  to {
    fill: #e7f2f8;
  }
}

@keyframes rxmirror-unclear {
  to {
    opacity: 0;
  }
}

@keyframes rxmirror-soften {
  to {
    opacity: 0.55;
  }
}

/* The mist creeps in from the left edge of the glass and spreads. */
@keyframes rxmirror-fog {
  from {
    opacity: 0;
    transform: translateX(-8px) scale(0.6);
  }

  to {
    opacity: 0.88;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rxmirror__glass,
  .rxmirror__face,
  .rxmirror__face-soft,
  .rxmirror__shine,
  .rxmirror__fog {
    animation-duration: 1ms;
    animation-delay: 0ms;
  }
}

/* "Go at your own pace": a snail (answer.js, SNAIL), the same size and style
   as the others, in its own natural colors, no face. It slides in a little
   from the left (its body stretching as it goes, the shell carried along),
   settles, and stays still. Reduced motion: shown in place. */
.rxcard__art--snail {
  width: 6rem;
  height: 8rem;
  background: none;
}

.rxcard__art .rxsnail {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.rxsnail__skin { fill: #dccdb3; }
.rxsnail__skin-shade { fill: #c6b597; }
.rxsnail__tip { fill: #c6b597; }

.rxsnail__feeler {
  fill: none;
  stroke: #c6b597;
  stroke-width: 2.4;
  stroke-linecap: round;
}

.rxsnail__shell-main { fill: #cf8f4e; }
.rxsnail__shell-shade { fill: #a86d36; }

.rxsnail__spiral {
  fill: none;
  stroke: #8e5a2b;
  stroke-width: 2.6;
  stroke-linecap: round;
}

.rxsnail__shine {
  fill: none;
  stroke: #ffffff;
  stroke-width: 2.4;
  stroke-linecap: round;
  opacity: 0.4;
}

/* In from a little to the left, slowly (it's a snail), easing to a stop. */
.rxsnail__move {
  animation: rxsnail-in 1100ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

/* The body stretches as it moves, then gathers back. */
.rxsnail__body {
  transform-box: fill-box;
  transform-origin: left bottom;
  animation: rxsnail-stretch 1100ms ease-in-out both;
}

@keyframes rxsnail-in {
  from {
    opacity: 0;
    transform: translateX(-12px);
  }

  30% {
    opacity: 1;
  }

  to {
    transform: none;
  }
}

@keyframes rxsnail-stretch {
  0%,
  100% {
    transform: none;
  }

  50% {
    transform: scaleX(1.06);
  }
}

@media (prefers-reduced-motion: reduce) {
  .rxsnail__move,
  .rxsnail__body {
    animation: none;
  }
}

/* Between questions: a mark, the encouragement, which question is next, and the
   button right under the words, all in the middle of the screen. */
.rxnext {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-s);
  margin-block: auto;
  text-align: center;
}

.rxnext[hidden],
.rxask[hidden] {
  display: none;
}

/* Between questions the words centre on the screen itself, not on the space under the
   top bar (that sits a few rem lower than the middle). The step is pulled up under the
   bar to cover the whole viewport, and a little weight at the bottom lifts the group
   slightly above the exact middle, where the eye reads the centre of a page. */
.cstep[data-step="questions"]:not(.is-answering) {
  min-height: 100svh;
  margin-top: calc(var(--rx-top, 0px) * -1);
  padding-bottom: 10svh;
  box-sizing: border-box;
}

.rxnext .rxcard__art {
  margin-bottom: var(--space-s);
}

/* The mark between questions: a pile of video tapes, one per question so far
   (answer.js, tapeStack), the top one labelled with the number coming up.
   Black and white like the clapperboard (an exception, see rules.md).
   Once, as the screen opens, the new tape drops onto the pile, worked out
   like a real fall: it accelerates under gravity (an exact parabola), held a
   little askew, so one corner hits first; it slaps down flat around that
   corner, bounces a hair (most of the energy is gone on a soft landing),
   and settles. The pile under it takes the hit and two puffs of dust push
   out from under it. Then everything stays still. Reduced motion: the pile
   just shows. */
.rxnext__tapes {
  width: 8rem;
  height: 9.5rem;
  background: none;
}

.rxnext__tapes .rxtapes {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.rxtape__top { fill: #58524e; stroke: #58524e; stroke-width: 3; stroke-linejoin: round; }
.rxtape__spine { fill: #45403c; }
.rxtape__spine-shade { fill: #2d2926; }
.rxtape__cast,
.rxtape__fall,
.rxtape__ground-contact { fill: #120f0d; }
.rxtape__cast { opacity: 0.55; }
.rxtape__fall { opacity: 0; transform-box: fill-box; transform-origin: center; }
.rxtape__ground-soft { fill: #120f0d; opacity: 0.12; }
.rxtape__ground-contact { opacity: 0.28; }
.rxtape__ground { transform-box: fill-box; transform-origin: center; }
.rxtape__paper { fill: #f6f3ec; }
.rxtape__window { fill: #1d1a19; }
.rxtape__reel { fill: #6b6560; }
.rxtape__hub { fill: #f6f3ec; }

.rxtape__num {
  fill: #2f2b2a;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-anchor: middle;
  dominant-baseline: central;
}

.rxtape__drop {
  transform-box: view-box;
}

.rxtape__dust circle {
  fill: var(--neutral-4);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.rxnext:not([hidden]) .rxtape--top .rxtape__drop {
  animation: rxtape-drop 760ms 200ms both;
}

.rxnext:not([hidden]) .rxtape:not(.rxtape--top) .rxtape__drop {
  animation: rxtape-give 760ms 200ms both;
}

/* The shadow of the falling tape: faint and spread out while it's high,
   dark and tight just before it lands (then the tape covers it). On the
   first breather it's the ground shadow itself that gathers. */
.rxnext:not([hidden]) .rxtape__fall {
  animation: rxtape-fall-shadow 760ms 200ms both;
}

.rxnext:not([hidden]) .rxtape--under .rxtape__cast {
  animation: rxtape-cast 760ms 200ms both;
}

.rxnext:not([hidden]) .rxtape__ground--fall {
  animation: rxtape-ground 760ms 200ms both;
}

.rxnext:not([hidden]) .rxtape__dust circle {
  animation: rxtape-dust 420ms cubic-bezier(0.23, 1, 0.32, 1) 650ms both;
}

.rxtape__dust circle:first-child { --dir: -1; }
.rxtape__dust circle:last-child { --dir: 1; }

/* 0 to 48%: falling from rest, so the distance grows with time squared
   (cubic-bezier(1/3, 0, 2/3, 1/3) is exactly y = t²). It's tipped 6deg, so its
   right corner meets the pile first, 3.3 units before its middle would.
   48 to 60%: it pivots on that corner and slaps flat, still speeding up.
   Then a small bounce (up 1.6, falling back under the same gravity) and a
   last tiny one, each a fraction of the one before. */
@keyframes rxtape-drop {
  0% {
    opacity: 0;
    transform: translateY(-46px) rotate(6deg);
    animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333);
  }
  6% { opacity: 1; }
  48% {
    transform: translateY(-3.3px) rotate(6deg);
    animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333);
  }
  60% {
    transform: translateY(0) rotate(0deg);
    animation-timing-function: cubic-bezier(0.333, 0.667, 0.667, 1);
  }
  71% {
    transform: translateY(-1.6px) rotate(-0.8deg);
    animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333);
  }
  82% {
    transform: translateY(0) rotate(0deg);
    animation-timing-function: cubic-bezier(0.333, 0.667, 0.667, 1);
  }
  88% {
    transform: translateY(-0.4px) rotate(0deg);
    animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333);
  }
  94%, 100% { opacity: 1; transform: translateY(0) rotate(0deg); }
}

/* The pile takes the hit as the tape slaps flat, and springs back. */
@keyframes rxtape-give {
  0%, 60% { transform: translateY(0); animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
  66% { transform: translateY(0.9px); }
  100% { transform: translateY(0); }
}

@keyframes rxtape-fall-shadow {
  0% { opacity: 0; transform: scale(1.12); animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333); }
  48% { opacity: 0.4; transform: scale(1); }
  60%, 100% { opacity: 0.5; transform: scale(1); }
}

/* The band it throws on the tape below arrives the moment it's down. */
@keyframes rxtape-cast {
  0%, 52% { opacity: 0; }
  60%, 100% { opacity: 0.55; }
}

@keyframes rxtape-ground {
  0% { opacity: 0.2; transform: scale(1.25, 1.4); animation-timing-function: cubic-bezier(0.333, 0, 0.667, 0.333); }
  60%, 100% { opacity: 1; transform: scale(1); }
}

@keyframes rxtape-dust {
  0% { opacity: 0.9; transform: translateX(0) scale(0.5); }
  100% { opacity: 0; transform: translateX(calc(var(--dir) * 5px)) scale(1.2); }
}

@media (prefers-reduced-motion: reduce) {
  .rxnext:not([hidden]) :is(.rxtape__drop, .rxtape__dust circle, .rxtape__fall, .rxtape__cast, .rxtape__ground) {
    animation: none;
  }
}

.rxnext__go {
  min-width: 14rem;
  margin-top: var(--space-l);
  padding-block: var(--space-m);
  font-size: var(--size-m);
  line-height: var(--line-m);
}

.rxnext__go:active {
  transform: scale(0.97);
}

.rxnext:not([hidden]) > * {
  animation: rx-rise 360ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both;
}

.rxnext:not([hidden]) > :nth-child(2) {
  animation-delay: 50ms;
}

.rxnext:not([hidden]) > :nth-child(3) {
  animation-delay: 100ms;
}

.rxnext:not([hidden]) > :nth-child(5) {
  animation-delay: 150ms;
}

.cfoot[hidden] {
  display: none;
}

.rxask {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* The camera. Off: a calm panel. Practice: clear. The questions: blurred, so
   they know it's on but can't watch themselves. */
.rxcam[hidden] {
  display: none;
}

/* One cell exactly the size of the camera, so what's pinned to its corners stays inside it. */
.rec.rxcam {
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
}

/* A camera that is off is plain grey, with no black edge showing at the rounded corners. */
.rxcam[data-state="off"] {
  background: var(--neutral-3);
}

.rxcam .rxcam__idle .button--secondary {
  background: var(--neutral-1); /* on the grey panel, so it can be seen */
}

@media (hover: hover) {
  .rxcam .rxcam__idle .button--secondary:hover:not(:disabled) {
    background: var(--neutral-4);
  }
}

.rxcam:not([data-state="off"]) .rxcam__idle {
  display: none;
}

.rxcam__idle[hidden] {
  display: none;
}

.rxcam .rec__idle {
  background: var(--neutral-3);
  color: var(--neutral-8);
}

.rxcam .rec__idle p {
  color: var(--neutral-8);
}

/* 20px, not more: a bigger blur on a live, full-size video drops frames while the camera morphs. */
/* Blurred and dimmed: brightness 0.45 means even a white wall or a white shirt turns a
   mid grey, so the white words on top always clear 4.5:1 contrast (WCAG AA). */
.rxcam.is-blurred .rec__video--live {
  filter: blur(20px) brightness(0.45);
  transform: scaleX(-1) scale(1.25);
}




/* In practice the recording dot is not red and not blinking: red means a real answer. */

.rxcam .rec__video--live {
  transition:
    filter 700ms var(--motion-large-easing),
    transform 700ms var(--motion-large-easing);
}

/* Marks on the camera are one thing: a dark, see-through chip with white text, in
   the shape of a squircle rectangle (not a pill). Time left sits top right, there
   from the moment the camera is on; the voice meter sits bottom left while recording. */
.rxchip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-s);
  border-radius: var(--radius-xs);
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  color: var(--neutral-1);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
}

@supports (corner-shape: squircle) {
  .rxchip {
    border-radius: var(--radius-s);
    corner-shape: squircle;
  }
}

.rxchip[hidden] {
  display: none;
}

.rxcam__time {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: end;
  margin: var(--space-m);
}

.rxcam__time i {
  width: var(--space-xs);
  height: var(--space-xs);
  border-radius: var(--radius-full);
  background: var(--neutral-6);
}

.rxcam[data-state="recording"] .rxcam__time i {
  background: var(--error);
  animation: caret-blink 1.1s step-end infinite;
}

/* Bottom left: the voice meter, then the camera and mic pickers. */
.rxcam__dock {
  grid-area: 1 / 1;
  align-self: end;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin: var(--space-m);
}

/* Pickers: small dark chips, just an icon and a chevron (the device's name
   is in the menu). The real select covers the chip, so a tap opens the
   browser's own list. There the whole time the camera is on. */
.rxdevices {
  display: flex;
  gap: var(--space-xs);
}

.rxcam[data-state="off"] .rxdevices {
  display: none;
}

.rxdev {
  position: relative;
  gap: 2px;
  padding-inline: var(--space-xs) 6px;
  cursor: pointer;
  transition: background-color 150ms ease-out;
}

.rxdev[hidden] {
  display: none;
}

.rxdev .icon {
  font-size: 1.125rem;
}

.rxdev__more {
  width: 1rem;
  height: 1rem;
  fill: currentColor;
  opacity: 0.8;
}

.rxdev select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  font-size: 16px; /* no zoom on iPhone when it opens */
}

@media (hover: hover) and (pointer: fine) {
  .rxdev:hover {
    background: color-mix(in srgb, var(--neutral-10) 70%, transparent);
  }
}

.rxdev:has(select:focus-visible) {
  outline: 2px solid var(--neutral-1);
  outline-offset: 2px;
}

.rxcam[data-state="off"] .rxcam__voice {
  display: none;
}

.rxcam__voice .vmeter {
  width: 2rem;
  height: 1.25rem;
  gap: 3px;
}

.rxcam__voice .vmeter i {
  background: var(--neutral-1);
}

/* The question, on the camera itself while answering. */
.rxcam__q {
  grid-area: 1 / 1;
  align-self: center;
  justify-self: center;
  align-items: center;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  max-width: 100%;
  padding: var(--space-xl) var(--space-l);
  color: var(--neutral-1);
  /* A close shadow for the letter edges, a wide one as a soft halo: a second guard on top of the dimmed video. */
  text-shadow:
    0 1px 2px color-mix(in srgb, var(--neutral-10) 60%, transparent),
    0 2px 18px color-mix(in srgb, var(--neutral-10) 55%, transparent);
}

.rxcam__q[hidden] {
  display: none;
}

.rxcam__qlabel,
.rxcam__qtext {
  margin: 0;
}

.rxcam__qlabel {
  color: var(--neutral-1); /* full white: a faded label loses contrast */
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
}

.rxcam__qtext {
  max-width: 24ch; /* short lines read at a glance */
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: clamp(1.75rem, 1.25rem + 2vw, var(--size-xxl)); /* 28px on a phone, up to 48px */
  line-height: 1.15;
  letter-spacing: var(--letter-spacing-xl);
  text-wrap: balance;
}

/* Answering: the heading goes and the camera grows into the space, nearly the whole screen. */
.cstep.is-answering [data-cam-slot] {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.cstep.is-answering .rec.rxcam {
  flex: 1;
  aspect-ratio: auto;
  min-height: 50svh;
}

.rxfoot[hidden] {
  display: none;
}


/* Under the camera: the Practice | Real question switch, then one line saying what this is. */
.rxbelow {
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  margin-top: calc(var(--space-m) * -1); /* close under the camera */
}

.rxprac {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
}

.rxcam__count {
  grid-area: 1 / 1;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--neutral-10) 35%, transparent);
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: 7rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.rxcam__count[hidden],
.rxcam__saved[hidden] {
  display: none;
}

/* The take ends: their reflection fades out to a dark neutral grey (the
   take is done, so showing them would look like it's still recording), and
   the save sits there like the question did: white words with the same soft
   shadow and one thick white bar, filling over the 2 seconds it saves. Then
   the words and bar cross-fade to a big check and "Saved". */
.rxcam__saved {
  grid-area: 1 / 1;
  display: grid;
  place-items: center;
  padding: var(--space-l);
  color: var(--neutral-1);
  text-align: center;
  text-shadow:
    0 1px 2px color-mix(in srgb, var(--neutral-10) 60%, transparent),
    0 2px 18px color-mix(in srgb, var(--neutral-10) 55%, transparent);
  animation: rxsave-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

/* Motion (Emil's rules): it enters, it doesn't pop. It fades in fast
   (ease-out, 220ms) and the words and bar rise 6px just behind it. The bar
   is the one long motion. When it's done, saving leaves through a 2px blur
   while the check grows in from 90% (never from nothing) with a hair of
   overshoot, so the finish feels like a small "done!". */
@keyframes rxsave-in {
  from { opacity: 0; }
}

.rxsave__state {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-m);
  transition:
    opacity 180ms ease-out,
    filter 180ms ease-out,
    transform 360ms cubic-bezier(0.34, 1.4, 0.64, 1);
}

.rxsave__state--saving {
  animation: rxsave-rise 320ms cubic-bezier(0.23, 1, 0.32, 1) 60ms both;
}

@keyframes rxsave-rise {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

.rxsave__state--done {
  gap: var(--space-xs);
  opacity: 0;
  transform: scale(0.9);
}

.rxcam__saved.is-done .rxsave__state--saving {
  opacity: 0;
  filter: blur(2px);
}

.rxcam__saved.is-done .rxsave__state--done {
  opacity: 1;
  transform: none;
  transition-delay: 80ms;
}

.rxsave__title {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.3;
}

/* The big check: white, like the words, with the same soft shadow. */
.rxsave__check {
  color: var(--neutral-1);
  font-size: 4rem;
  line-height: 1;
}

/* While it saves the mic isn't listening, so the voice meter and pickers step away,
   and their reflection fades out: the take is done, so showing them again
   would look like it's still recording. A dark grey stays behind. */
.rxcam:has(.rxcam__saved:not([hidden])) .rxcam__dock {
  visibility: hidden;
}

.rxcam:has(.rxcam__saved:not([hidden])) {
  /* A dark neutral grey: black eased toward the lighter grey, which keeps
     only a trace of warmth instead of the browner --neutral-9. */
  background: color-mix(in oklch, var(--neutral-10) 62%, var(--neutral-5));
}

.rxcam:has(.rxcam__saved:not([hidden])) .rec__video--live {
  opacity: 0;
}

/* The bar: thick, fast at first and easing near the end, like a real upload. */
.rxsave__bar {
  width: min(18rem, 60vw);
  height: 10px;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--neutral-1) 25%, transparent);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--neutral-10) 25%, transparent);
}

.rxsave__bar span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--neutral-1);
  transform-origin: left;
  animation: rxsave-fill var(--save-ms, 2000ms) cubic-bezier(0.3, 0.7, 0.4, 1) 150ms both;
}

@keyframes rxsave-fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.rxcam__bar span {
  transform-origin: left;
}

/* The sacrifice: one composer. The pills pick the kind; the box under them stays the
   same size for every kind, so switching changes what's inside, never the page. */
.give {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.give__kinds {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* The ask, said plainly under the pills, so nobody thinks they have to fill all three. */
.give__hint {
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
}

/* Plain pills, the same as every other pill on the site: full rounding, icon
   beside the name on one horizontal spine. Roomy ends: round things (the
   icon, the count) get 16px from the side, plain text a little more (20px),
   since a word's edge sits further in than a round shape's. */
.give__kind {
  gap: 6px;
  padding-inline: var(--space-m) 20px;
  white-space: nowrap;
}

.give__kind:has(.give__badge:not([hidden])) {
  padding-inline-end: var(--space-m);
}

.give__kind .icon {
  font-size: 1.25rem;
}

/* How many are in it: a small count inside the pill, after the name, so it
   moves with the pill instead of floating on a corner. */
.give__badge {
  display: inline-grid;
  place-items: center;
  min-width: 1.25rem;
  height: 1.25rem;
  margin-inline-start: 2px; /* 8px from the name with the gap, a touch more than icon to name */
  padding-inline: 0.3rem;
  border-radius: var(--radius-full);
  background: var(--neutral-8);
  color: var(--neutral-1);
  font-size: var(--size-xs);
  line-height: 1;
  font-weight: var(--weight-ui-medium);
  font-variant-numeric: tabular-nums;
  animation: give-badge 200ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

@keyframes give-badge {
  from { opacity: 0; transform: scale(0.8); }
}

@media (prefers-reduced-motion: reduce) {
  .give__badge { animation: none; }
}

/* Under the pills, one row on the box's two edges: the ask on the left, the room
   left on the right, both the same quiet grey text. */
.give__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap; /* on the narrowest phones the room left drops under the ask */
  justify-content: space-between;
  gap: var(--space-xxs) var(--space-s);
  margin-top: var(--space-xs);
}

.give__quota {
  flex: none;
  margin: 0;
  color: var(--neutral-8);
  font-size: var(--size-xs); /* the same text style as the ask beside it: one line, one look */
  line-height: var(--line-xs);
  font-variant-numeric: tabular-nums;
}

.give__box {
  position: relative;
  display: grid;
  height: clamp(16rem, 42svh, 24rem);
  overflow: hidden;
  border-radius: var(--radius-l);
  background: var(--neutral-3);
}

.give__pane {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  padding: var(--space-l);
  text-align: center;
  animation: give-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

.give__pane[hidden],
.give [hidden] {
  display: none;
}

@keyframes give-in {
  from {
    opacity: 0;
    filter: blur(4px);
  }
}

/* The same mark as the camera when it's off: a white squircle with the icon. */
.give__mark,
.give__mic {
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  margin-bottom: var(--space-xs);
  border-radius: var(--radius-m);
  background: var(--neutral-1);
  color: var(--neutral-10);
  font-size: 2rem;
  box-shadow: var(--shadow-m);
}

@supports (corner-shape: squircle) {
  .give__mark,
  .give__mic {
    border-radius: 50%;
    corner-shape: squircle;
  }
}

.give__mark .icon,
.give__mic .icon {
  font-size: 1em;
}

.give__title {
  color: var(--neutral-10);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
}

.give__sub {
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
}

/* Photos or videos: empty, the whole box is the picker. Once they pick, each one
   becomes a file card, the way an attachment sits in a message, and the box
   scrolls when there are more than fit. */
.give__pane[data-give="photo"] {
  align-items: stretch;
  padding: 0;
}

.give__drop {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  padding: var(--space-l);
  cursor: pointer;
  transition: background-color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .give__drop:hover {
    background: var(--neutral-4);
  }
}

.give__drop:has(input:focus-visible) {
  outline: 2px solid var(--neutral-9);
  outline-offset: -4px;
  border-radius: var(--radius-l);
}

.give__drop:active .give__mark {
  transform: scale(0.97);
}

.give__mark {
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* The offering: an empty pedestal under a spotlight, the empty photo bobbing
   above the cushion. Drawn like the lock (chunky, flat, a darker band for
   depth, a white highlight, no outlines); stone in the warm greys, the beam in
   the brand yellow, the cushion red velvet. */
.rxoffer {
  width: clamp(5.5rem, 20svh, 8.5rem);
  height: auto;
  margin-bottom: var(--space-xs);
  overflow: visible;
}

.rxoffer__beam { fill: #ffce00; opacity: 0.16; }
.rxoffer__pool { fill: #ffce00; opacity: 0.3; }
.rxoffer__stone { fill: var(--neutral-5); }
.rxoffer__stone-shade { fill: var(--neutral-6); }
.rxoffer__column { fill: var(--neutral-4); }
.rxoffer__shine { fill: #ffffff; opacity: 0.7; }
.rxoffer__velvet { fill: #e0533d; }
.rxoffer__velvet-shade { fill: #c13f2b; }
.rxoffer__sparks { fill: #ffce00; }

.rxoffer__frame {
  fill: var(--neutral-1);
  stroke: var(--neutral-6);
  stroke-width: 2.5;
  stroke-dasharray: 4.5 4;
  stroke-linecap: round;
}

.rxoffer__plus {
  fill: none;
  stroke-linejoin: round;
  stroke: var(--neutral-7);
  stroke-width: 3.2;
  stroke-linecap: round;
}

.rxoffer__slot {
  transform-box: fill-box;
  transform-origin: center;
  animation: rxoffer-bob 2.8s ease-in-out infinite;
}

.rxoffer__sparks path {
  transform-box: fill-box;
  transform-origin: center;
  animation: rxoffer-twinkle 2.8s ease-in-out infinite;
}

.rxoffer__sparks path + path {
  animation-delay: -1.4s;
}

@keyframes rxoffer-bob {
  0%, 100% { transform: translateY(0) rotate(-5deg); }
  50% { transform: translateY(-3px) rotate(-3deg); }
}

@keyframes rxoffer-twinkle {
  0%, 100% { transform: scale(0.6); opacity: 0.5; }
  50% { transform: scale(1); opacity: 1; }
}

.give__drop:active .rxoffer {
  transform: scale(0.97);
}

.rxoffer {
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

@media (prefers-reduced-motion: reduce) {
  .rxoffer__slot,
  .rxoffer__sparks path {
    animation: none;
  }
}

/* Photos, nothing picked yet: the box turns white with a dashed edge, so the
   offering stands out and it reads as the place to drop. */
.give__box:has(.give__pane[data-give="photo"]:not([hidden]) .give__files[hidden]),
.give__box:has(.give__pane[data-give="voice"]:not([hidden])) {
  background: var(--neutral-1);
  border: 2px dashed var(--neutral-5);
}

@media (hover: hover) {
  .give__box .give__drop:hover {
    background: var(--neutral-2);
  }
}

.give__box.is-over:has(.give__pane[data-give="photo"]:not([hidden])) {
  background: var(--neutral-3);
  border-color: var(--neutral-6);
}

/* Dragging files over the box: it lights up a step, so it's clearly the place to drop. */
.give__box.is-over {
  background: var(--neutral-4);
}

/* With files in it, the box shrinks to fit them (no big empty space under a
   row of small tiles), up to its usual height, then scrolls. */
.give__box:has(.give__files:not([hidden])) {
  height: auto;
  max-height: clamp(16rem, 42svh, 24rem);
}

.give__files {
  padding: var(--space-m);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Small file tiles in rows from the top left, like attachments in a message.
   Every tile is the same width; the + tile after them is the next slot. */
.give__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
  gap: var(--space-m) var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

.file {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  animation: give-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

.file__thumb {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  margin-bottom: var(--space-xs);
  overflow: hidden;
  border-radius: var(--radius-s);
  background: var(--neutral-4);
  box-shadow: 0 1px 2px #0000000f;
}

.file__thumb img,
.file__thumb video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A video shows its first frame with a small play mark, so it reads as a video. */
.file__play {
  position: absolute;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--neutral-10) 55%, transparent);
  color: var(--neutral-1);
  font-size: 1.25rem;
}

.file__name,
.file__meta {
  overflow: hidden;
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.file__name {
  color: var(--neutral-10);
  font-weight: var(--weight-ui-medium);
}

.file__meta {
  color: var(--neutral-8);
  font-variant-numeric: tabular-nums;
}

/* Remove: a small dark round button on the thumbnail's corner. Its hit area is
   bigger than it looks (the ::before), so it's easy to tap. */
.file__remove {
  position: absolute;
  top: var(--space-xxs);
  right: var(--space-xxs);
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--neutral-10) 60%, transparent);
  color: var(--neutral-1);
  font-size: 1rem;
  cursor: pointer;
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.file__remove::before {
  content: "";
  position: absolute;
  inset: -0.5rem;
}

.file__remove .icon {
  font-size: 1em;
}

.file__remove:active {
  transform: scale(0.92);
}

.file__remove:focus-visible {
  outline: 2px solid var(--neutral-10);
  outline-offset: 2px;
}

/* The + tile: just the empty square, a step lighter than the box, with a plus. */
.file--add {
  cursor: pointer;
}

.file--add .file__thumb {
  background: var(--neutral-1);
  box-shadow: none;
  color: var(--neutral-8);
  font-size: 1.75rem;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    color var(--motion-duration) var(--motion-easing),
    transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.file--add .icon {
  font-size: 1em;
}

@media (hover: hover) {
  .file--add:hover .file__thumb {
    color: var(--neutral-10);
  }
}

.file--add:active .file__thumb {
  transform: scale(0.96);
}

.file--add:has(input:focus-visible) .file__thumb {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Voice note: the mark is the button. Recording, it turns dark with a stop square. */
.give__mic {
  border: 0;
  cursor: pointer;
  transition:
    transform 160ms cubic-bezier(0.23, 1, 0.32, 1),
    background-color 200ms ease,
    color 200ms ease;
}

.give__mic:active {
  transform: scale(0.95);
}

.give__mic:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 3px;
}

/* Voice note states (ready, recording, recorded) share the box's center. */
.voice__state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  width: 100%;
  animation: give-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

.voice__state[hidden] {
  display: none;
}

/* Recording: the friend's voice meter, bigger and dark, then the time and Stop. */
.vmeter--big {
  width: 4.5rem;
  height: 4rem;
  gap: 6px;
  margin-bottom: var(--space-s);
}

.vmeter--big i {
  background: var(--neutral-9);
  transition: transform 80ms linear;
}

.voice__time {
  font-size: var(--size-xl);
  line-height: var(--line-xl);
  font-variant-numeric: tabular-nums;
}

.voice__stop {
  margin-top: var(--space-s);
}

.voice__square {
  width: 0.7em;
  height: 0.7em;
  border-radius: 2px;
  background: currentColor;
}

/* Recorded: a player pill (play, progress, time, remove) on the box's grey, the
   same build as the photo cards' remove and the video player's line. */
.vnote {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  width: min(100%, 22rem);
  padding: var(--space-xs);
  padding-right: var(--space-s);
  border-radius: var(--radius-full);
  background: var(--neutral-3);
}

.vnote__play {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--neutral-1);
  color: var(--neutral-10);
  box-shadow: 0 1px 2px #0000000f;
  font-size: 1.5rem;
  cursor: pointer;
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.vnote__play .icon,
.vnote__remove .icon {
  font-size: 1em;
}

.vnote__play:active,
.vnote__remove:active {
  transform: scale(0.92);
}

.vnote__track {
  flex: 1;
  height: 4px;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--neutral-5);
}

.vnote__track span {
  display: block;
  height: 100%;
  background: var(--neutral-10);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 250ms linear;
}

.vnote__time {
  flex: none;
  min-width: 2.25rem;
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.vnote__remove {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--neutral-8);
  font-size: 1.125rem;
  cursor: pointer;
  transition:
    background-color var(--motion-duration) var(--motion-easing),
    transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

.vnote__remove::before {
  content: "";
  position: absolute;
  inset: -0.5rem;
}

@media (hover: hover) {
  .vnote__remove:hover {
    background: var(--neutral-4);
    color: var(--neutral-10);
  }
}

.vnote__play:focus-visible,
.vnote__remove:focus-visible {
  outline: 2px solid var(--neutral-10);
  outline-offset: 2px;
}

.voice__again {
  margin-top: var(--space-s);
}

/* Voice, ready: built like the photo picker, the whole box is the button and
   the floating frame holds a mic instead of a +. */
.give__pane--voice {
  align-items: stretch;
  padding: 0;
}

.give__pane--voice > .voice__state {
  flex: 1;
  justify-content: center;
  padding: var(--space-l);
}

button.give__drop {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: center;
}

button.give__drop:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: -4px;
  border-radius: var(--radius-l);
}

.rxoffer__glyph { fill: var(--neutral-7); }

/* The mic's lines, 30% lighter than the + so it doesn't look heavy. */
.rxoffer__plus--mic {
  stroke-width: 2.24;
}

/* A few words: the box is the field. */
.give__pane--words {
  align-items: stretch;
  padding: 0;
}

.give__words {
  flex: 1;
  width: 100%;
  padding: var(--space-l);
  border: 0;
  background: transparent;
  color: var(--neutral-10);
  font: inherit;
  font-size: var(--size-l);
  line-height: var(--line-l);
  text-wrap: pretty;
  resize: none;
}

.give__words::placeholder {
  color: var(--neutral-7);
}

.give__words:focus {
  outline: none;
}

.give__box:has(.give__words:focus-visible) {
  box-shadow: inset 0 0 0 2px var(--neutral-9);
}

.give__count {
  align-self: flex-end;
  padding: 0 var(--space-l) var(--space-m);
  color: var(--neutral-7);
  font-size: var(--size-s);
  line-height: var(--line-s);
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .give__pane {
    animation: none;
  }
}

/* Sealed: a treasure chest, drawn after Duolingo's shape language (few bold
   rounded shapes, flat color, one light and one dark tone per material, no
   outlines). Its own small palette, all warm: wood, the brand yellow as gold,
   a deep brown inside, a warm grey for the shackle.
   The resting state is the end state (closed and locked), so with no
   animation, or reduced motion, it simply shows sealed. .is-playing runs the
   story once:
     0ms          the lid hovers high above the open chest
     120ms        the tapes drop in one by one, 240ms apart (left, right,
                  then the middle one in front): each appears just under
                  the lid, lifts a hair, then falls in and sinks out of sight
     1150ms       the last one is in; the lid drops, accelerating like a
                  real lid (ease-in on purpose: it is gravity, not UI)
     ~1560ms      slam: the chest squashes, dust puffs, impact lines, and the
                  text below is knocked down and springs back up
     1850ms       the lock drops onto the hasp and settles
     2360ms       the shackle snaps shut: a small squash and a sparkle */
.chest {
  --wood: #cf7a34;
  --wood-light: #e59a52;
  --wood-dark: #a55a22;
  --inside: #5a2e12;
  --band: #86431a; /* the straps: darker than the wood, so the gold lock is the one bright thing */
  --gold: var(--color-1);
  --gold-light: #fff0a3;
  --gold-dark: #f0a800;
  /* The latch and shackle are silver so the gold lock stands out against
     them; a warm silver, so it doesn't go cold next to the wood. */
  --silver: #dcd9d1;
  --silver-dark: #b3ae9f;
  --metal: var(--silver-dark);
  --slam: 1560ms;
  display: block;
  width: 11rem;
  height: auto;
  margin-bottom: var(--space-s);
  overflow: visible;
}

.chest .c-wood { fill: var(--wood); }
.chest .c-wood-light { fill: var(--wood-light); }
.chest .c-wood-dark { fill: var(--wood-dark); }
.chest .c-inside { fill: var(--inside); }
.chest .c-gold { fill: var(--gold); }
.chest .c-gold-light { fill: var(--gold-light); }
.chest .c-gold-dark { fill: var(--gold-dark); }
.chest .c-silver { fill: var(--silver); }
.chest .c-silver-dark { fill: var(--silver-dark); }
/* The tapes are black and white, the same as the pile of tapes between questions. */
.chest .c-band { fill: var(--band); }
.chest .c-shine { fill: #fff; opacity: 0.35; }
.chest .c-tape { fill: #45403c; }
.chest .c-tape-paper { fill: #f6f3ec; }
.chest .c-tape-window { fill: #1d1a19; }
.chest .c-tape-hub { fill: #f6f3ec; }
/* Secondary details stay quiet so the big shapes read first. */
.chest .c-detail { fill: var(--gold-dark); opacity: 0.45; }
.chest .c-soft { opacity: 0.55; }
.chest .c-ground { fill: color-mix(in oklch, var(--wood-dark) 14%, transparent); }

.chest .c-metal {
  fill: none;
  stroke: var(--metal);
  stroke-width: 5;
  stroke-linecap: round;
}

.chest__lines path {
  fill: none;
  stroke: var(--neutral-5);
  stroke-width: 3.5;
  stroke-linecap: round;
}

.chest__dust circle {
  fill: var(--neutral-4);
}

/* Every moving part turns around its own natural point. */
.chest :is(.chest__all, .chest__lid, .chest__lock, .chest__click, .chest__shackle, .chest__lines) {
  transform-box: view-box;
}

.chest__all { transform-origin: 100px 166px; }
.chest__lid { transform-origin: 100px 86px; }
.chest__click { transform-origin: 100px 110px; }
.chest__dust circle,
.chest__spark { transform-box: fill-box; transform-origin: center; }

/* Resting state: only the closed, locked chest shows. */
.chest__tapes,
.chest__dust,
.chest__lines,
.chest__spark {
  opacity: 0;
}

.chest.is-playing .chest__tapes {
  opacity: 1;
}

.chest__tape {
  transform-box: view-box;
}

.chest.is-playing .chest__tape {
  animation: chest-tape-in 560ms calc(120ms + var(--k) * 240ms) both;
}

.chest.is-playing .chest__lid {
  animation: chest-lid 520ms 1150ms both;
}

.chest.is-playing .chest__all {
  animation: chest-squash 440ms var(--slam) both;
}

.chest.is-playing .chest__dust {
  opacity: 1;
}

.chest.is-playing .chest__dust circle {
  animation: chest-dust 620ms cubic-bezier(0.23, 1, 0.32, 1) var(--slam) both;
}

.chest.is-playing .chest__dust circle:nth-child(-n + 2) { --dir: -1; }
.chest.is-playing .chest__dust circle:nth-child(n + 3) { --dir: 1; }

.chest.is-playing .chest__lines--left { --dir: -1; }
.chest.is-playing .chest__lines--right { --dir: 1; }

.chest.is-playing .chest__lines {
  animation: chest-lines 380ms cubic-bezier(0.23, 1, 0.32, 1) var(--slam) both;
}

.chest.is-playing .chest__lock {
  animation: chest-lock 460ms 1850ms both;
}

.chest.is-playing .chest__shackle {
  animation: chest-shackle 130ms cubic-bezier(0.55, 0, 1, 0.45) 2360ms both;
}

.chest.is-playing .chest__click {
  animation: chest-click 260ms cubic-bezier(0.23, 1, 0.32, 1) 2490ms both;
}

.chest.is-playing .chest__spark {
  animation: chest-spark 640ms cubic-bezier(0.23, 1, 0.32, 1) 2500ms both;
}

.chest.is-playing .chest__spark--small {
  animation-delay: 2580ms;
}

/* One tape going in: it fades in just under the lid, lifts a hair (the
   anticipation), then falls, gaining speed, down behind the chest's front
   until it's out of sight. It stays there, so it's inside when the lid shuts. */
@keyframes chest-tape-in {
  0% {
    opacity: 0;
    transform: translateY(-28px) scale(0.96);
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
  25% {
    opacity: 1;
    transform: translateY(-34px) scale(1);
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.35);
  }
  100% {
    opacity: 1;
    transform: translateY(48px) scale(1);
  }
}

/* Hovering open, then it drops (gaining speed), hits, bounces up a hair
   and settles. */
@keyframes chest-lid {
  0% {
    transform: translateY(-92px) rotate(-7deg); /* high enough that the tapes pass under it */
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.35);
  }
  78% {
    transform: translateY(0) rotate(0deg);
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
  88% {
    transform: translateY(-4px) rotate(-1deg);
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.35);
  }
  100% { transform: translateY(0) rotate(0deg); }
}

@keyframes chest-squash {
  0% { transform: scale(1, 1); }
  22% { transform: scale(1.1, 0.86); }
  55% { transform: scale(0.97, 1.04); }
  100% { transform: scale(1, 1); }
}

@keyframes chest-dust {
  0% { opacity: 0; transform: translateX(0) scale(0.4); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translateX(calc(var(--dir) * 12px)) scale(1.3); }
}

@keyframes chest-lines {
  0% { opacity: 0; transform: translate(0, 0); }
  25% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(var(--dir) * 6px), -3px); }
}

/* Drops in from above, lands, a small bounce, still. */
@keyframes chest-lock {
  0% {
    opacity: 0;
    transform: translateY(-46px);
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.35);
  }
  15% { opacity: 1; }
  62% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
  80% {
    transform: translateY(-5px);
    animation-timing-function: cubic-bezier(0.55, 0, 0.9, 0.35);
  }
  100% { opacity: 1; transform: translateY(0); }
}

@keyframes chest-shackle {
  from { transform: translateY(-7px); }
  to { transform: translateY(0); }
}

@keyframes chest-click {
  0% { transform: scale(1, 1); }
  35% { transform: scale(1.08, 0.92); }
  100% { transform: scale(1, 1); }
}

@keyframes chest-spark {
  0% { opacity: 0; transform: scale(0.4) rotate(-20deg); }
  35% { opacity: 1; transform: scale(1.1) rotate(0deg); }
  100% { opacity: 0; transform: scale(0.8) rotate(10deg); }
}

/* Leaving a step (answer.js fadeTo): out quicker than the next comes in. */
.cstep.is-leaving {
  animation: step-out 200ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

@keyframes step-out {
  to {
    opacity: 0;
    transform: translateY(calc(-1 * var(--space-xs)));
  }
}

/* Sealing: the beat before the chest. Centered like Sealed, so the hand-over
   keeps everything on the same middle line. */
.sealing {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-block: auto;
  text-align: center;
}

/* A tape-shaped rectangle: a faint track, and a line tracing round it with a
   softer tail behind (after loading.dev's Trace). Constant motion: linear. */
.trace {
  display: block;
  width: 5.5rem;
  height: auto;
  margin-bottom: var(--space-l);
  overflow: visible;
}

.trace__track,
.trace__line {
  fill: none;
  stroke-width: 4;
}

.trace__track { stroke: var(--neutral-3); }
.trace__reel { fill: none; stroke: var(--neutral-3); stroke-width: 3.5; } /* hollow rings: reels, not eyes */

.trace__line {
  stroke: var(--neutral-10);
  stroke-linecap: round;
  stroke-dasharray: 14 86;
  animation: trace 1.4s linear infinite;
  animation-delay: -0.22s; /* the head runs just ahead of its tail */
}

.trace__line--tail {
  stroke: var(--neutral-6);
  stroke-dasharray: 30 70;
  animation-delay: 0s;
}

@keyframes trace {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: -100; }
}

@media (prefers-reduced-motion: reduce) {
  .trace__line {
    animation: none;
  }
}

/* The sealed screen is one centered moment, in the middle of the screen:
   chest, title, sentence. */
[data-step="sealed"] .done {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-block: auto;
  text-align: center;
}

/* The sacrifice intro is one short line; it only wraps on phones. */
@media (min-width: 601px) {
  [data-step="sacrifice"] .cstep__text {
    white-space: nowrap;
  }
}

[data-step="sealed"] .cstep__text {
  max-width: 26em;
  text-wrap: balance; /* short text: even lines, no word left alone at the end */
}

[data-step="sealed"] .cstep__text > span {
  display: block;
}

/* The slam comes down from above, so it travels down the screen: the title
   is knocked down and springs back up (a hair past, then settles), and the
   sentence follows a beat later, a touch less. Each block moves as one, no
   letter by letter. */
.is-jolted .done > :is(.cstep__title, .cstep__text) {
  animation: text-jolt 520ms var(--at) both;
}

.is-jolted .done > .cstep__title { --amp: 12px; --at: 1560ms; }
.is-jolted .done > .cstep__text { --amp: 7px; --at: 1610ms; }

@keyframes text-jolt {
  0% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
  22% {
    transform: translateY(var(--amp));
    animation-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
  }
  62% {
    transform: translateY(calc(var(--amp) * -0.3));
    animation-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
  }
  100% { transform: translateY(0); }
}

/* The camera: big, widescreen where there's room, upright on a phone, so it fits
   how the phone is held. The text keeps a readable width on the same left edge. */
.rx-page {
  --create-col: 52rem; /* a wider column than setup, for the camera */
}

.rx-page .cstep__head {
  max-width: 40rem;
  gap: var(--space-s); /* a 36px title needs more air than 8px above its sentence */
}

/* The sentence under the title keeps a readable measure (about 65 characters),
   narrower than the title, so it doesn't run long under it. */
.rx-page .cstep__head > .cstep__text {
  max-width: 34em;
}

.rec.rxcam {
  aspect-ratio: 16 / 9;
}

.rxcam > :not(video) {
  position: relative;
  z-index: 1; /* above the (mirrored) video, which would otherwise cover them and catch clicks */
}

/* Full-camera overlays (the 3, 2, 1 and "Saved") fill the frame, so what's inside is truly centered. */
.rxcam > .rxcam__count,
.rxcam > .rxcam__saved {
  position: absolute;
  inset: 0;
}

/* "Saved" covers the whole camera, chips included (it comes earlier in the markup, so it needs the lift). */
.rxcam > .rxcam__saved {
  z-index: 2;
}


.rxcam__idle .button {
  margin-top: var(--space-xs);
}

@media (max-width: 600px) {
  .rec.rxcam {
    aspect-ratio: 4 / 5; /* upright, the full width of the column, short enough to leave the caption above the button */
    /* ...and never taller than what's left of the screen once the header, the
       words above and the button below are counted, so the camera's bottom
       row (voice meter, pickers) and the button are both on screen without
       scrolling. On a tall phone the 4:5 shape wins; on a short one it
       crops a little shorter. */
    width: 100%; /* stays full width; only the height gives */
    max-height: max(15rem, calc(100svh - 20rem));
  }
}

/* Phones: the friend's side keeps its top compact, so each screen's button is
   in view without scrolling. The bar holding Back is slimmer (and folds away
   when there is no Back), the page starts closer to it, and the space between
   the heading, the camera and the note is tighter. */
@media (max-width: 600px) {
  .rx-page .cbar {
    padding-block: var(--space-xs);
  }

  .rx-page .cbar:not(:has(.cbar__btn:not([hidden]))) {
    padding-block: 0;
  }

  .rx-page .create {
    padding-top: var(--space-s);
  }

  .rx-page .cstep {
    gap: var(--space-m);
  }

  .rx-page .cfoot {
    padding-top: var(--space-s);
  }

  /* While answering the heading is gone, so the camera can take that room. */
  .rx-page .is-answering .rec.rxcam {
    max-height: max(15rem, calc(100svh - 13rem));
  }

  /* The sacrifice: the composer gives a little so "Seal it in" and "Skip
     this" stay on screen under the pills. */
  .rx-page .give__box {
    height: clamp(12rem, 100svh - 29rem, 24rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .rx-pop,
  .rxcard--from-right,
  .rxcard--from-left,
  .rxcam__saved,
  .rxsave__state,
  .rxsave__bar span,
  .chest *,
  .wave > span {
    animation: none !important;
  }
}

/* ---------- The friend's practice and questions: motion and button width ---------- */
.rx-page {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

/* Every main button in the friend's flow is one size: a button, not a bar across the
   page, centered at the bottom (the one between questions sits under its words, same size). */
.rx-page .cfoot__go,
.rx-page .rxnext__go {
  flex: none;
  width: auto;
  min-width: 14rem;
  align-self: center;
  margin-top: 0;
  padding-inline: var(--space-xl);
  padding-block: var(--space-m);
  font-size: var(--size-m);
  line-height: var(--line-m);
  overflow: hidden;
}

.rx-page .rxnext__go {
  margin-top: var(--space-l);
}

.rx-page .cfoot__go:active:not(:disabled),
.rx-page .rxnext__go:active:not(:disabled) {
  transform: scale(0.97);
}

/* The cards: back sits right next to the main button, and the pair is centered. */
.rx-page .rxfoot {
  align-self: center;
}

.rx-page .rxfoot__back {
  align-self: stretch; /* as tall as the main button */
}

/* One width for the cards' main button: its longest label is stacked
   invisibly under the real one (answer.js), so nothing moves between cards. */
.rxsize {
  display: inline-grid;
}

.rxsize > span {
  grid-area: 1 / 1;
}

.rxsize__ghost {
  visibility: hidden;
}

/* The words on that button roll: one set leaves through the top as the next comes from below. */
.rxroll {
  display: inline-grid;
  overflow: hidden;
}

.rxroll > span {
  grid-area: 1 / 1;
  text-align: center;
}

.rxreplay {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  fill: currentColor;
  transition: transform 300ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1));
}

.button:active .rxreplay {
  transform: rotate(-120deg);
}

/* Layout changes are one move. The camera is one object the whole time: its box morphs
   between sizes and its picture is cropped to that box, never stretched, so it reads as
   the same camera growing, not a new one swapping in. The parts around it (the heading,
   the line under it, the button, the between-questions words) travel with it instead of
   jumping to their new place. */
::view-transition {
  --rx-morph: 420ms;
  --rx-morph-ease: cubic-bezier(0.77, 0, 0.175, 1); /* moving on screen: ease-in-out */
  --rx-out: cubic-bezier(0.23, 1, 0.32, 1); /* coming and going: ease-out */
}

.rxcam {
  view-transition-name: rxcam;
}

[data-step="practice"] #practice-head {
  view-transition-name: rxhead;
}

#rxprac {
  view-transition-name: rxprac;
}

[data-step="practice"] .cfoot,
#q-foot {
  view-transition-name: rxgo;
}

#q-breather {
  view-transition-name: rxnext;
}

::view-transition-group(root) {
  animation: none;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-group(rxcam),
::view-transition-group(rxhead),
::view-transition-group(rxprac),
::view-transition-group(rxgo),
::view-transition-group(rxnext) {
  animation-duration: var(--rx-morph);
  animation-timing-function: var(--rx-morph-ease);
}

/* The box clips its picture with the camera's own corners, and the picture fills the box
   by cropping (cover), the way the video itself does. Without this the picture keeps its
   starting shape and spills out of, or floats inside, the box while it grows. */
::view-transition-group(rxcam) {
  overflow: clip;
  border-radius: var(--radius-l);
}

::view-transition-old(rxcam),
::view-transition-new(rxcam) {
  block-size: 100%;
  object-fit: cover;
}

/* Anything on screen before and after is one picture that travels, never two that
   crossfade. The new picture is live, so the camera keeps moving while it morphs. */
html[data-morph="grow"]::view-transition-old(rxcam):not(:only-child),
::view-transition-old(rxhead):not(:only-child),
::view-transition-old(rxprac):not(:only-child),
::view-transition-old(rxgo):not(:only-child),
::view-transition-old(rxnext):not(:only-child) {
  display: none;
}

::view-transition-new(rxcam):not(:only-child),
::view-transition-new(rxhead):not(:only-child),
::view-transition-new(rxprac):not(:only-child),
::view-transition-new(rxgo):not(:only-child),
::view-transition-new(rxnext):not(:only-child) {
  animation: none;
}

/* reveal: the old view closes in on its middle, showing what is under it. */
html[data-morph="reveal"]::view-transition-old(rxcam) {
  animation: rx-close 360ms var(--rx-out) both;
}

@keyframes rx-close {
  from {
    clip-path: inset(0 round var(--radius-l));
  }
  to {
    clip-path: inset(50% round var(--radius-l));
  }
}

/* The camera arriving or leaving on its own (around a question): it settles in from a
   touch smaller, and leaves the same way, faster. Nothing appears from nothing. */
::view-transition-new(rxcam):only-child {
  animation: rx-arrive var(--rx-morph) var(--rx-out) both;
}

::view-transition-old(rxcam):only-child,
::view-transition-old(rxnext):only-child {
  animation: rx-leave 220ms var(--rx-out) both;
}

/* The between-questions words bring their own rise (see .rxnext), so the picture just shows. */
::view-transition-new(rxnext):only-child {
  animation: none;
}

@keyframes rx-arrive {
  from {
    opacity: 0;
    transform: scale(0.96);
    filter: blur(4px);
  }
}

@keyframes rx-leave {
  to {
    opacity: 0;
    transform: scale(0.96);
    filter: blur(4px);
  }
}

/* The heading only slides when it actually goes or comes back; when it stays, it just moves. */
::view-transition-old(rxhead):only-child {
  animation: rx-head-out 260ms var(--rx-out) both;
}

::view-transition-new(rxhead):only-child {
  animation: rx-head-in 360ms var(--rx-out) both;
}

@keyframes rx-head-out {
  to {
    transform: translateY(-20px);
    opacity: 0;
  }
}

@keyframes rx-head-in {
  from {
    transform: translateY(-20px);
    opacity: 0;
  }
}

/* Marks inside the camera grow from their own corner; the question and the panel's
   parts rise in one after another. */
.rxcam__time:not([hidden]) {
  transform-origin: top right;
  animation: rx-pop 260ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both;
}

.rxcam__voice {
  transform-origin: bottom left;
  animation: rx-pop 260ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both;
}

@keyframes rx-pop {
  from {
    transform: scale(0.8);
    opacity: 0;
  }
}

.rxcam__q:not([hidden]) {
  animation: rx-rise 320ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both;
}

.rxcam__idle:not([hidden]) > * {
  animation: rx-rise 360ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both;
}

.rxcam__idle:not([hidden]) > :nth-child(2) {
  animation-delay: 50ms;
}

.rxcam__idle:not([hidden]) > :nth-child(3) {
  animation-delay: 100ms;
}

@keyframes rx-rise {
  from {
    transform: translateY(14px) scale(0.96);
    opacity: 0;
  }
}

/* The blur eases in and out with the same curve; the reflection fades
   out while an answer saves. */
.rxcam .rec__video--live {
  transition:
    filter 450ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)),
    transform 450ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)),
    opacity 300ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .rxcam__q,
  .rxcam__time,
  .rxcam__voice,
  .rxcam__idle > * {
    animation: none !important;
  }
}

/* Pricing: one plan, one wide raised card as wide as the privacy panel above
   it (the title sits on the container edge, over the card's edge). Two
   columns on one top edge and one bottom edge. Left, the result: the plan,
   the total and what it's made of. Right, the choice and the act: the
   question, the slider, the open year, and the button pinned to the bottom,
   where the decision ends, level with the last line of the breakdown.
   Phones keep only what explains it. */
.price {
  display: grid;
  /* The privacy panel's own grid: its inset, its gap, and the art column on
     the right, so the plan sits under that copy and the slider under its card. */
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--art-col));
  grid-template-areas:
    "plan calc"
    "plan action";
  grid-template-rows: auto 1fr;
  align-items: start;
  column-gap: var(--section-inner);
  row-gap: var(--space-l);
  padding: clamp(var(--space-xl), 0.7rem + 4.9vw, var(--inset)) var(--inset);
  border-radius: var(--radius-xl);
  background: var(--neutral-1);
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--neutral-9) 7%, transparent),
    0 1px 2px color-mix(in oklch, var(--neutral-9) 6%, transparent),
    0 8px 24px color-mix(in oklch, var(--neutral-9) 9%, transparent);
}

@supports (corner-shape: squircle) {
  .price {
    border-radius: calc(var(--radius-xl) * 1.4);
    corner-shape: squircle;
  }
}

.price__plan {
  grid-area: plan;
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}

.price__name {
  margin: 0;
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--type-item);
  line-height: 1.2;
  letter-spacing: var(--letter-spacing-m);
}

/* Desktop says only "Pay once for each capsule."; the slider and the
   breakdown beside it show the rest. Phones, without the breakdown, get the
   whole sentence. */
.price__lede-more {
  display: none;
}

.price__lede {
  color: var(--neutral-8);
  font-size: var(--size-m);
  line-height: var(--line-m);
  letter-spacing: var(--letter-spacing-m);
}

.price__total {
  display: flex;
  margin-top: var(--space-s);
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: var(--space-s);
}

.price__amount {
  font-family: var(--font-brand);
  font-weight: var(--weight-brand-heavy);
  font-size: var(--size-xxl);
  line-height: 1;
  letter-spacing: var(--letter-spacing-xxl);
  font-variant-numeric: tabular-nums;
  color: var(--neutral-10);
}

.price__for {
  color: var(--neutral-8);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
}

.price__note {
  margin-top: calc(var(--space-m) * -0.5);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.price__action {
  grid-area: action;
  align-self: end;
  width: 100%;
  max-width: var(--art-col);
  padding-block: var(--space-m);
}

.price__calc {
  grid-area: calc;
  position: relative; /* the bottle's corner */
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
}

.price__label {
  color: var(--neutral-10);
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
}

/* Setup's own slider, with its wine bottle and word (phones get the bare
   track, below). The bottle is tucked into the column's top-right corner,
   level with the question, at two thirds of setup's size, so it no longer
   sets the readout's height: "3 years" sits right under the question. The
   min-height holds its place before the script arrives, so nothing jumps. */
.price .wine {
  position: absolute;
  top: 0;
  right: 0;
  width: calc(4.75rem * 2 / 3);
  height: calc(7.125rem * 2 / 3);
}

.price__slider {
  min-height: 7.5rem; /* the mounted slider, with the bottle out of its flow */
}

/* Desktop: the bottle 1.3x bigger, so its details read. The readout row grows
   just enough for the track to clear it; the space comes out of the gap above
   the button, so both columns still end on one line. */
@media (min-width: 901px) {
  .price {
    --wine-h: calc(7.125rem * 2 / 3 * 1.3);
  }

  .price .wine {
    width: calc(4.75rem * 2 / 3 * 1.3);
    height: var(--wine-h);
  }

  .price .years__head {
    align-items: flex-start;
    min-height: calc(var(--wine-h) - var(--line-m) - 2 * var(--space-s));
  }

  .price__slider {
    min-height: 8.5rem;
  }
}

.price__date {
  min-height: var(--line-s);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

/* What the total is made of, right under it: the checkout's own lines, as
   wide as the button so the amounts end on its edge. */
.price__lines {
  max-width: var(--art-col);
  display: flex;
  flex-direction: column;
  gap: var(--space-s);
  margin: var(--space-s) 0 0;
  padding: var(--space-m) 0 0;
  list-style: none;
  box-shadow: inset 0 1px 0 var(--neutral-3);
  color: var(--neutral-8);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.price__lines li {
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: var(--space-m);
}

.price__lines li > span:first-child {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
}

.price__lines li > span:last-child {
  color: var(--neutral-10);
  font-variant-numeric: tabular-nums;
}

/* Stacked: the plan, then the price, then the slider, then the lines, and
   the button last. */
@media (max-width: 900px) {
  .price {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "plan"
      "calc"
      "action";
    grid-template-rows: none;
    row-gap: var(--space-xl);
    padding: var(--space-l);
  }

  .price__action {
    margin-top: var(--space-s);
  }
}

/* "Show breakdown": phones only, on the "Plus taxes." line. */
.price__more {
  display: none;
}

/* Phones: only what explains it at a glance, in one column: the plan, the
   price, then the slider and the way in. The breakdown waits behind "Show
   breakdown" on the "Plus taxes." line and opens right under it, following
   the slider like everything else. */
@media (max-width: 600px) {
  .price {
    grid-template-areas: none;
    row-gap: var(--space-m);
  }

  .price__plan,
  .price__calc {
    display: contents;
  }

  .price__name { order: 1; }
  .price__lede { order: 2; }
  .price__total { order: 3; margin-top: 0; }
  .price__note { order: 4; }
  .price__lines { order: 5; }
  .price__label { order: 6; margin-top: var(--space-m); }
  .price__slider { order: 7; }
  .price__date { order: 8; }
  .price__action { order: 9; grid-area: auto; margin-top: var(--space-m); }

  .price__lede-more {
    display: inline;
  }

  .price__note {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
  }

  /* Quieter than a usual .link: the note's own weight and grey, with a faint
     thin underline, so it reads as part of the line, not a button. */
  .price__more {
    display: inline;
    padding-inline: var(--space-xxs);
    color: var(--neutral-7);
    font-weight: var(--weight-ui-regular);
    text-decoration-color: var(--neutral-5);
    text-decoration-thickness: 1px;
  }

  .price .years__head {
    display: none;
  }

  .price__slider {
    min-height: 4.5rem;
  }

  .price__lines {
    display: none;
    margin: 0;
  }

  .price[data-open] .price__lines {
    display: flex;
    transition: opacity 200ms ease-out, transform 200ms cubic-bezier(0.23, 1, 0.32, 1);

    @starting-style {
      opacity: 0;
      transform: translateY(-4px);
    }
  }
}

@media (max-width: 600px) and (prefers-reduced-motion: reduce) {
  .price[data-open] .price__lines {
    transition: none;
  }
}

/* Footer: on the 1200px container like the sections above. The wordmark on
   the left, the links on the right (Create your capsule first); a hairline
   over it all. Under it, full width,
   the pile of keepsakes (keepsake-pile.js). */
.footer {
  width: 100%;
  margin-top: auto;
}

.footer__inner {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding: var(--section-inner) var(--page-gutter);
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--grid-gap);
  align-items: start;
}

.footer__inner::before {
  content: "";
  grid-column: 1 / -1;
  height: 1px;
  margin-bottom: var(--section-inner);
  box-shadow: inset 0 1px 0 var(--neutral-4);
}

/* Left: the wordmark with the small print under it. */
.footer__brand {
  grid-column: 1 / span 4;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-m);
}

.footer__mark {
  font-size: var(--type-display);
  line-height: 1.1;
  letter-spacing: var(--letter-spacing-xl);
}

.footer__more {
  grid-column: 9 / span 4;
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.footer__links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-s);
}

.footer__links a,
.footer__links button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--neutral-9);
  font: inherit;
  font-size: var(--size-m);
  line-height: var(--line-m);
  font-weight: var(--weight-ui-medium);
  text-decoration: none;
  cursor: pointer;
  border-radius: var(--radius-xs);
  transition: color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .footer__links a:hover,
  .footer__links button:hover {
    color: var(--neutral-10);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}

.footer__links a:focus-visible,
.footer__links button:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* The small print, together on one line: ©, Privacy Policy, Terms. */
.footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-m);
  row-gap: var(--space-xxs);
  color: var(--neutral-7);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}

.footer__legal a {
  border-radius: var(--radius-xs);
  color: inherit;
  text-decoration: none;
  transition: color var(--motion-duration) var(--motion-easing);
}

@media (hover: hover) {
  .footer__legal a:hover {
    color: var(--neutral-9);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}

.footer__legal a:focus-visible {
  outline: 2px solid var(--neutral-9);
  outline-offset: 2px;
}

/* Under the small print: this is a concept, nothing is saved. */
.footer__concept {
  margin: 0;
  max-width: 36ch;
  color: var(--neutral-7);
  font-size: var(--size-xs);
  line-height: var(--line-xs);
  letter-spacing: var(--letter-spacing-xs);
}

/* The pile: full width along the bottom of the page. The page still scrolls
   over it on touch; a mouse shoves and throws. A soft mask fades its top
   quarter to nothing, so keepsakes drift in from above (and fade out when
   thrown) instead of popping in at a hard line. A mask, not a white overlay,
   so it fades the keepsakes themselves over any background. The settled pile
   fills about the lower half, well under the fade, so it stays crisp. */
.pile {
  position: relative;
  width: 100%;
  height: clamp(12rem, 22vw, 20rem);
  overflow: hidden;
  touch-action: pan-y;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 25%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 25%);
}

.pile__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

@media (max-width: 900px) {
  .footer__brand,
  .footer__more {
    grid-column: 1 / -1;
  }

  .footer__more {
    margin-top: var(--section-inner);
  }
}
