/* ==========================================================================
   Offhand home page — everything on this file is loaded by `/` and nowhere
   else. `public/styles.css` stays the site-wide sheet; if a rule here would
   help another page it belongs over there instead, and if a rule here bleeds
   onto another page it is a bug.

   Scope: every new selector sits under `.home-redesign` (the body class) or
   under one of the frozen hooks listed in
   `marketing/homepage-redesign/HANDOFF-A.md`. Do not edit the design-system
   token sources in `_design/`; layout-specific numbers may live here, but
   they are not new brand tokens.

   OWNERSHIP
     Package A (foundation) created this file and migrated the block below.
     Package B owns it from here. Package C owns `public/homepage.js` and
     must not edit this file.
   ========================================================================== */

/* -------------------------------------------------------- migrated block --
   Moved verbatim out of `public/styles.css` (lines 1668-1944 before this
   change) by Package A. It is the drawn iPhone and its DOM screen: pixel
   measures read off `assets/hero-1.1.2.webp`, a state machine keyed on
   `.demo-phone[data-state]`, and a reduced-motion branch. All of it is still
   in use — the handset is the capture surface of the new product story — so
   nothing here was rewritten, only its three dead wrappers retargeted:

     .demo        -> gone. Package B builds `.story` in its place.
     .demo-steps  -> gone. Package B builds `.story-steps`.
     .demo-stage  -> retargeted to `.story-phone`, which is the new surface
                     the handset sits in. The scale mechanism (`--demo-k`,
                     one design size transformed as a unit) is unchanged and
                     is worth keeping.

   The old `.demo.live .card.on` step-highlighting rules were dropped with
   the wrappers: the steps are no longer `.card`, and lighting the current
   step is Package B's to rebuild against `[data-story-step]`.
   -------------------------------------------------------------------------- */
/* ------------------------------------------------------------------ demo */
/* "How it works" is one demo: the three steps on the left, the handset on
   the right, and demo.js playing a capture on the phone while it lights the
   step the phone is on. The technique is the one on osis.co
   (marketing/iphone-demo-design-notes.md): the screen is DOM, not a
   screenshot; it is drawn once at a fixed size and scaled as a unit; a
   timer chain sets one state on `.demo-phone`, and every move is CSS
   reading that state. The handset is the hero's own drawing at 420px, so
   the screen inside is 402 x 874 — the iPhone 17 Pro's own points — and
   every measure below is the app's, read off assets/hero-1.1.2.webp (the
   1.1.2 capture: a tighter day header than 1.1, and the completion ring on
   the title line). */
/* The handset's own surface inside the product story. One design size
   (420px wide, a 402 x 874 screen) transformed as a unit, so nothing inside
   it ever reflows — the technique in marketing/iphone-demo-design-notes.md. */
