/* ============================================================
   Min — the public pitch deck
   ------------------------------------------------------------
   Slides made of web, not of exported rectangles: the same optical
   resin, the same Min, the same fog as the landing page. This file
   loads *after* landing.css and only does two things:

     1. turns a scrolling document into a paged, swipeable deck
     2. builds the one figure each slide is carrying

   Nothing here re-invents a material. If a surface needs to be an
   object it gets .resin; if a person needs to be a body it gets
   .blob; buttons are .btn. --bg and --ink are lerped between the
   slides' palettes by pitchdeck.js, exactly as the landing page
   lerps them along the scroll.
   ============================================================ */

/* ---- the deck ----------------------------------------------
   A horizontal scroll-snap track. Swiping is therefore native — the
   script only adds the keyboard, the wheel and the toolbar on top, so
   if it never runs you can still drag your way through the whole deck. */

html, body { height: 100%; }
body {
  overflow: hidden;
  /* the deck is one screen; nothing here should rubber-band */
  overscroll-behavior: none;
}
html { scroll-behavior: auto; }   /* the deck animates its own scrolling */

.deck {
  position: relative;
  z-index: 1;
  display: flex;
  height: 100svh;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.deck::-webkit-scrollbar { display: none; }

.slide {
  position: relative;
  flex: 0 0 100%;
  width: 100%;
  height: 100svh;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  padding:
    clamp(var(--space-8), 7svh, 72px)
    var(--space-6)
    calc(var(--dock-clear) + var(--space-4));
  /* safety valve: a cramped phone in landscape scrolls the slide's own
     content rather than clipping it. The wheel handler notices and lets
     that scroll happen instead of paging. */
  overflow-y: auto;
  scrollbar-width: none;
}
.slide::-webkit-scrollbar { display: none; }

/* ---- vertical on phones -----------------------------------
   A thumb pages up and down, the way every feed on a phone does. The
   track just turns ninety degrees: same snap, same slides, same script —
   pitchdeck.js reads the axis from this exact query, so the breakpoint
   lives in both files and must stay the same number.

   The slide gives up its own scrollbar here: the deck owns the vertical
   gesture, and a slide with somewhere to scroll would swallow it. The
   phone rules at the foot of this file are what keep every slide inside
   one screen instead. */
@media (max-width: 760px) {
  .deck {
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
    scroll-snap-type: y mandatory;
    overscroll-behavior-y: contain;
  }
  .slide {
    flex: 0 0 100svh;
    overflow: hidden;
  }
  /* Both arrows point the way the thumb now goes. `rotate` is its own
     property, so the cue's translateX keeps animating along the arrow —
     it's composed inside the rotation, and nudges downward for free. */
  .hint svg,
  .bar__btn svg { rotate: 90deg; }
}

/* One column, centred, with the figure and the words in a fixed rhythm.
   Every slide is this shape — the only thing that changes is the figure. */
.slide__inner {
  display: grid;
  justify-items: center;
  gap: clamp(var(--space-6), 3.4svh, var(--space-10));
  width: min(1040px, 100%);
  margin-inline: auto;
}

/* the small label in the corner of every slide but the cover */
.slide__tag {
  position: absolute;
  top: clamp(var(--space-6), 4svh, var(--space-9));
  left: 50%;
  translate: -50% 0;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---- type, at deck scale ----------------------------------
   Shorter than the landing page's: a slide has one line to say and it
   has to fit on one screen at any size, including a phone in landscape. */

.slide h2 {
  font-size: clamp(1.75rem, min(4.6vw, 5.6svh), 3.25rem);
  max-width: 24ch;
}
.slide h3 {
  font-size: clamp(1.0625rem, 2.2vw, 1.375rem);
  font-weight: var(--font-weight-semibold);
  letter-spacing: -0.02em;
}
.slide .lede {
  font-size: clamp(1rem, min(1.7vw, 2.4svh), 1.25rem);
  max-width: 52ch;
  margin-inline: auto;
}

/* the quiet line under the figure — the aside, not the point */
.slide__foot {
  font-size: clamp(0.875rem, 1.35vw, var(--text-md));
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 56ch;
  text-wrap: pretty;
}

/* ---- your space -------------------------------------------
   Every slide carries one empty paragraph. Type into it and it appears,
   in the same voice as the rest of the slide; leave it empty and it does
   not exist. Nothing to hide, nothing to remember to delete.

     <p class="slot">Your line here.</p>
*/
.slot {
  font-size: clamp(0.9375rem, 1.5vw, 1.0625rem);
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 54ch;
  margin-inline: auto;
  text-wrap: pretty;
}
.slot:empty { display: none; }

/* ---- 1. the cover -----------------------------------------
   Almost empty on purpose: the mark, the line, and nothing else to read. */

.cover .wordmark--hero { width: min(340px, 60vw); margin-bottom: 0; }
.cover h1 {
  font-size: clamp(2rem, min(5.6vw, 7svh), 3.75rem);
  max-width: 20ch;
}

/* the swipe cue, on the cover only, until you first move */
.hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: opacity var(--duration-standard) ease;
}
.hint svg { animation: hint-slide 1.9s ease-in-out infinite; }
@keyframes hint-slide {
  0%, 100% { transform: translateX(0); opacity: 0.55; }
  50%      { transform: translateX(5px); opacity: 1; }
}
.has-moved .hint { opacity: 0; }

/* ---- 2. the problem ---------------------------------------
   A crowd of people in a room, each lit from below by their own screen.
   Nobody is connected to anybody: the arcs between them start, hesitate,
   and fade — the near-miss, drawn. */

.crowd {
  position: relative;
  width: min(620px, 86vw);
  aspect-ratio: 16 / 9;
}
.crowd .blob {
  /* the crowd's bodies are smaller than the ring's — there are more of
     them in less room */
  width: clamp(24px, 8.5%, 46px);
  --cold: 1;
  --warm: 0;
  animation: crowd-drift 9s ease-in-out infinite;
}
/* each body keeps its own period, so the crowd never breathes in unison */
.crowd .blob:nth-child(2n)  { animation-duration: 11s; animation-delay: -2s; }
.crowd .blob:nth-child(3n)  { animation-duration: 13s; animation-delay: -5s; }
.crowd .blob:nth-child(5n)  { animation-duration: 10s; animation-delay: -7s; }
@keyframes crowd-drift {
  0%, 100% { transform: translate(0, 0); }
  33%      { transform: translate(3px, -4px); }
  66%      { transform: translate(-4px, 2px); }
}

/* the connections that never happen */
.crowd__misses {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.crowd__misses path {
  fill: none;
  stroke: color-mix(in srgb, var(--ink) 34%, transparent);
  stroke-width: 0.4;
  stroke-linecap: round;
  stroke-dasharray: 3 3;
  opacity: 0;
}
.slide.is-active .crowd__misses path { animation: near-miss 7s var(--ease-emergence) infinite; }
/* the shorthand above sets the delay too, so these have to out-specify it —
   without .is-active here the four arcs all start together */
.slide.is-active .crowd__misses path:nth-child(2) { animation-delay: 1.6s; }
.slide.is-active .crowd__misses path:nth-child(3) { animation-delay: 3.4s; }
.slide.is-active .crowd__misses path:nth-child(4) { animation-delay: 5.1s; }
@keyframes near-miss {
  0%       { opacity: 0; stroke-dashoffset: 40; }
  14%      { opacity: 0.85; }
  /* it gets most of the way there, and then it doesn't */
  34%      { opacity: 0.7; stroke-dashoffset: 8; }
  55%, 100%{ opacity: 0; stroke-dashoffset: 8; }
}

/* the phones themselves: a cold rectangle of light under each face */
.crowd .blob::after { inset: -34% -18%; }

/* ---- 3. why now -------------------------------------------
   Three shifts that read as separate news stories, and the hairlines
   underneath that make them one. The cards ride the emergence cascade;
   the joins draw once the last card has landed, and the opening arrives
   after them — the argument in the order you'd say it out loud. */

.shifts {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(var(--space-3), 1.8vw, var(--space-5));
  justify-items: center;
  width: 100%;
}
@media (min-width: 820px) { .shifts { grid-template-columns: repeat(3, 1fr); } }

/* These are not objects — they're three things that are already true, so
   they're hollows in the slide rather than resin on it (the same move
   `.vs--them` makes). It also keeps the ink: resin forces dark ink, and
   dark ink on this slide's cave brown is the mid-tone trap. */
.shift {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-3);
  height: 100%;
  padding: clamp(var(--space-4), 2vw, var(--space-6));
  border-radius: var(--radius-2xl);
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  text-align: center;
}
.shift h3 { color: var(--ink); font-size: var(--text-lg); }
.shift p {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 26ch;
}
.shift__icon { color: var(--ink); opacity: 0.85; }
.shift__icon svg { width: clamp(30px, 4.4vw, 40px); height: auto; display: block; }

/* the record turns; the other two just sit there being facts */
.shift .vinyl { animation: spin 6s linear infinite; transform-origin: center; }
@keyframes spin { to { transform: rotate(360deg); } }

/* the three lines that make it one story */
.shifts__join {
  grid-column: 1 / -1;
  width: min(100%, 620px);
  height: auto;          /* the viewBox keeps its aspect, so no distortion */
  overflow: visible;
}
.shifts__join path {
  fill: none;
  stroke: color-mix(in srgb, var(--ink) 32%, transparent);
  stroke-width: 0.22;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0;
}
/* the third card has landed by 1.09s (3 steps + the emergence itself) */
.slide.is-active .shifts__join path {
  animation: join-draw 0.55s var(--ease-emergence) 1.1s forwards;
}
/* the shorthand above sets the delay too, so these have to out-specify it */
.slide.is-active .shifts__join path:nth-child(2) { animation-delay: 1.2s; }
.slide.is-active .shifts__join path:nth-child(3) { animation-delay: 1.3s; }
@keyframes join-draw {
  0%   { opacity: 0;    stroke-dashoffset: 1; }
  22%  { opacity: 0.95; }
  100% { opacity: 0.95; stroke-dashoffset: 0; }
}

/* where the three arrive */
.shifts__now {
  grid-column: 1 / -1;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  padding: var(--space-2) var(--space-4);
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}

/* The payoff can't arrive before the lines that earn it, and the joins
   finish at 1.85s — past the cascade's five steps. So this slide's last
   three lines are timed off the drawing, not off the step count. `.in`
   lands on the slide itself, so this is `.slide--now.in`, not a
   descendant selector. */
.slide--now.in .shifts__now  { transition-delay: 1.85s; }
.slide--now.in .slide__foot  { transition-delay: 2.05s; }
.slide--now.in .slot         { transition-delay: 2.25s; }

/* ---- 4. the solution -------------------------------------
   The problem's scattered bodies, gathered: the landing page's ring,
   played on entry instead of scrubbed by a scroll. All of the per-element
   values still come from --in / --cold / --warm, so the CSS is the
   landing page's — only the driver changed. */

.slide .scene { height: auto; padding: 0; }
.slide .scene__stage { position: static; height: auto; gap: 0; }
.slide .ring { width: min(46svh, 420px, 82vw); }
/* .min's base rule is width/height 100%, which beats aspect-ratio and would
   stretch him to the full height of the ring. The ring is square, so an
   equal percentage of both axes is the square box he wants. */
.slide .min--dawn { width: 38%; height: 38%; animation: float-min 8s ease-in-out infinite; }

/* ---- 5. how it works --------------------------------------
   Three beats, left to right, each one an object doing the thing rather
   than a caption describing it. */

.beats {
  display: grid;
  gap: clamp(var(--space-4), 2.4vw, var(--space-6));
  grid-template-columns: 1fr;
  width: 100%;
}
@media (min-width: 820px) { .beats { grid-template-columns: repeat(3, 1fr); } }

.beat {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-4);
  padding: clamp(var(--space-5), 2.2vw, var(--space-7));
  border-radius: var(--radius-2xl);
  text-align: center;
}
.beat h3 { color: var(--ink); }
.beat p { font-size: var(--text-base); line-height: 1.5; color: var(--ink-soft); max-width: 30ch; }

