/* =============================================================
   SCROLL-DRIVEN STORY
   A stage that stays while the copy moves past it. The device
   rotates in real 3D and the screen changes with the step, so the
   reader is walked through a flow rather than handed a grid of
   screenshots.

   The artefact is a 2x PNG inside a CSS 3D shell rather than a
   WebGL texture, because the whole point is that the interface
   stays legible. Nothing here is required to read the page: the
   steps are ordinary text and the stage falls back to a single
   still when script or motion is unavailable.
   ============================================================= */

.st {
  --st-dur: 420ms;
  --st-ease: cubic-bezier(.22,.7,.2,1);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0 clamp(32px, 6vw, 96px);
  margin: 0 0 40px;
}
.st[data-align="left"] { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.st[data-align="left"] .st-rail { order: -1; }

/* the stage stays put; sticky, not scroll-jacked, so the page never fights the reader */
.st-rail { position: relative; }
.st-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  place-items: center;
  perspective: 1600px;
  perspective-origin: 50% 45%;
}
/* More than one device can share a stage. When the story moves from the person
   who reports to the person who acts, the phone steps back and the manager's
   screen comes forward, so the handoff is shown rather than described. */
.st-stage .st-device { grid-area: 1 / 1; }
.st-stage[data-devices="2"] .st-device {
  opacity: 0;
  pointer-events: none;
  transition: opacity 560ms var(--st-ease), transform 720ms cubic-bezier(.16,.84,.24,1), filter 560ms var(--st-ease);
  filter: blur(6px);
}
.st-stage[data-devices="2"] .st-device.is-live {
  opacity: 1;
  pointer-events: auto;
  filter: none;
}
.st-stage[data-devices="2"] .st-device:not(.is-live).phone { transform: scale(.82) translateX(-8%) rotateY(14deg); }
.st-stage[data-devices="2"] .st-device:not(.is-live).browser { transform: scale(.86) translateX(8%) rotateY(-12deg); }