.story-phone {
  --demo-k: .72;
  position: relative;
  margin: 0;
  height: calc(892px * var(--demo-k));  /* the frame: 874 + two 9px insets */
}
.demo-phone {
  position: absolute;
  left: 50%;
  top: 0;
  width: 420px;
  transform: translateX(-50%) scale(var(--demo-k));
  transform-origin: 50% 0;
  --ease-out: cubic-bezier(.25, .1, .25, 1);
  --spring-capture: cubic-bezier(.32, .72, .24, 1);    /* the app's own capture morph */
  --glass-capture: rgba(28, 31, 28, .82);
  --moss-light: #99bfa1;                               /* the app's dark-scheme moss */
}
.demo-frame { width: 100%; }
.demo-screen {
  position: relative;
  width: 100%;
  aspect-ratio: 402 / 874;
  border-radius: 15.4% / 7.08%;
  overflow: hidden;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-system);
  -webkit-font-smoothing: antialiased;
  text-wrap: initial;
}
.demo-screen svg { display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* The status bar. Over the list, so the list can scroll under it. */
.ds-statusbar { position: absolute; top: 0; left: 0; right: 0; height: 50px; z-index: 6; pointer-events: none; }
.ds-statusbar::before {
  content: "";
  position: absolute;
  inset: 0 0 -28px;
  background: linear-gradient(var(--canvas) 60%, transparent);
}
.ds-time { position: absolute; left: 56px; top: 21px; font: 600 17px/20px var(--font-system); letter-spacing: -.2px; }
.ds-island { position: absolute; left: 50%; top: 15px; width: 126px; height: 36px; margin-left: -63px; border-radius: 18px; background: #050604; }
.ds-sys { position: absolute; right: 36px; top: 20px; display: flex; align-items: center; gap: 7px; }
.ds-signal { width: 19px; height: 12px; fill: currentColor; stroke: none; }
.ds-wifi { width: 17px; height: 17px; stroke-width: 2.4; }
.ds-batt { width: 28px; height: 13px; stroke: none; }

/* The day. Cards sit 30px in; the title and date 9px further out, as in
   the app. */
.ds-list {
  position: absolute;
  inset: 0;
  padding: 115px 30px 0;
  z-index: 1;
  transition: transform .9s var(--ease-out);
}
.ds-title { display: flex; align-items: center; gap: 8px; margin: 0 0 0 -9px; font: 700 33px/40px var(--font-system); letter-spacing: -.4px; }
.ds-chev { width: 16px; height: 16px; margin-top: 4px; color: var(--ink-tertiary); stroke-width: 2.2; }
.ds-date { margin: 0 0 0 -9px; font: 400 15px/20px var(--font-system); color: var(--text-secondary); }
.ds-chips { display: flex; gap: 8px; margin-top: 8px; }
.ds-chip {
  display: inline-flex; align-items: center; gap: 7px;
  height: 28px; padding: 0 11px 0 10px;
  border-radius: var(--radius-pill);
  font: 500 13px/28px var(--font-system);
  background: color-mix(in srgb, currentColor 11%, transparent);
}
.ds-chip::before, .ds-tag::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.is-work { color: #b8503a; }
.is-groc { color: #4560c4; }
.is-fit  { color: #a67a1a; }

.ds-section { margin-top: 18px; }
.ds-chips + .ds-section { margin-top: 20px; }
.ds-head { display: flex; align-items: center; gap: 9px; height: 30px; margin-bottom: 4px; padding: 0 2px 0 1px; font: 600 15px/20px var(--font-system); }
.ds-glyph { width: 20px; height: 20px; stroke-width: 1.9; }
.ds-now {
  height: 15px; padding: 0 5px;
  border-radius: var(--radius-pill);
  font: 700 9px/15px var(--font-system);
  letter-spacing: .4px; text-transform: uppercase;
  color: var(--moss); background: var(--moss-badge);
}
.ds-count { margin-left: auto; font: 400 15px/20px var(--font-system); color: var(--text-secondary); }
.ds-count::before { content: attr(data-idle); }
.ds-card {
  display: flex; align-items: flex-start; gap: 14px;   /* 1.1.2: the ring sits on the title line */
  min-height: 53px; padding: 6px 16px 7px; margin-top: 8px;
  background: var(--paper);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-card);
}
.ds-check { width: 22px; height: 22px; flex: none; border-radius: 50%; border: 1.5px solid var(--ink-checkbox); }
.ds-card-in { min-width: 0; }
.ds-task { margin: 0; font: 400 17px/22px var(--font-system); }
.ds-meta { display: flex; align-items: center; gap: 6px; margin: 2px 0 0; font: 400 11.5px/14px var(--font-system); color: var(--text-secondary); }
.ds-meta svg { width: 12px; height: 12px; }
.ds-tag { display: inline-flex; align-items: center; gap: 5px; margin-left: 4px; font-weight: 500; }
.ds-tag::before { width: 6px; height: 6px; }
.ds-empty { margin: 0 0 0 1px; font: 400 12px/16px var(--font-system); color: var(--text-tertiary); }
.ds-done { display: flex; align-items: center; gap: 8px; margin: 22px 0 0 1px; font: 400 13px/18px var(--font-system); color: var(--text-secondary); }
.ds-done svg { width: 15px; height: 15px; stroke-width: 1.8; }
.ds-done .ds-done-chev { width: 12px; height: 12px; margin-left: -2px; stroke-width: 2.2; }

/* The four tasks the capture files. Each one unfolds from nothing and pops
   — the app's own row entrance — in its turn; the list rolls up as they land,
   so all four sit above the capsule and the title rolls under the status bar. */
.ds-new { display: none; }
.demo-phone:is([data-state="review"], [data-state="settled"], [data-state="out"]) .ds-new {
  display: flex;
  animation: ds-pop .42s var(--spring-capture) both;
  animation-delay: calc(var(--i) * 190ms);
}
.demo-phone:is([data-state="review"], [data-state="settled"], [data-state="out"]) .ds-empty { display: none; }
.demo-phone:is([data-state="review"], [data-state="settled"], [data-state="out"]) .ds-count::before { content: attr(data-done); }
.demo-phone:is([data-state="review"], [data-state="settled"], [data-state="out"]) .ds-list { transform: translateY(-128px); }
@keyframes ds-pop {
  0%   { opacity: 0; margin-top: -55px; transform: translateY(10px) scale(.96); }
  100% { opacity: 1; margin-top: 8px; transform: none; }
}

/* The status line: "Finding tasks…" with a spinner, then "4 tasks added"
   in moss. Pinned just above the capsule and flush with its left edge,
   outside the list. */
.ds-pill {
  position: absolute; left: 20px; bottom: 119px; z-index: 3;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px;
  border-radius: var(--radius-pill);
  background: var(--paper);
  border: 1px solid var(--border-card);
  box-shadow: 0 8px 22px -10px rgba(28, 31, 28, .4);
  font: 400 13px/18px var(--font-system);
  color: var(--text-secondary);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .25s var(--ease-out), transform .25s var(--ease-out);
}
.demo-phone:is([data-state="finding"], [data-state="review"]) .ds-pill { opacity: 1; transform: none; }
/* Bounded, not infinite: the save scene now RESTS on `finding`, where the old
   demo only passed through it, and the Mac's own spinner beside it stops after
   seven turns. Two spinners in one frame must not disagree. */
.ds-spin { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--ink-quaternary); border-top-color: var(--text-secondary); animation: ds-spin .8s linear 7; }
.ds-pill-ico { display: none; width: 12px; height: 12px; color: var(--moss); stroke-width: 2.5; }
.ds-pill-done { display: none; }
.demo-phone[data-state="review"] .ds-spin, .demo-phone[data-state="review"] .ds-pill-finding { display: none; }
.demo-phone[data-state="review"] .ds-pill-ico, .demo-phone[data-state="review"] .ds-pill-done { display: block; }
.demo-phone[data-state="review"] .ds-pill { font-weight: 600; color: var(--moss); }
@keyframes ds-spin { to { transform: rotate(360deg); } }

/* The capsule at the foot of the day, and the panel it morphs into. Both
   glass-dark, both ending 49px up; the panel grows from the capsule's
   height to its own while the capsule fades under it. */
.ds-capsule {
  position: absolute; left: 20px; right: 20px; bottom: 49px; z-index: 3;
  display: flex; align-items: center; gap: 12px;
  height: 58px; padding: 0 15px 0 22px;
  border-radius: var(--radius-pill);
  background: var(--glass-capture);
  color: var(--canvas);
  font: 600 17px/22px var(--font-system);
  transition: opacity .22s var(--ease-out);
}
.ds-capsule > svg { width: 21px; height: 21px; stroke-width: 2.2; }
.ds-capsule-arrow { margin-left: auto; width: 28px; height: 28px; border-radius: 50%; background: rgba(245, 242, 232, .18); display: grid; place-items: center; }
.ds-capsule-arrow svg { width: 15px; height: 15px; stroke-width: 2.6; }
.demo-phone:is([data-state="listen"], [data-state="save"]) .ds-capsule { opacity: 0; }

.ds-panel {
  position: absolute; left: 16px; right: 16px; bottom: 49px; z-index: 4;
  height: 58px;
  border-radius: 28px;
  background: var(--glass-capture);
  color: #efece2;
  opacity: 0;
  overflow: hidden;
  transition: height .34s var(--spring-capture), opacity .18s var(--ease-out) .12s;
}
.ds-panel-in { position: absolute; inset: 0; opacity: 0; transition: opacity .2s var(--ease-out); }
.demo-phone:is([data-state="listen"], [data-state="save"]) .ds-panel { height: 225px; opacity: 1; transition: height .34s var(--spring-capture), opacity .12s var(--ease-out); }
.demo-phone:is([data-state="listen"], [data-state="save"]) .ds-panel-in { opacity: 1; transition: opacity .25s var(--ease-out) .14s; }
.ds-close { position: absolute; left: 14px; top: 14px; width: 32px; height: 32px; border-radius: 50%; background: rgba(245, 242, 232, .14); display: grid; place-items: center; }
.ds-close svg { width: 13px; height: 13px; stroke-width: 2.4; }
.ds-grab { position: absolute; left: 50%; top: 26px; width: 36px; height: 5px; margin-left: -18px; border-radius: 3px; background: rgba(245, 242, 232, .28); }
.ds-script {
  position: absolute; left: 14px; right: 14px; top: 73px; margin: 0;
  font: 400 19.4px/24.5px var(--font-serif);
  text-wrap: pretty;
}
.ds-script em { font-style: normal; color: var(--moss-light); }
/* Words land one at a time; the clause still being heard is underlined,
   the app's mark for a transcript that may yet change. */
.ds-script .w { opacity: 0; }
.ds-script .w.on { opacity: 1; }
.ds-script .w.live { text-decoration: underline; text-decoration-color: rgba(153, 191, 161, .75); text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.ds-bar { position: absolute; left: 14px; right: 14px; bottom: 14px; height: 44px; display: flex; align-items: center; gap: 10px; }
.ds-mode, .ds-rec {
  display: flex; align-items: center; gap: 6px;
  height: 42px; padding: 0 12px 0 14px;
  border-radius: var(--radius-pill);
  background: rgba(245, 242, 232, .14);
  font: 600 14px/20px var(--font-system);
}
.ds-mode svg { width: 12px; height: 12px; stroke-width: 2.4; }
.ds-rec { margin-left: auto; gap: 8px; padding: 0 12px; background: rgba(153, 191, 161, .16); font: 600 14px/20px var(--font-system); font-variant-numeric: tabular-nums; color: var(--moss-light); }
.ds-pause { width: 8px; height: 12px; fill: currentColor; stroke: none; }
.ds-wave { display: flex; align-items: center; gap: 2px; height: 20px; }
/* Counted, like the two spinners above: the capture rests on `listen`, so an
   endless waveform would be a page that never stops moving for a reader who
   stayed. Five turns of .7s is 3.5s of running — the bars go still between
   3.6s and 4.1s into the run, as the last words land and the clock stops at
   0:18 — and the count is ODD so the last turn ends on `to`, which is the
   height the bar has with no animation at all. Nothing steps at the end, and
   the frame it stops on is the frame `.no-anim` parks the scene on.
   Running time only: the play state below pauses the clock with the bars, and
   `run()` re-creates the animation through `.no-anim` on every replay. */
.ds-wave i { width: 2.4px; height: var(--h); border-radius: 2px; background: currentColor; transform-origin: 50% 50%; animation: ds-wave .7s ease-in-out 5 alternate; animation-play-state: paused; }
.ds-wave i:nth-child(2) { animation-delay: -.25s; }
.ds-wave i:nth-child(3) { animation-delay: -.5s; }
.ds-wave i:nth-child(4) { animation-delay: -.1s; }
.ds-wave i:nth-child(5) { animation-delay: -.4s; }
.demo-phone[data-state="listen"] .ds-wave i { animation-play-state: running; }
@keyframes ds-wave { from { transform: scaleY(.55); } to { transform: scaleY(1); } }
.ds-send { position: relative; width: 44px; height: 44px; border-radius: 50%; background: var(--canvas); color: var(--ink); display: grid; place-items: center; transition: transform .15s var(--ease-out); }
.ds-send svg { width: 20px; height: 20px; stroke-width: 2.6; }
.ds-ripple { position: absolute; inset: 0; border-radius: 50%; background: rgba(255, 255, 255, .6); opacity: 0; transform: scale(.4); }
.demo-phone[data-state="save"] .ds-send { transform: scale(.94); }
.demo-phone[data-state="save"] .ds-ripple { animation: ds-tap .5s ease-out both; }
@keyframes ds-tap {
  0%   { opacity: 0; transform: scale(.4); }
  30%  { opacity: 1; }
  100% { opacity: 0; transform: scale(1.7); }
}

/* The Action Button, pressed: it lights and gives a little. */
.key-action.hit { animation: ds-key .55s var(--ease-out); }
@keyframes ds-key {
  0%, 100% { transform: none; box-shadow: none; }
  25%, 60% { transform: translateX(1.5px); background: #d6dfd6; box-shadow: 0 0 0 2px rgba(61, 89, 71, .45), 0 0 10px 3px rgba(61, 89, 71, .6); }
}

/* Between loops the screen fades to canvas, the day resets underneath,
   and the veil lifts. */
.ds-veil { position: absolute; inset: 0; z-index: 5; background: var(--canvas); opacity: 0; pointer-events: none; transition: opacity .35s var(--ease-out); }
.demo-phone[data-state="out"] .ds-veil { opacity: 1; }
.demo-phone.no-anim *:not(.ds-veil) { transition: none !important; animation: none !important; }

@media (max-width: 920px) {
  .story-phone { --demo-k: .66; }
}
@media (max-width: 560px) {
  .story-phone { --demo-k: .6; }
}
/* ====================== end of the migrated block. Package B starts here ==
   Composition, the Mac surfaces, the smaller demos and every breakpoint.
   Everything below sits under `.home-redesign` or one of the frozen hooks in
   marketing/homepage-redesign/HANDOFF-A.md, so none of it can reach /press,
   /support, /blog or any other page: this file is linked from index.html
   alone, and nothing here was added to styles.css.
   ========================================================================== */

/* ------------------------------------------------------- shared, page-wide */
/* Motion. `--ease-out` and `--spring-capture` are the handset's own curves,
   lifted up here so the page can use them too; `.demo-phone` still declares
   its own copies and is untouched. The durations name what the migrated block
   already does by hand: .18/.32/.58 are its .22, .34 and .6. */
.home-redesign {
  --ease-out: cubic-bezier(.25, .1, .25, 1);
  --spring-capture: cubic-bezier(.32, .72, .24, 1);
  --dur-fast: .18s;
  --dur-mid: .32s;
  --dur-slow: .58s;

  /* Contrast. The design system's secondary ink is rgba(28,31,28,.6), which
     is 4.24:1 on canvas and 4.36:1 on paper — under AA either way, and this
     page introduces a lot of new secondary text (task meta, step bodies,
     captions). .68 is 5.45:1 on canvas, 5.3:1 on paper, and the warmth
     survives. The handset gets the design system's own value back below, so
     the pixel-verified screen keeps matching the app. */
  --text-secondary: rgba(28, 31, 28, .68);
}
.home-redesign .demo-phone { --text-secondary: rgba(28, 31, 28, .6); }

/* Package C hides and unhides six controls with the `hidden` attribute. Every
   one of them is given an explicit `display` somewhere below, which beats the
   UA rule behind `[hidden]`, so the attribute is restated here once. */
.home-redesign [hidden] { display: none !important; }

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

/* The device requirement, in both of its new positions. styles.css sets it in
   `--ink-tertiary`, which is 1.88:1 — that is unreadable, and this is the one
   line a reader has to take in before spending money. */
.home-redesign .requirement { color: rgba(28, 31, 28, .68); }
/* Under the final CTA the column is centred, so the marginal rule moves to
   the top and the block centres with it. */
.home-redesign .get .requirement {
  margin: var(--space-10) auto 0;
  padding: var(--space-7) 0 0;
  border-left: 0;
  border-top: 1px solid var(--ink-quaternary);
  max-width: 44ch;
}

/* Lucide marks used bare (no `.icon`) get their geometry from the sprite and
   nothing else: without this the replay glyph paints as a filled blob. */
.home-redesign .icon-sm,
.home-redesign .mac-win svg,
.home-redesign .float-win svg,
.home-redesign .mac-task svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.home-redesign .mac-win svg,
.home-redesign .float-win svg,
.home-redesign .mac-task svg { display: inline-block; flex: none; }

/* Two quiet controls. Neither is a primary action — the hero's one button
   is — so both are outlines on canvas. */
.home-redesign .ghost-btn {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 var(--space-7);
  border: 1px solid var(--ink-quaternary);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink);
  font: 600 14px/18px var(--font-system);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}
.home-redesign .ghost-btn:hover { border-color: var(--ink); background: var(--paper); }
.home-redesign .ghost-btn .icon-sm { width: 15px; height: 15px; margin-right: var(--space-2); }

.home-redesign .chip-btn {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 var(--space-7);
  border: 1px solid var(--ink-quaternary);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink);
  font: var(--type-subheadline-semibold);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.home-redesign .chip-btn:hover { border-color: var(--ink); }
/* The site-wide focus ring squares its host off at 4px; a pill keeps its own
   shape so the moss outline traces the button rather than boxing it. */
.home-redesign .chip-btn:focus-visible,
.home-redesign .ghost-btn:focus-visible { border-radius: var(--radius-pill); }
.home-redesign .chip-btn[aria-pressed="true"] {
  background: var(--action-primary);
  border-color: var(--action-primary);
  color: var(--text-on-primary);
}


/* ================================================================== hero ==
   The scene gets the wider column, and the paper card is lifted off the
   handset's lower corner. Its shadow is the one the screenshot frames used
   before the evidence band was removed: a light version of the handset's,
   because paper against canvas is only one step of value and a hairline
   alone will not carry that across a whole panel. */
/* The scene takes the wider share, and more of it than the still capture
   needed: the composition is three surfaces across a near-square box, and
   what it costs the copy is a measure the copy no longer wants — the lede is
   one line now and the requirement under the button is four words. */
.home-redesign .hero { grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr); gap: 48px; }

/* The hero's one button, standing where the App Store badge stood. The badge
   was 52px tall and set the height of that row, so the pill keeps 52 and the
   lines above and below it stay where they were. `.pill` itself is 40 and is
   the masthead's size; this is the only place the page asks for more. */
/* One action, on its own. "See how it works" stood beside it as bare text,
   floating against 52px of button with nothing to stand on, and dropped to
   a line of its own the moment the column narrowed. Made a button it did
   not fit: the copy column is 384px at its widest and the pair wants 414,
   so it stacked at every width the hero has two columns at.
   It is gone rather than stacked. The masthead already carries "How it
   works", and the scene beside this copy is the answer playing in full —
   a second button under the first, to scroll to three lines of text, was
   the least of the three things competing for that corner. */
.home-redesign .hero .pill-lg {
  height: 52px;
  padding: 0 var(--space-10);
  font: var(--type-headline);
  gap: var(--space-4);
}
/* The mark is flush to the top and bottom of its own 24 box — brand marks
   are drawn that way, and the two in the footer are the same — so it keeps
   `.icon-brand`'s 16 rather than taking the 18 a Lucide glyph would need to
   match this label. Centred by the flex line, not nudged. */
.home-redesign .hero .pill-mark { width: 16px; height: 16px; }

/* The scene is the stage now: the Mac window, the floating window and the
   handset, playing the note onto both. It is the same box "How it works"
   used to stand it in, so `--mac-k` is all that changes — chosen per tier
   against the narrowest viewport in the tier, so the stage never exceeds the
   column it is in. The stage box is 861 x --mac-k wide. */
.hero-scene { position: relative; }
.hero-scene .story-stage { margin: 0 auto; }



/* ========================================================= product story ==
   Three short steps in normal flow, one stage beside them. On a desktop tall
   enough to hold it the stage is sticky and the steps scroll past; everywhere
   else the stage is an ordinary block under the steps, because a scene the
   reader cannot see the whole of is worse than no scene.

   THE STAGE IS ONE NUMBER. `--mac-k` is the scale the two Mac surfaces are
   drawn at; the handset's own `--demo-k` and the stage box are both derived
   from it, and every position and every scene move below is a percentage. So
   one declaration per breakpoint moves the whole composition, and nothing
   inside any of the three surfaces ever reflows — the technique the handset
   already uses, in marketing/iphone-demo-design-notes.md. */
.story-steps { list-style: none; margin: 0; padding: 0; }
.story-step {
  position: relative;
  padding: var(--space-1) 0 var(--space-1) var(--space-9);
  border-left: 2px solid var(--ink-quaternary);
  transition: border-color var(--dur-mid) var(--ease-out);
}
.story-step + .story-step { margin-top: var(--space-12); }
.story-step-n {
  margin: 0;
  font: var(--type-caption2-bold);
  letter-spacing: var(--tracking-section);
  text-transform: uppercase;
  color: var(--text-secondary);
  transition: color var(--dur-mid) var(--ease-out);
}
.story-step-h {
  margin: var(--space-3) 0 0;
  font: 600 20px/26px var(--font-system);
  letter-spacing: -.01em;
  text-wrap: pretty;
}
.story-step .card-body { margin-top: var(--space-3); }
.story-step .transcript { margin-top: var(--space-4); }

/* The step the scene is on. Only the rule and the number change: the body of
   every step stays at full strength, so the two steps that are not current
   are as readable as the one that is — which is the state a reader with
   JavaScript off sees for two steps out of three, for good. */
.story-result {
  list-style: none;
  margin: var(--space-5) 0 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--ink-border-soft);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-card);
  overflow: hidden;
}
.story-result li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-2) var(--space-5);
  background: var(--paper);
  font: var(--type-subheadline);
}
.story-when { color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ------------------------------------------------------------- the stage */
.story-stage {
  /* 701 of viewport is 653 of content, and .75 is the most of that the stage
     can take. Below 701 the Mac window steps out — see the tier at the foot
     of this file. */
  --mac-k: .75;
  /* `.story-phone` declares `--demo-k` itself in the migrated block, and a
     property declared on the element beats one inherited from the stage — so
     the handset's scale is carried down under its own name and handed over in
     the rule below, where the specificity is high enough to land. */
  --phone-k: calc(var(--mac-k) * .765);
  position: relative;
  width: calc(800px * var(--mac-k) / .929);
  max-width: 100%;
  aspect-ratio: 861 / 880;
  margin: var(--space-12) auto 0;
}
.story-stage > .story-surface { position: absolute; transform-origin: 50% 50%; }

/* The Mac window: x 0, y 3%, and 92.9% of the stage wide. */
.story-desk {
  left: 0;
  top: 3%;
  width: calc(800px * var(--mac-k));
  height: calc(830px * var(--mac-k));
}
/* The floating window, over the Mac's lower right. */
.story-float {
  left: 59.4%;
  top: 44%;
  width: calc(340px * var(--mac-k));
  height: calc(480px * var(--mac-k));
}
/* The handset, centred: 31.6% + 37.3% wide puts its middle on the stage's. */
.story-stage .story-phone {
  --demo-k: var(--phone-k);
  left: 31.6%;
  top: 7.4%;
  width: calc(420px * var(--demo-k));
  height: calc(892px * var(--demo-k));
}

/* ----------------------------------------------------- the three surfaces */
.mac-win, .float-win {
  transform: scale(var(--mac-k));
  transform-origin: 0 0;
  font-family: var(--font-system);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-wrap: initial;
}

/* ----------------------------------------------------------- the Mac window
   Drawn from ~/work/offhand-launch-assets/mac/mac-hero-01-day.png at one
   design size and scaled as a unit. The proportions are that capture's: the
   sidebar is 22.6% of the window, the pager sits 24px into the main column,
   the day title is a little over three times the body, the task row carries a
   name over a meta line with the ring centred on both, the section count is
   right-aligned and the add button is a dark disc in the bottom right. The
   window is taller than the capture's because this one is full — seven tasks
   and a status line against that one's four. */
.mac-win {
  --mac-side: 181px;
  position: relative;
  width: 800px;
  height: 830px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 14px;
  background: var(--canvas);
  border: 1px solid rgba(28, 31, 28, .16);
  box-shadow: 0 40px 80px -34px rgba(28, 31, 28, .5), 0 6px 20px -12px rgba(28, 31, 28, .24);
}

.mac-bar {
  flex: none;
  display: grid;
  grid-template-columns: var(--mac-side) minmax(0, 1fr) auto;
  align-items: center;
  height: 52px;
  padding: 0 20px 0 18px;
}
.mac-lights { display: flex; gap: 8px; }
.mac-lights i { width: 12px; height: 12px; border-radius: 50%; box-shadow: inset 0 0 0 .5px rgba(28, 31, 28, .18); }
.mac-lights i:nth-child(1) { background: #ff5f57; }
.mac-lights i:nth-child(2) { background: #febc2e; }
.mac-lights i:nth-child(3) { background: #28c840; }

.mac-nav {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-left: 24px;
  font: 400 12px/16px var(--font-system);
  color: var(--text-secondary);
}
.mac-nav svg { width: 13px; height: 13px; }
.mac-nav-l { transform: rotate(180deg); }
.mac-nav-day {
  padding: 2px 11px;
  border-radius: var(--radius-pill);
  background: rgba(28, 31, 28, .07);
  color: var(--ink);
  font-weight: 500;
}

.mac-chord {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 7px;
  font: 400 11.5px/16px var(--font-system);
  color: var(--text-secondary);
}
.mac-chord svg { width: 13px; height: 13px; }
.mac-chord kbd {
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--paper);
  border: 1px solid var(--ink-quaternary);
  color: var(--ink);
  font: 600 11px/14px var(--font-system);
}

.mac-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--mac-side) minmax(0, 1fr);
}

.mac-side {
  display: flex;
  flex-direction: column;
  padding: 2px 11px 16px;
  border-right: 1px solid var(--ink-border-soft);
}
.mac-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 14px;
  padding-left: 8px;
  font: 600 14px/19px var(--font-system);
}
.mac-brand svg { width: 15px; height: 15px; }
.mac-side-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.mac-side-list li {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 30px;
  padding: 0 9px;
  border-radius: 7px;
  font: 400 13.5px/18px var(--font-system);
}
.mac-side-list svg { width: 15px; height: 15px; color: var(--text-secondary); }
.mac-side-list li.is-on { background: rgba(28, 31, 28, .07); font-weight: 500; }
.mac-side-n { margin-left: auto; font: 400 12px/16px var(--font-system); color: var(--text-secondary); }
.mac-side-foot {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: auto 0 0;
  padding-left: 9px;
  font: 400 11.5px/16px var(--font-system);
  color: var(--text-secondary);
}
.mac-side-foot svg { width: 13px; height: 13px; }