/* the stage each beat's little figure plays on */
.beat__stage {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* the app's own cave, so the three figures read as one device */
  background:
    radial-gradient(120% 70% at 50% 108%, rgba(214, 197, 172, 0.18), transparent 70%),
    linear-gradient(180deg, var(--color-dusk-top), var(--color-dusk-bottom));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* — beat 1: the intro arrives — */
.notif {
  position: absolute;
  left: 8%; right: 8%;
  top: 14%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 11px;
  border-radius: 14px;
  text-align: left;
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(8px);
  color: #FAF7F2;
  opacity: 0;
}
.slide.is-active .notif { animation: notif-in 6s var(--ease-emergence) infinite; }
@keyframes notif-in {
  0%       { opacity: 0; transform: translateY(-10px) scale(1.03); filter: blur(4px); }
  12%, 76% { opacity: 1; transform: none; filter: none; }
  92%, 100%{ opacity: 0; transform: translateY(-6px); filter: blur(3px); }
}
.notif .min { width: 22px; height: 22px; flex: none; }
.notif b { display: block; font-size: 11px; font-weight: var(--font-weight-semibold); line-height: 1.25; }
.notif i { display: block; font-style: normal; font-size: 9.5px; color: rgba(250, 247, 242, 0.55); }

/* the yes, pressing itself */
.notif__yes {
  margin-left: auto;
  flex: none;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: var(--font-weight-semibold);
  color: #23211E;
  background: linear-gradient(96deg, var(--color-accent-soft), var(--color-accent));
}
.slide.is-active .notif__yes { animation: yes-press 6s var(--ease-drop) infinite; }
@keyframes yes-press {
  0%, 54%   { transform: none; box-shadow: 0 0 0 0 rgba(228, 210, 240, 0); }
  60%       { transform: scale(0.92); box-shadow: 0 0 0 6px rgba(228, 210, 240, 0.22); }
  70%, 100% { transform: none; box-shadow: 0 0 0 0 rgba(228, 210, 240, 0); }
}

/* — beat 2: you walk over — */
.walk { position: absolute; inset: 0; }
.walk__path {
  position: absolute;
  left: 18%; right: 18%;
  top: 58%;
  height: 1px;
  background: repeating-linear-gradient(90deg,
    rgba(250, 247, 242, 0.3) 0 4px, transparent 4px 9px);
}
.walk__you, .walk__them {
  position: absolute;
  top: 58%;
  width: 13px;
  aspect-ratio: 1 / 1.06;
  translate: -50% -50%;
  border-radius: 46% 46% 52% 52% / 48% 48% 54% 54%;
  background: linear-gradient(172deg, rgba(255, 252, 245, 0.95), rgba(235, 211, 176, 0.92));
}
.walk__you { left: 18%; }
.walk__them { left: 82%; }
/* the pair that has already agreed carries a little of the accent */
.walk__them { box-shadow: 0 0 14px 3px color-mix(in srgb, var(--color-accent-soft) 40%, transparent); }
.slide.is-active .walk__you { animation: walk-over 6s var(--ease-drop) infinite; }
@keyframes walk-over {
  0%, 8%    { left: 18%; }
  62%       { left: 74%; }
  80%, 100% { left: 74%; }
}
/* footsteps: the ground the walk covers, lighting up behind you */
.walk__trail {
  position: absolute;
  left: 18%;
  top: 58%;
  height: 1px;
  translate: 0 -50%;
  width: 0;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--color-accent-soft) 70%, transparent));
}
.slide.is-active .walk__trail { animation: walk-trail 6s var(--ease-drop) infinite; }
@keyframes walk-trail {
  0%, 8%    { width: 0; }
  62%       { width: 56%; }
  80%, 100% { width: 56%; opacity: 0; }
}