/* ---------- the phone ---------- */
.st-device {
  position: relative;
  transform-style: preserve-3d;
  will-change: transform;
  transition: transform var(--st-dur) var(--st-ease);
}
.st-device.phone {
  width: 300px;
  aspect-ratio: 390 / 844;
  border-radius: 42px;
  background: #0d0d0f;
  padding: 9px;
  box-shadow:
    0 0 0 1px rgba(17,17,16,.16),
    0 30px 60px -22px rgba(17,17,16,.5),
    0 90px 120px -60px rgba(17,17,16,.4);
}
.st-device.phone::after {
  content: "";
  position: absolute; left: 50%; top: 17px; transform: translateX(-50%);
  width: 86px; height: 22px; border-radius: 12px; background: #0d0d0f; z-index: 3;
}
.st-screen {
  position: relative; width: 100%; height: 100%;
  border-radius: 34px; overflow: hidden; background: #fff;
}
/* a browser screen has no fixed device ratio, so it takes one from its artwork */
.st-device.browser .st-screen { height: auto; aspect-ratio: var(--st-ratio, 4 / 3); }
.st-device.browser .st-shot { object-fit: contain; object-position: 50% 50%; background: #fff; }
/* a page longer than the window is shown from the top, the way a browser shows it */
.st-device.browser.from-top .st-shot { object-fit: cover; object-position: 50% 0; }
.st-device.browser {
  width: min(100%, 680px);
  border-radius: 12px;
  background: #e9e9e6;
  padding: 26px 1px 1px;
  box-shadow: 0 0 0 1px rgba(17,17,16,.12), 0 26px 52px -24px rgba(17,17,16,.42);
}
.st-device.browser::before {
  content: "";
  position: absolute; left: 12px; top: 10px;
  width: 30px; height: 6px; border-radius: 3px;
  background: radial-gradient(circle 3px at 3px 3px, #c9c9c4 99%, transparent),
              radial-gradient(circle 3px at 15px 3px, #c9c9c4 99%, transparent),
              radial-gradient(circle 3px at 27px 3px, #c9c9c4 99%, transparent);
}
.st-device.browser .st-screen { border-radius: 0 0 11px 11px; }

/* the shots are stacked; one is visible at a time */
.st-shot {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0;
  opacity: 0;
  transform: scale(1.02);
  transition: opacity var(--st-dur) var(--st-ease), transform var(--st-dur) var(--st-ease);
}
.st-shot.is-on { opacity: 1; transform: none; }

/* Instead of dimming the screen, the frame moves in on what the step is about.
   The shot scales about the point named by the step, the device holds still, and
   the crop happens inside the screen, which is what a camera move looks like. */
.st-shot.is-on {
  opacity: 1;
  transform: scale(var(--z, 1));
  transform-origin: var(--zx, 50%) var(--zy, 50%);
  transition: opacity var(--st-dur) var(--st-ease),
              transform 720ms cubic-bezier(.16,.84,.24,1);
}
.st-lens { display: none; }

/* ---------- the copy ---------- */
.st-copy { list-style: none; margin: 0; padding: 0; }
.st-step {
  min-height: 86vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 8vh 0;
  opacity: .34;
  transition: opacity var(--st-dur) var(--st-ease);
}
.st-step.is-on { opacity: 1; }
.st-step .st-kind {
  display: inline-block;
  font-family: var(--mono); font-size: var(--t-1); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 10px;
}
.st-step .st-n {
  display: block;
  font-family: var(--mono); font-size: var(--t-1); color: #9b3427; margin-bottom: 6px;
}
.st-step h3 {
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.16; letter-spacing: -.025em;
  margin: 0 0 12px; max-width: 20ch;
}
.st-step p { margin: 0 0 12px; font-size: var(--t-4); line-height: 1.6; color: #3c3c38; max-width: 46ch; }
.st-step .st-quote {
  border-left: 3px solid #9b3427;
  padding: 2px 0 2px 14px; margin: 14px 0 0;
  font-size: var(--t-4); line-height: 1.55; color: var(--ink); max-width: 46ch;
}
.st-step .st-rej {
  margin-top: 14px; font-size: var(--t-3); line-height: 1.55; color: var(--ink-soft); max-width: 46ch;
}
.st-step .st-rej b {
  display: block; font-family: var(--mono); font-size: var(--t-1); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 3px;
}

/* progress down the side of the stage */
.st-ticks { position: absolute; left: -26px; top: 50%; transform: translateY(-50%); display: grid; gap: 9px; }
.st-ticks i { width: 5px; height: 5px; border-radius: 50%; background: var(--line-strong); display: block; transition: all var(--st-dur) var(--st-ease); }
.st-ticks i.on { background: #9b3427; height: 18px; border-radius: 3px; }

/* ---------- graceful degradation ---------- */
.st-fallback { display: none; }
@media (max-width: 900px) {
  .st { display: block; }
  .st-stage { position: static; height: auto; padding: 0 0 20px; }
  .st-device.phone { width: 260px; }
  .st-step { min-height: 0; padding: 18px 0; opacity: 1; }
  .st-ticks { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .st-device, .st-shot, .st-step, .st-lens { transition: none !important; }
  .st-device { transform: none !important; }
}
@media print {
  .st { display: block; }
  .st-stage { position: static; height: auto; }
  .st-step { min-height: 0; opacity: 1; }
  .st-ticks { display: none; }
}

/* =============================================================
   v13 · A REAL IPHONE, NOT A ROUNDED CROP
   iPhone 15 and 16 are 393 x 852 points, with a 54pt status bar and
   a 34pt bottom safe area (Apple's figures, via useyourloaf.com's
   screen-size reference). The Dynamic Island is 125 x 36.67pt sitting
   11pt below the top of the display and the home indicator is
   139 x 5pt; the display corner radius is taken as 55pt, which is the
   figure device-frame libraries publish rather than one Apple
   documents. Every number below is that spec scaled by the width the
   frame is drawn at, so the proportions hold at any size instead of
   being eyeballed.
   ============================================================= */
.st-device.phone,
.dv-phone {
  --sw: 342px;                 /* drawn width of the display */
  --s: calc(var(--sw) / 393);  /* points to pixels at this size */
  --bezel: calc(8 * var(--s));
  --screen-r: calc(55 * var(--s));
  width: calc(var(--sw) + var(--bezel) * 2);
  aspect-ratio: auto;
  height: calc(852 * var(--s) + var(--bezel) * 2);
  padding: var(--bezel);
  border-radius: calc(var(--screen-r) + var(--bezel));
  background: linear-gradient(150deg, #3a3a3e 0%, #101013 34%, #17171b 62%, #45454a 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.14),
    0 0 0 1px rgba(17,17,16,.22),
    0 34px 64px -26px rgba(17,17,16,.5),
    0 90px 130px -70px rgba(17,17,16,.42);
}
.st-device.phone .st-screen,
.dv-phone .dv-screen {
  border-radius: var(--screen-r);
  height: 100%;
  overflow: hidden;
  background: #fff;
}
/* the island sits over the screen, in the gap the status bar leaves for it */
.st-device.phone::after,
.dv-phone::after {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(var(--bezel) + 11 * var(--s));
  transform: translateX(-50%);
  width: calc(125 * var(--s));
  height: calc(36.67 * var(--s));
  border-radius: calc(18.33 * var(--s));
  background: #08080a;
  z-index: 3;
}
/* the side buttons, because a phone without them reads as a rectangle */
.st-device.phone::before,
.dv-phone::before {
  content: "";
  position: absolute;
  left: calc(var(--bezel) * -0.5);
  top: calc(120 * var(--s));
  width: calc(var(--bezel) * 0.5);
  height: calc(32 * var(--s));
  border-radius: 2px 0 0 2px;
  background: #2b2b30;
  box-shadow: 0 calc(52 * var(--s)) 0 #2b2b30, 0 calc(104 * var(--s)) 0 #2b2b30;
}
.st-device.phone .st-shot { object-fit: fill; }

@media (max-width: 1180px) { .st-device.phone { --sw: 300px; } }
@media (max-width: 900px) { .st-device.phone { --sw: 250px; } }