.mac-main { min-width: 0; padding: 22px 44px 0 40px; overflow: hidden; }
.mac-h1 { margin: 0; font: 700 28px/34px var(--font-system); letter-spacing: -.022em; }
.mac-sub { margin: 3px 0 0; font: 400 12.5px/17px var(--font-system); color: var(--text-secondary); }

.mac-chips { display: flex; gap: 8px; margin-top: 14px; }
.mac-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 11px;
  border-radius: var(--radius-pill);
  background: var(--paper);
  border: 1px solid var(--ink-quaternary);
  font: 500 11.5px/22px var(--font-system);
  /* The capture's chip is a paper pill with a coloured dot and an ink label,
     not a tinted pill like the iPhone's. `.is-work` and friends set `color`,
     so the dot takes its own property and the label keeps the ink. */
  color: var(--ink);
}
.mac-chip::before, .mac-tag::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--dot, currentColor);
}
.mac-chip.is-work { --dot: #b8503a; }
.mac-chip.is-groc { --dot: #4560c4; }
.mac-chip.is-fit  { --dot: #a67a1a; }

.mac-sec { margin-top: 16px; }
.mac-sec-h {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 1px;
  padding-left: 2px;
  font: 600 12.5px/18px var(--font-system);
}
.mac-sec-h > svg { width: 14px; height: 14px; }
.mac-now {
  height: 15px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  font: 700 8.5px/15px var(--font-system);
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--moss);
  background: var(--moss-badge);
}
.mac-sec-n { margin-left: auto; font: 400 12px/16px var(--font-system); color: var(--text-secondary); }

/* The counts before and after the save, the way `.ds-count` already does it. */
.mac-side-n::before, .mac-sec-n::before, .mac-sub span::before { content: attr(data-idle); }
[data-scene="review"] .mac-side-n::before,
[data-scene="review"] .mac-sec-n::before,
[data-scene="review"] .mac-sub span::before { content: attr(data-done); }

/* One task row, drawn once: it is the Mac window's row and the timing
   proof's result, so it has to read at page size as well as at `--mac-k`. */
.mac-task {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 12px;
  padding: 9px 14px;
  margin-top: 8px;
  background: var(--paper);
  border: 1px solid var(--border-card);
  border-radius: 12px;
}
.mac-check {
  grid-row: 1 / span 2;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--ink-checkbox);
}
.mac-name { font: 400 15px/21px var(--font-system); }
.mac-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 400 12px/16px var(--font-system);
  color: var(--text-secondary);
}
.mac-meta svg { width: 13px; height: 13px; }
.mac-tag { display: inline-flex; align-items: center; gap: 5px; margin-left: 2px; font-weight: 500; }