/* — beat 3: you meet, and the phone goes away — */
.meet { position: absolute; inset: 0; display: grid; place-items: center; }
.meet__pair { position: relative; display: flex; gap: 5px; }
.meet__pair span {
  width: 15px;
  aspect-ratio: 1 / 1.06;
  border-radius: 46% 46% 52% 52% / 48% 48% 54% 54%;
  background: linear-gradient(172deg, rgba(255, 252, 245, 0.96), rgba(235, 211, 176, 0.92));
}
/* the thread between them, with a pulse running end to end */
.meet__thread {
  position: absolute;
  top: 50%; left: 50%;
  translate: -50% -50%;
  width: 46px; height: 1px;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--color-accent-soft) 85%, transparent),
    transparent);
}
.slide.is-active .meet__thread { animation: thread-pulse 3.4s ease-in-out infinite; }
@keyframes thread-pulse {
  0%, 100% { opacity: 0.35; transform: scaleX(0.9); }
  50%      { opacity: 1;    transform: scaleX(1); }
}
/* a phone, face down on the table, which is the whole point */
.meet__phone {
  position: absolute;
  bottom: 16%;
  left: 50%;
  translate: -50% 0;
  width: 34px; height: 15px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.12);
  rotate: -8deg;
}
.meet__phone::after {
  content: 'screen off';
  position: absolute;
  left: 50%; top: calc(100% + 5px);
  translate: -50% 0;
  font-size: 8px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(250, 247, 242, 0.4);
  white-space: nowrap;
}

/* ---- 6. why it's different --------------------------------
   The two business models, side by side: one that has to keep you
   scrolling, and one that only pays off once you've left. */

.versus {
  display: grid;
  gap: clamp(var(--space-4), 2.6vw, var(--space-6));
  grid-template-columns: 1fr;
  width: min(760px, 100%);
}
@media (min-width: 760px) { .versus { grid-template-columns: 1fr 1fr; align-items: stretch; } }

.vs {
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--space-4);
  padding: clamp(var(--space-5), 2.2vw, var(--space-7));
  border-radius: var(--radius-2xl);
  text-align: left;
}
.vs__label {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.vs p { font-size: var(--text-base); line-height: 1.5; color: var(--ink-soft); }

/* the one that isn't us is a hollow in the page, not an object on it —
   it doesn't get to be resin */
.vs--them {
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  color: var(--ink);
}

/* an endless feed, ending never */
.feed {
  position: relative;
  height: clamp(86px, 15svh, 132px);
  overflow: hidden;
  border-radius: var(--radius-md);
  /* it fades at both ends, because it has no ends */
  mask-image: linear-gradient(180deg, transparent, #000 22%, #000 78%, transparent);
}
.feed__strip { display: grid; gap: 7px; }
.slide.is-active .feed__strip { animation: feed 3.4s linear infinite; }
/* the strip holds two identical runs, so one run's height is one loop */
@keyframes feed { to { transform: translateY(-50%); } }
.feed__strip i {
  display: block;
  height: 13px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
}
.feed__strip i:nth-child(3n) { width: 72%; }
.feed__strip i:nth-child(4n) { width: 86%; }

/* ours: one card, and then the screen is done with you */
.done {
  position: relative;
  height: clamp(86px, 15svh, 132px);
  border-radius: var(--radius-md);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.done__card {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 999px;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: #23211E;
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.6), rgba(242, 238, 231, 0.3));
  box-shadow: var(--edge-resin), 0 10px 22px -12px rgba(15, 13, 20, 0.5);
}
.done__card .min { width: 20px; height: 20px; flex: none; }
.done__out {
  position: absolute;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  opacity: 0;
}
/* the card hands over to the street: the app's successful outcome is the
   app being finished with */
.slide.is-active .done__card { animation: hand-over-card 5.6s var(--ease-emergence) infinite; }
.slide.is-active .done__out  { animation: hand-over-out 5.6s var(--ease-emergence) infinite; }
@keyframes hand-over-card {
  0%, 42%  { opacity: 1; transform: none; filter: none; }
  58%,100% { opacity: 0; transform: translateY(-8px) scale(0.98); filter: blur(4px); }
}
@keyframes hand-over-out {
  0%, 46%  { opacity: 0; transform: translateY(8px); filter: blur(4px); }
  62%, 92% { opacity: 1; transform: none; filter: none; }
  100%     { opacity: 0; }
}

/* the line that carries the slide, under both columns */
.versus__line {
  font-size: clamp(1.0625rem, 2vw, 1.375rem);
  font-weight: var(--font-weight-semibold);
  letter-spacing: -0.02em;
  color: var(--ink);
  max-width: 40ch;
  margin-inline: auto;
}

/* ---- 7. the vision ---------------------------------------
   The landing page's four "nots", at deck size: two by two, tighter
   padding, and the strike-through still draws itself on entry. */

.slide .nots { margin-top: 0; gap: clamp(var(--space-3), 1.6vw, var(--space-5)); width: 100%; }
@media (min-width: 700px) { .slide .nots { grid-template-columns: 1fr 1fr; } }
.slide .not {
  padding: clamp(var(--space-4), 2.2vw, var(--space-7));
  border-radius: var(--radius-2xl);
  text-align: left;
}
.slide .not > b { font-size: clamp(1rem, min(2.1vw, 2.6svh), 1.375rem); margin-bottom: var(--space-2); }
.slide .not p { font-size: var(--text-sm); line-height: 1.5; }

/* ---- 8. the close ----------------------------------------- */

.close .hero__actions { margin-top: var(--space-4); }
.close__where {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

/* The QR plate stays literally white and unfiltered — the code has to
   survive a camera across a room, so it is the one object on the page that
   is not made of the site's glass. */
.close__scan {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
.close__plate {
  background: #fff;
  padding: clamp(8px, 0.9vw, 12px);
  border-radius: var(--radius-lg);
  box-shadow: 0 10px 30px -12px rgb(15 13 20 / 0.45);
  line-height: 0;
}
.close__plate img {
  display: block;
  width: clamp(96px, min(11vw, 16svh), 168px);
  height: auto;
}
.close__scanline {
  font-size: var(--text-xs);
  color: var(--ink-faint);
}

/* No room for it on the vertical track, and no reason for it either. */
@media (max-width: 760px) {
  .close__scan { display: none; }
}

/* ---- the toolbar ------------------------------------------
   Same pebble as the site's nav (it borrows .nav wholesale), with the
   deck's controls sunk into it as wells rather than stacked on it as
   more objects. */

.bar { gap: var(--space-4); padding: 7px 10px 7px 16px; }

.bar__group { display: flex; align-items: center; gap: var(--space-2); }

.bar__btn {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(35, 33, 30, 0.1);
  background: rgba(35, 33, 30, 0.05);
  box-shadow: inset 0 1px 2px rgba(15, 13, 20, 0.08);
  color: #23211E;
  cursor: pointer;
  transition: background var(--transition-fast), opacity var(--transition-fast);
}
.bar__btn:hover:not(:disabled) { background: rgba(35, 33, 30, 0.11); }
.bar__btn:disabled { opacity: 0.3; cursor: default; }

/* the dots: one per slide, the current one stretched into a pill */
.bar__dots { display: flex; align-items: center; gap: 7px; }
.bar__dot {
  position: relative;
  width: 7px; height: 7px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgba(35, 33, 30, 0.2);
  cursor: pointer;
  transition:
    width var(--duration-quick) var(--ease-emergence),
    background var(--duration-quick) ease;
}
.bar__dot:hover { background: rgba(35, 33, 30, 0.38); }
.bar__dot[aria-current="true"] {
  width: 22px;
  background: linear-gradient(96deg, var(--color-accent-hover), var(--color-accent));
}

.bar__count {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: #6D6861;
  min-width: 3.4ch;
  text-align: right;
}

/* On a phone the dots are the whole navigation — the arrows are what a
   thumb does anyway, and the label has nowhere to go. */
@media (max-width: 640px) {
  .bar { gap: var(--space-3); padding: 7px 12px; }
  .bar .wordmark--nav { width: 40px; }
  .bar__count { display: none; }
  .bar__dots { gap: 6px; }
}

/* ---- the progress hairline --------------------------------- */
.rail { transform: scaleX(var(--p, 0)); }

/* ---- small screens ---------------------------------------- */

@media (max-width: 760px) {
  .slide { padding-inline: var(--space-5); }
  .crowd { width: 92vw; }

  /* The three shifts stay three on a phone — stacked, they cost a screen
     and a half. Icon and label only; the evidence under each one is
     desktop detail, and the foot below still carries the argument. */
  .shifts { grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
  .shift { padding: var(--space-4) var(--space-2); gap: var(--space-2); }
  .shift h3 { font-size: var(--text-sm); }
  .shift p { display: none; }

  /* Three stacked beats can't keep their sentences and still fit one
     screen. The figures stay — they're the story — and flatten; the
     headline above already says "yes → walk over → hello", so the
     explanatory line is desktop detail. */
  .beats { gap: var(--space-3); }
  .beat { padding: var(--space-3) var(--space-4) var(--space-4); gap: var(--space-3); }
  .beat__stage { aspect-ratio: 20 / 7; }
  .beat p { display: none; }

  /* the two models get shorter figures rather than a scrollbar */
  .feed, .done { height: clamp(64px, 11svh, 110px); }
  .vs { padding: var(--space-4) var(--space-5); gap: var(--space-3); }
  .vs p { font-size: var(--text-sm); }
}

/* Short viewports (a laptop in a lecture hall, a phone on its side) — the
   figure gives up room before the words do. */
@media (max-height: 620px) {
  .slide__inner { gap: var(--space-4); }
  .slide__tag { display: none; }
  .beat__stage { display: none; }
  .cover .wordmark--hero { width: min(220px, 42vw); }
}

@media (prefers-reduced-motion: reduce) {
  /* Nothing animates, so every figure has to be readable in its finished
     state: the three shifts are already joined, and the ring is assembled
     (pitchdeck.js leaves .scene unarmed, which is the assembled figure). */
  .shifts__join path { opacity: 0.95; stroke-dashoffset: 0; }
  .notif, .done__card { opacity: 1; }
  .done__out { display: none; }
  .deck { scroll-behavior: auto; }
}