.mac-empty { margin: 5px 0 0 2px; font: 400 11.5px/16px var(--font-system); color: var(--text-secondary); }
.mac-done {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 18px 0 0 2px;
  font: 400 12px/16px var(--font-system);
  color: var(--text-secondary);
}
.mac-done svg { width: 14px; height: 14px; }
.mac-done-chev { width: 12px; height: 12px; margin-left: -2px; }

/* "Finding tasks…", and only after the save. `display` rather than opacity,
   so the spinner does not turn in a scene that is not asking for it; and the
   turn is counted, so nothing on this page runs without end. */
.mac-status { display: none; }
[data-scene="save"] .mac-status,
[data-scene="review"] .mac-status {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 16px 0 0 2px;
  font: 400 12.5px/18px var(--font-system);
  color: var(--text-secondary);
  animation: mac-rise var(--dur-mid) var(--ease-out) both;
}
.mac-spin {
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--ink-quaternary);
  border-top-color: var(--text-secondary);
  animation: ds-spin .8s linear 7;
}
.mac-status-finding { white-space: nowrap; }
.mac-status-done { display: none; align-items: center; gap: 6px; color: var(--moss); font-weight: 600; }
.mac-status-done svg { width: 13px; height: 13px; }
[data-scene="review"] .mac-spin, [data-scene="review"] .mac-status-finding { display: none; }
[data-scene="review"] .mac-status-done { display: inline-flex; }
@keyframes mac-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* The four tasks the note filed. Same four, in the same order, as the ones in
   the handset and in `.story-result` — the contract in HANDOFF-A. */
.mac-task.is-new { display: none; }
[data-scene="review"] .mac-task.is-new {
  display: grid;
  animation: mac-pop .42s var(--spring-capture) both;
  animation-delay: calc(var(--i) * 150ms);
}
[data-scene="review"] .mac-empty { display: none; }
@keyframes mac-pop {
  0%   { opacity: 0; margin-top: -57px; transform: translateY(8px) scale(.97); }
  100% { opacity: 1; margin-top: 8px; transform: none; }
}

.mac-add {
  position: absolute;
  right: 20px;
  bottom: 18px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--action-primary);
  color: var(--text-on-primary);
  box-shadow: 0 8px 18px -8px rgba(28, 31, 28, .55);
}
.mac-add svg { width: 17px; height: 17px; stroke-width: 2.4; }

/* ------------------------------------------------------ the floating window
   340 x 480, the real thing's own points, from
   mac/2026-09-09/floating-light.png. It is the one surface here that actually
   floats over other windows, so its chrome takes the glass treatment and the
   lift shadow; the rows stay paper, because that is what holds reading. */
.float-win {
  position: relative;
  width: 340px;
  height: 480px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 14px;
  background: rgba(245, 242, 232, .9);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  border: 1px solid rgba(28, 31, 28, .18);
  box-shadow: 0 28px 56px -22px rgba(28, 31, 28, .5), 0 4px 14px -6px rgba(28, 31, 28, .26);
}
.float-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--ink-border-soft);
}
.float-head > span:first-child { display: flex; flex-direction: column; gap: 2px; }
.float-head strong { font: 600 16px/20px var(--font-system); }
.float-head em { font: 400 12.5px/16px var(--font-system); font-style: normal; color: var(--text-secondary); }
.float-acts { display: flex; align-items: center; gap: 14px; color: var(--text-secondary); }
.float-acts svg { width: 15px; height: 15px; }
.float-body { flex: 1; min-height: 0; padding: 12px 13px 0; overflow: hidden; }
.float-task {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 42px;
  padding: 9px 13px;
  margin-bottom: 8px;
  background: var(--paper);
  border: 1px solid var(--border-card);
  border-radius: 12px;
  font: 400 14.5px/19px var(--font-system);
}
.float-task .mac-check { width: 16px; height: 16px; }
.float-sec {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 14px 0 8px 3px;
  font: 600 12.5px/17px var(--font-system);
}
.float-sec > svg { width: 14px; height: 14px; }
.float-foot {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 10px 16px 12px;
  border-top: 1px solid var(--ink-border-soft);
  font: 400 12px/16px var(--font-system);
  color: var(--text-secondary);
}
.float-foot svg { width: 14px; height: 14px; }

/* ========================================================= feature proof ==
   One feature out of the grid, with its demonstration beside it. The copy
   sits bare on canvas and the demo on paper, so the pair reads as two
   different kinds of thing rather than as two more cards. */
.proof {
  display: grid;
  grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr);
  gap: var(--space-12) 56px;
  align-items: center;
}
.proof-copy .card-body { margin-top: var(--space-4); }
.proof-copy .card-title { font: 600 22px/28px var(--font-system); letter-spacing: -.015em; }

.proof-demo {
  background: var(--paper);
  border: 1px solid var(--border-card);
  border-radius: var(--radius-panel);
  padding: var(--space-10) var(--space-9) var(--space-9);
  /* The result is on the page until Package C takes it away, and the reader
     puts it back. Holding the taller of the two states stops the panel
     jumping under the button that changed it. */
  min-height: 268px;
  display: flex;
  flex-direction: column;
}
.proof-label {
  margin: 0;
  font: var(--type-caption2-bold);
  letter-spacing: var(--tracking-section);
  text-transform: uppercase;
  color: var(--moss);
}
.proof-said {
  margin: var(--space-5) 0 0;
  font: var(--type-transcript);
  color: var(--ink);
  text-wrap: pretty;
}
.proof-got { display: grid; margin-top: var(--space-2-5); }
.proof-got .mac-task { margin-top: var(--space-3); }
/* Paper on paper is no card at all: inside the two demo panels the row takes
   the canvas fill and a soft ink hairline, which is the same one step of
   value the app's paper-on-canvas row has, the other way up. */
.proof-got .mac-task { background: var(--canvas); border-color: var(--ink-border-soft); }
.proof-acts { display: flex; align-items: center; gap: var(--space-4); margin-top: auto; padding-top: var(--space-8); }

.features-rest { margin-top: 56px; }

/* The line out of a band and into the post behind it. */
.band-more { margin: var(--space-10) 0 0; font: var(--type-subheadline-semibold); }


/* ========================================================== scene states ==
   Three discrete compositions, told in transform and opacity only, every
   figure a percentage of the surface's own box so one `--mac-k` moves all of
   them. They settle; nothing overshoots, and nothing repeats. */
.story-stage > .story-surface {
  transition: transform var(--dur-slow) var(--spring-capture), opacity var(--dur-mid) var(--ease-out);
}

/* Capture: the handset forward with its panel open, the Mac set back behind
   it, the floating window not yet in the story. */
[data-scene="capture"] .story-desk  { transform: translate(2.9%, 4.6%) scale(.93); opacity: .5; z-index: 1; }
[data-scene="capture"] .story-phone { transform: none; opacity: 1; z-index: 4; }
[data-scene="capture"] .story-float { transform: translate(0, 4%) scale(.96); opacity: 0; z-index: 2; }

/* Save: the Mac comes forward and the handset recedes across its lower left,
   close enough that the open capture panel still reads as attached to it. */
[data-scene="save"] .story-desk  { transform: none; opacity: 1; z-index: 3; }
/* Far enough left that the handset stands over the window's sidebar and not
   over its content column: "Finding tasks…" is the whole point of this scene
   and the phone must not be sitting on it. The small overhang past the
   stage's left edge falls in the 48px gap, never on the steps. */
[data-scene="save"] .story-phone { transform: translate(-106%, 19%) scale(.78); opacity: 1; z-index: 4; }
[data-scene="save"] .story-float { transform: translate(0, 4%) scale(.96); opacity: 0; z-index: 2; }

/* Review: the window settled with its four new rows, the floating window
   arrived over it, and the handset still there at the foot — carrying the
   same four tasks, which is the whole claim of this scene.

   The handset is drawn as large as the stage allows and pushed hard left, so
   that what it covers is the Mac's sidebar and nothing of the day itself. Two
   things set those numbers and neither is free to move far. It may hang about
   40px past the stage's left edge, because the story grid puts a 48px gap
   there and the steps begin after it — 48 is the budget, 40 is the budget
   with a margin. And its own width at this tier is 231px before this scale,
   so .72 is 166px: below about .7 the task rows stop being rows and become
   texture, which is the state this scene was in when it was .58, a 134px
   thumbnail of the list the Mac beside it was already showing at full size.
   Raising it uncovers the sidebar's own foot as a side effect — "Stored on
   this Mac", which is a sentence worth not hiding. */
[data-scene="review"] .story-desk  { transform: none; opacity: 1; z-index: 2; }
[data-scene="review"] .story-phone { transform: translate(-116%, 29%) scale(.72); opacity: 1; z-index: 3; }
[data-scene="review"] .story-float { transform: none; opacity: 1; z-index: 4; }


/* ========================================================== breakpoints ==
   `--mac-k` per tier, chosen against the narrowest viewport in the tier so
   the stage never exceeds its column. The stage box is 800/.929 x --mac-k
   square, so the check is: 861 x k <= the shell's content width. */

/* One column still, and the shell has grown: 861 of viewport is 813 of
   content, and .93 is the most of that the stage can take. */
@media (min-width: 861px) { .story-stage { --mac-k: .93; } }

/* From 921 the hero is two columns and the stage is in the right-hand one —
   1.22 of 2 of the content width, less the 48px between them. That column is
   503 at the bottom of this tier and 600 once the shell stops growing at
   1080, and .58 and .69 are those two divided by the stage's own 861. The
   sticky layout this composition was drawn for stood it in 620px at .72, so
   the wide tier is very nearly the size it was designed at. */
@media (min-width: 921px)  { .story-stage { --mac-k: .58; } }
@media (min-width: 1080px) { .story-stage { --mac-k: .69; } }

/* Under 700 the Mac window can only be a thumbnail — at 350px of column its
   task names would draw at six pixels — so it steps out, and the two surfaces
   that stay are the two that are still legible at this width: the handset at
   its own scale and the floating window at very nearly its own 340 points.
   The step copy carries the Mac; `.story-step` 3 names it in words. */
@media (max-width: 700px) {
  .story-stage {
    --phone-k: .58;
    --float-k: .88;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-12);
    width: auto;
    aspect-ratio: auto;
    margin-top: var(--space-10);
  }
  .story-stage > .story-surface {
    position: relative;
    left: auto;
    top: auto;
    transform: none;
    opacity: 1;
    transition: none;
  }
  .story-stage .story-phone { order: 1; }
  .story-float { order: 2; top: auto; left: auto; width: calc(340px * var(--float-k)); height: calc(480px * var(--float-k)); }
  .float-win { transform: scale(var(--float-k)); }
  .story-desk { display: none; }
}
@media (max-width: 380px) {
  .story-stage { --phone-k: .52; --float-k: .8; }
}

/* Hero, proof and evidence. */
@media (max-width: 1039px) {
  .proof { gap: var(--space-12) 40px; }
}
@media (max-width: 920px) {
  .home-redesign .hero { grid-template-columns: minmax(0, 1fr); }
  /* One column, so the stage has the whole shell and takes the base
     `--mac-k` the old two-column story used at this width. */
  .hero-scene { margin-inline: auto; }
  .proof { grid-template-columns: minmax(0, 1fr); }
  .proof-demo { min-height: 0; }
  .features-rest { margin-top: 40px; }
}
@media (max-width: 720px) {
  .story-step + .story-step { margin-top: var(--space-10); }
}
@media (max-width: 560px) {
  .proof-demo { padding: var(--space-8); }
}
@media (max-width: 400px) {
  .mac-task { padding: 8px 11px; column-gap: 10px; }
  .story-step { padding-left: var(--space-5); }
}


/* ======================================================== reduced motion ==
   Everything above that moves is spatial: the scene choreography, the row
   entrances, the status rise, the spinner. With the preference set there is
   no choreography at all — the stage rests on the composition the review
   state means, whichever scene the reader is on, and every state change lands
   at once. The handset's own branch, the four lines it already had, is kept.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .ds-list, .ds-pill, .ds-panel, .ds-panel-in, .ds-capsule, .ds-send, .ds-veil { transition: none; }
  .ds-new, .ds-spin, .ds-wave i, .ds-ripple, .key-action.hit { animation: none; }

  .home-redesign [data-hero-story] .story-surface,
  .home-redesign .story-step,
  .home-redesign .story-step-n,
  .home-redesign .ghost-btn,
  .home-redesign .chip-btn { transition: none; }

  /* The stage holds the review arrangement in every scene: no surface slides,
     scales or fades as the reader moves between the steps. */
  .home-redesign [data-hero-story] .story-desk  { transform: none; opacity: 1; z-index: 2; }
  .home-redesign [data-hero-story] .story-float { transform: none; opacity: 1; z-index: 4; }
  .home-redesign [data-hero-story] .story-phone { transform: translate(-116%, 29%) scale(.72); opacity: 1; z-index: 3; }

  .home-redesign .mac-status { animation: none; }
  .home-redesign .mac-spin { animation: none; border-top-color: var(--ink-quaternary); }
  .home-redesign [data-scene="review"] .mac-task.is-new { animation: none; }
}
@media (prefers-reduced-motion: reduce) and (max-width: 700px) {
  /* Stacked already: the phone keeps its place in the flow. */
  .home-redesign [data-hero-story] .story-phone { transform: none; }
}
