/* ============================================================
   "From a sentence to a finished image"
   Left column scrolls through four steps; the right column is a
   sticky panel that swaps a mock UI per step.

   ONE set of markup drives both layouts. Desktop places steps in
   column 1 and stacks every panel in column 2; mobile resets the
   grid so source order takes over — step copy, then its graphic,
   four times. No duplicated markup.
   ============================================================ */
.fs{
  background:#FBF7F2; border-block:1px solid var(--line-2);
  padding-block:clamp(52px,7vw,104px) clamp(18px,2.4vw,36px);
}
.fs-head{max-width:60ch; margin-bottom:clamp(34px,4.4vw,58px)}
.fs-title{
  font-family:var(--f-dis); font-weight:800; letter-spacing:-.045em; line-height:1.02;
  font-size:clamp(32px,5.2vw,62px);
}
.fs-lede{margin-top:18px; max-width:46ch; font-size:clamp(15.5px,1.4vw,17px); line-height:1.6; color:var(--ink-2)}

.fs-grid{
  display:grid; grid-template-columns:minmax(0,.84fr) minmax(0,1.16fr);
  /* Explicit rows are REQUIRED here. Without them the grid has no explicit
     row lines, so `grid-row:1/-1` on the panels resolves -1 to line 1 and
     collapses to a single row — row 1 then stretches to the panel's full
     height while rows 2-4 stay short, which threw the step rhythm off.
     One track per step also guarantees a constant title-to-title distance. */
  /* Four step rows plus a TAIL row. The panel spans 1/-1, so the tail
     extends its containing block and therefore its sticky travel. Without
     it the panel runs out of track at ~281px while step 4 only activates
     after ~648px of scroll — so it unstuck and scrolled off the top long
     before step 4 was readable. The tail is what keeps it pinned. */
  grid-template-rows:repeat(4, minmax(216px, auto)) clamp(170px, 24vh, 300px);
  column-gap:clamp(28px,5vw,78px);
}

/* ---------- steps ---------- */
/* Every step reserves the SAME fixed block, whether or not its copy is
   showing. Sizing to content made step 1 (expanded on load) taller than
   the collapsed ones, so the title-to-title rhythm changed as you
   scrolled. A fixed reserve also gives the sticky panel room to travel. */
.fs-step{
  grid-column:1; border-left:2px solid var(--line);
  padding:0 0 0 clamp(18px,2vw,26px);
  display:flex; flex-direction:column;
  transition:border-color .5s var(--ease);
}
.fs-step p{max-width:46ch}
.fs-step.is-on{border-left-color:var(--saf)}
.fs-n{
  display:block; font-family:var(--f-mon); font-size:10.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--saf); opacity:.5; transition:opacity .45s var(--ease);
}
.fs-step.is-on .fs-n{opacity:1}
.fs-step h3{
  margin-top:9px; font-family:var(--f-dis); font-weight:700; letter-spacing:-.032em;
  font-size:clamp(20px,2.3vw,29px); color:#B9AFA6; transition:color .5s var(--ease);
}
.fs-step.is-on h3{color:var(--ink)}
/* copy stays revealed once a step has been reached — the list accumulates */
.fs-step p{
  font-size:14.6px; line-height:1.62; color:var(--ink-2); max-width:46ch;
  max-height:0; opacity:0; overflow:hidden;
  transition:max-height .55s var(--ease), opacity .45s var(--ease), margin-top .55s var(--ease);
  margin-top:0;
}
/* 5.6em fits inside the 216px reserve — a longer paragraph would
   overflow the block and break the constant spacing */
.fs-step.seen p{max-height:5.6em; opacity:1; margin-top:11px}

/* ---------- sticky panel column ---------- */
.fs-viz{
  grid-column:2; grid-row:1 / -1; position:sticky; top:88px; align-self:start;
  transition:opacity .45s var(--ease), transform .45s var(--ease);
}
/* Specificity matters here. The shared reveal system sets
   [data-animate].is-in{opacity:1} at (0,2,0), which outranks a plain
   .fs-viz{opacity:0} — so every panel was fully opaque and only
   visibility:hidden was holding it back, on a 0.55s transition. That gap is
   what let panel 4's export list show through on step 3. This selector is
   (0,3,0) and visibility is no longer transitioned, so it flips at once. */
.fs-grid > .fs-viz:not(.is-on){
  opacity:0; visibility:hidden; pointer-events:none; transform:scale(.985);
}
.fs-viz.is-on{opacity:1; visibility:visible; transform:none}
/* sticky + taller-than-viewport means the top is unreachable, so cap it */
.fs-viz{max-height:calc(100vh - 108px)}
@media (max-width:900px){ .fs-viz{max-height:none} }
.fs-panel{
  position:relative; border:1px solid var(--line-2); border-radius:24px;
  background:linear-gradient(180deg,#FFFDFB 0%,#FDF9F4 100%);
  padding:clamp(18px,2.2vw,30px); overflow:hidden;
  box-shadow:0 30px 70px -44px rgba(80,50,20,.20);
}
/* the faint warm bloom the mockups carry behind the mock UI */
.fs-panel::before{
  content:""; position:absolute; left:8%; top:-18%; width:62%; aspect-ratio:1; pointer-events:none;
  background:radial-gradient(circle, rgba(241,115,31,.10) 0%, transparent 66%);
}

/* floating badge, shared by the panels */
.fb{
  position:absolute; z-index:6; width:clamp(44px,4vw,58px); aspect-ratio:1; border-radius:16px;
  display:grid; place-items:center; background:#fff; color:var(--saf);
  border:1px solid var(--line-2); box-shadow:0 12px 28px -14px rgba(80,50,20,.30);
  animation:fbFloat 5.5s ease-in-out infinite;
}
@keyframes fbFloat{0%,100%{transform:translateY(0)} 50%{transform:translateY(-7px)}}
.fb-2{animation-delay:-1.8s}
.fb-3{animation-delay:-3.4s}
/* dashed connectors */
.fs-arrow{position:absolute; z-index:5; pointer-events:none; overflow:visible}
.fs-arrow path{
  fill:none; stroke:var(--saf); stroke-width:1.6; stroke-dasharray:5 6; opacity:.55;
  animation:dashRun 2.4s linear infinite;
}
@keyframes dashRun{to{stroke-dashoffset:-22}}

/* ============================================================
   PANEL 1 — describe the idea
   ============================================================ */
.v1{display:flex; gap:clamp(10px,1.4vw,18px); align-items:flex-start; position:relative; z-index:4}
.v1-win{
  flex:1 1 56%; min-width:0; background:#fff; border:1px solid var(--line-2); border-radius:16px;
  box-shadow:0 16px 40px -26px rgba(80,50,20,.26); overflow:hidden;
}
.v1-bar{display:flex; gap:5px; padding:11px 14px; border-bottom:1px solid var(--line-2)}
.v1-bar i{width:8px; height:8px; border-radius:50%; background:var(--saf-l); opacity:.85}
.v1-bar i:nth-child(2){opacity:.6} .v1-bar i:nth-child(3){opacity:.4}
.v1-body{padding:14px}
.v1-prompt{
  border:1px solid var(--saf-100); background:#FFFCF9; border-radius:11px; padding:12px 13px;
  font-size:13.4px; line-height:1.5; color:var(--ink); min-height:5.2em;
}
.v1-prompt .cur{display:inline-block; width:6px; height:1em; margin-left:2px; vertical-align:-.13em; background:var(--saf); animation:blink 1s steps(1) infinite}
.v1-chips{display:flex; gap:8px; margin-top:12px}
.v1-chip{font-family:var(--f-mon); font-size:10.5px; padding:6px 10px; border-radius:8px; border:1px solid var(--line); color:var(--ink-3); background:#fff}
.v1-chip.on{background:var(--saf-50); border-color:var(--saf-100); color:#9A3D07}
.v1-lines{display:grid; gap:8px; margin-top:14px}
.v1-lines i{height:8px; border-radius:5px; background:#F1EAE1}
.v1-lines i:nth-child(1){width:82%} .v1-lines i:nth-child(2){width:92%} .v1-lines i:nth-child(3){width:64%}
.v1-out{
  flex:0 0 38%; border-radius:14px; overflow:hidden; position:relative; aspect-ratio:3/4;
  border:4px solid #fff; box-shadow:0 20px 44px -22px rgba(80,50,20,.38); margin-top:26px;
}
.v1-out img{width:100%; height:100%; object-fit:cover}

/* ============================================================
   PANEL 2 — choose the look
   ============================================================ */
.v2{position:relative; z-index:4}
.v2-pill{
  display:flex; align-items:center; gap:11px; width:max-content; max-width:100%;
  margin:0 auto 16px; padding:9px 14px 9px 10px; border-radius:14px; background:#fff;
  border:1px solid var(--line-2); box-shadow:0 12px 30px -18px rgba(80,50,20,.28);
}
.v2-pill .sp{width:32px; height:32px; border-radius:9px; display:grid; place-items:center; background:var(--saf-50); color:var(--saf); flex:none}
.v2-pill span{font-size:13.2px; line-height:1.35; color:var(--ink); border-left:1px solid var(--line); padding-left:11px}
/* the rail is a window; the track inside it slides so the active card
   always lands in the centre slot */
.v2{--v2-w:clamp(58px,9.4vw,124px); --v2-gap:clamp(6px,.8vw,11px)}
.v2-rail{
  position:relative; overflow:hidden;
  /* room for the centre card's 1.16 scale and its ring */
  padding-block:clamp(16px,2.2vw,26px);
}
.v2-track{
  display:flex; gap:var(--v2-gap); width:max-content;
  transition:transform .62s var(--ease); will-change:transform;
}
.v2-track.jump{transition:none}
.v2-card{
  position:relative; flex:0 0 auto; width:var(--v2-w); aspect-ratio:3/4.4;
  border-radius:13px; overflow:hidden; background:#EFE7DE;
  transition:transform .55s var(--ease), box-shadow .55s var(--ease), opacity .55s var(--ease);
  opacity:.62; transform:scale(.9);
}
.v2-card img{width:100%; height:100%; object-fit:cover}
.v2-card b{
  position:absolute; left:50%; bottom:9px; transform:translateX(-50%);
  font-family:var(--f-mon); font-size:9.5px; font-weight:500; white-space:nowrap;
  padding:5px 9px; border-radius:999px; background:rgba(255,255,255,.94); color:var(--ink-2);
}
.v2-card.on{
  opacity:1; transform:scale(1.16); z-index:3;
  box-shadow:0 0 0 2.5px var(--saf), 0 22px 46px -20px rgba(80,50,20,.42);
}
.v2-card.on b{color:#9A3D07}
.v2-dots{display:flex; align-items:center; justify-content:center; gap:12px; margin-top:16px}
.v2-nav{
  width:28px; height:28px; border-radius:50%; display:grid; place-items:center;
  color:var(--saf-d); background:#fff; border:1px solid var(--line);
  transition:.28s var(--ease); flex:none;
}
.v2-nav:hover{background:var(--saf); border-color:var(--saf); color:#fff; transform:translateY(-1px)}
.v2-nav:active{transform:translateY(0) scale(.94)}
.v2-dots .row{display:flex; align-items:center; gap:7px}
.v2-dot{
  width:7px; height:7px; padding:0; border-radius:50%; background:var(--saf-100);
  border:0; cursor:pointer; transition:.4s var(--ease); flex:none;
}
.v2-dot:hover{background:var(--saf-l)}
.v2-dot.on{width:10px; height:10px; background:var(--saf); box-shadow:0 0 0 3px var(--saf-50)}
.v2-note{
  display:flex; align-items:center; justify-content:center; gap:8px; margin-top:14px;
  font-family:var(--f-mon); font-size:11.5px; color:var(--saf-d);
}

/* ============================================================
   PANEL 3 — generate in seconds
   ============================================================ */
/* stretch, not start: the image now fills the row so there is no gap
   under it, and the left column is wider so the checklist labels fit on
   one line instead of wrapping */
.v3{
  display:grid; grid-template-columns:minmax(0,1.08fr) minmax(0,.92fr);
  gap:clamp(12px,1.8vw,26px); align-items:stretch; position:relative; z-index:4;
}
.v3-card{background:#fff; border:1px solid var(--line-2); border-radius:16px; padding:16px; box-shadow:0 16px 40px -26px rgba(80,50,20,.26)}
.v3-hd{display:flex; align-items:center; gap:9px}
.v3-hd .sp{color:var(--saf); flex:none}
.v3-hd b{font-family:var(--f-dis); font-size:16.5px; letter-spacing:-.028em}
.v3-hd .st{margin-left:auto; font-family:var(--f-mon); font-size:9.5px; padding:4px 8px; border-radius:999px; background:var(--saf-50); color:#9A3D07; white-space:nowrap}
.v3-prompt{margin-top:13px; padding:11px 12px; border-radius:10px; background:#FAF6F1; font-size:12.6px; line-height:1.5; color:var(--ink-2)}
.v3-list{display:grid; gap:2px; margin-top:13px}
.v3-item{
  display:flex; align-items:flex-start; gap:10px; padding:8px 9px; border-radius:9px;
  font-size:12.8px; line-height:1.45; color:var(--ink-3); transition:.4s;
}
.v3-item .dot{margin-top:1px}
.v3-item .dot{width:17px; height:17px; border-radius:50%; border:1.6px solid #E4DACF; display:grid; place-items:center; flex:none; transition:.4s}
.v3-item .dot svg{opacity:0; transition:.3s}
.v3-item.done{color:var(--ink)}
.v3-item.done .dot{background:var(--saf); border-color:var(--saf); color:#fff}
.v3-item.done .dot svg{opacity:1}
.v3-item.now{color:var(--ink); background:#FAF6F1}
/* the working step spins its own ring: three sides stay faint, one side
   takes the accent, and the whole frame rotates — so "in progress" reads
   as motion rather than as another static dot */
.v3-item.now .dot{
  border-width:2px; border-style:solid;
  border-color:var(--saf-100) var(--saf-100) var(--saf-100) var(--saf);
  animation:dotSpin .75s linear infinite;
}
.v3-item.now .dot::after{content:none}
@keyframes dotSpin{to{transform:rotate(360deg)}}
/* a pending step is just an empty ring */
.v3-item .dot{border-width:1.6px; border-style:solid}
.v3-bar{display:flex; align-items:center; gap:10px; margin-top:14px}
.v3-bar .tr{flex:1; height:7px; border-radius:6px; background:#F1EAE1; overflow:hidden}
.v3-bar .tr i{display:block; height:100%; width:0; border-radius:6px; background:linear-gradient(90deg,var(--saf),var(--saf-l))}
.v3-bar b{font-family:var(--f-mon); font-size:11.5px; color:var(--ink-2); font-variant-numeric:tabular-nums; min-width:3.2em; text-align:right}
.v3-out{
  position:relative; border-radius:16px; overflow:hidden; height:100%; min-height:220px;
  box-shadow:0 20px 46px -24px rgba(80,50,20,.36);
}
.v3-out img{width:100%; height:100%; object-fit:cover; transition:filter 1s var(--ease)}
.v3-out.busy img{filter:blur(14px) saturate(1.3)}
.v3-done{
  position:absolute; top:12px; right:12px; z-index:3; display:flex; align-items:center; gap:6px;
  padding:7px 12px; border-radius:999px; background:#fff; font-size:11.5px; font-weight:600; color:var(--ink);
  box-shadow:0 8px 20px -10px rgba(0,0,0,.3); opacity:0; transform:translateY(-6px); transition:.45s var(--ease);
}
.v3-done svg{color:var(--signal)}
.v3-out.ok .v3-done{opacity:1; transform:none}
.v3-toast{
  position:absolute; left:50%; bottom:14px; transform:translate(-50%,10px); z-index:3;
  display:flex; align-items:center; gap:8px; padding:10px 16px; border-radius:999px; background:#fff;
  font-family:var(--f-mon); font-size:11.5px; color:var(--saf-d);
  box-shadow:0 14px 32px -14px rgba(80,50,20,.4); opacity:0; transition:.5s var(--ease);
}
.v3-out.ok .v3-toast{opacity:1; transform:translate(-50%,0)}

/* ============================================================
   PANEL 4 — refine and export
   ============================================================ */
.v4{position:relative; z-index:4}
.v4-tools{
  display:flex; gap:2px; flex-wrap:wrap; background:#fff; border:1px solid var(--line-2);
  border-radius:13px; padding:6px; box-shadow:0 12px 30px -22px rgba(80,50,20,.26);
}
.v4-tool{
  display:flex; align-items:center; gap:6px; padding:8px 11px; border-radius:9px;
  font-size:12.2px; color:var(--ink-2); white-space:nowrap; transition:.35s;
}
.v4-tool svg{color:var(--ink-3); transition:.35s}
.v4-tool.on{background:var(--saf-50); color:#9A3D07; font-weight:600}
.v4-tool.on svg{color:var(--saf)}
/* stacked: image on top, export options underneath */
.v4-main{display:grid; gap:11px; margin-top:11px}
.v4-stage{background:#fff; border:1px solid var(--line-2); border-radius:14px; overflow:hidden}
.v4-img{position:relative; aspect-ratio:16/9}
/* most laptops sit under 940px of viewport height — a flatter frame is what
   keeps the whole panel inside it */
@media (max-height:940px){ .v4-img{aspect-ratio:2.4/1} }
.v4-img img{width:100%; height:100%; object-fit:cover}
.v4-prev{
  position:absolute; top:10px; right:10px; display:flex; align-items:center; gap:6px;
  padding:6px 11px; border-radius:999px; background:rgba(20,16,12,.82); color:#fff; font-size:11px;
}
.v4-foot{display:flex; align-items:center; gap:12px; padding:9px 12px; border-top:1px solid var(--line-2); font-size:11.5px; color:var(--ink-3)}
.v4-foot .sp{margin-left:auto}
.v4-side{background:#fff; border:1px solid var(--line-2); border-radius:14px; padding:11px 12px}
.v4-exp-hd{display:flex; align-items:center; gap:12px; flex-wrap:wrap}
.v4-side h4{font-family:var(--f-dis); font-size:14.5px; letter-spacing:-.024em}
.v4-exp-hd .v4-sel{margin-left:auto; margin-top:0; padding:7px 10px; font-size:11.2px}
.v4-fmt{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:7px; margin-top:11px}
.v4-row{
  position:relative; display:flex; align-items:center; gap:8px; padding:8px 9px;
  border:1px solid var(--line-2); border-radius:10px; min-width:0;
  transition:transform .35s var(--ease), border-color .35s var(--ease),
             background .35s var(--ease), box-shadow .35s var(--ease);
}
.v4-row .ic{width:24px; height:24px; border-radius:7px; display:grid; place-items:center; background:var(--paper-3); color:var(--ink-3); font-family:var(--f-mon); font-size:8px; font-weight:500; flex:none}
.v4-row b{display:block; font-size:12.2px; font-weight:600}
.v4-row span{display:block; font-size:10.5px; color:var(--ink-3)}
/* these must stay on one line — wrapping them is what inflated the panel */
.v4-row b,.v4-row span span{white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.v4-sel,.v4-dl,.v4-cp{white-space:nowrap}
.v4-row .rd{
  flex:0 0 15px; width:15px; height:15px; min-width:15px; min-height:15px;
  aspect-ratio:1; box-sizing:border-box; border-radius:999px;
  border:1.6px solid #E0D5C9; margin-left:auto; align-self:center;
  display:grid; place-items:center; padding:0; transition:.35s;
}
/* The selected format has to be obvious at a glance, so it does three things
   at once: a full saffron outline, a lift in scale above the other three, and
   a solid filled dot rather than a ring with a pip in it.
   The 1.06 scale grows a ~150px tile by ~9px total, i.e. ~4.5px a side — it
   fits inside the 7px grid gap, so the raised tile never collides with its
   neighbours. position:relative + z-index keeps it painted over them. */
.v4-row.on{
  border-color:var(--saf); background:#FFFCF9; z-index:2;
  transform:scale(1.06);
  box-shadow:0 0 0 1px var(--saf), 0 12px 24px -16px rgba(241,115,31,.6);
}
.v4-row.on .ic{background:var(--saf-50); color:#9A3D07}
.v4-row.on b{color:#9A3D07}
/* A solid filled disc, not an outline with a pip floating inside it.
   A white tick was tried here first and dropped: at 15px the stroke lands
   under 2px and reads as a smudge rather than a check, so the clean fill
   plus the halo carries the state better. */
.v4-row.on .rd{
  background:var(--saf); border-color:var(--saf);
  box-shadow:0 0 0 3px var(--saf-50);
}
.v4-row.on .rd::after{content:none}
.v4-actions{display:flex; gap:8px; margin-top:11px}
.v4-dim{margin-top:13px}
.v4-dim label{display:block; font-size:11px; font-weight:600; color:var(--ink-2)}
.v4-sel{
  display:flex; align-items:center; margin-top:6px; padding:9px 11px; border:1px solid var(--line);
  border-radius:9px; font-size:11.8px; color:var(--ink-2); background:#fff;
}
.v4-sel svg{margin-left:auto; color:var(--ink-3)}
.v4-dl{
  flex:1 1 auto; display:flex; align-items:center; justify-content:center; gap:8px; padding:11px;
  border-radius:10px; background:var(--saf); color:#fff; font-size:12.8px; font-weight:600;
  border:0; cursor:pointer; font-family:inherit; transition:.25s var(--ease);
}
.v4-dl:hover{background:var(--saf-d)}
.v4-dl:active{transform:scale(.985)}
.v4-dl.done{background:var(--signal)}
.v4-cp{
  flex:0 0 auto; display:flex; align-items:center; justify-content:center; gap:8px;
  padding:11px 14px; border-radius:10px; background:var(--paper-3); color:var(--ink-2);
  font-size:12.4px; font-weight:500; border:0; cursor:pointer; font-family:inherit;
  transition:.25s var(--ease);
}
.v4-cp:hover{background:var(--line-2); color:var(--ink)}
.v4-cp.done{background:var(--signal-50); color:var(--signal)}
.v4-row{cursor:pointer}
.v4-saved{
  display:flex; align-items:center; gap:10px; margin-top:10px; padding:9px 13px; border-radius:11px;
  background:var(--signal-50); border:1px solid rgba(15,118,110,.22); font-size:12.2px; color:var(--ink-2);
}
.v4-saved svg{color:var(--signal); flex:none}
.v4-saved b{color:var(--ink); font-weight:600}

/* ------------------------------------------------------------
   Panel 4 is the tall one. Rather than hand-tuning heights and
   hoping they add up, the panel is a flex column capped to the
   viewport: the toolbar, export block and saved bar keep their
   natural height, and the image is the one flexible element, so
   it absorbs whatever space is left. The panel therefore cannot
   overflow the viewport no matter what the content does.
   ------------------------------------------------------------ */
/* The cap must be an absolute length, not a percentage. `max-height:100%`
   resolves against the parent's CONTENT height, and .fs-viz has no definite
   height — so it computed to `none` and nothing was ever constrained. The
   viewport unit is definite, so the flex squeeze actually engages. */
.fs-viz[data-v="3"]{max-height:calc(100vh - 108px)}
.fs-viz[data-v="3"] > .fs-panel{
  max-height:calc(100vh - 108px); min-height:0; display:flex; flex-direction:column;
}
.fs-viz[data-v="3"] .v4{display:flex; flex-direction:column; min-height:0; flex:1 1 auto}
.fs-viz[data-v="3"] .v4-tools,
.fs-viz[data-v="3"] .v4-side,
.fs-viz[data-v="3"] .v4-saved{flex:0 0 auto}
/* the grid becomes a column so the stage can shrink */
.fs-viz[data-v="3"] .v4-main{display:flex; flex-direction:column; gap:11px; min-height:0; flex:1 1 auto}
.fs-viz[data-v="3"] .v4-stage{display:flex; flex-direction:column; min-height:0; flex:0 1 auto}
/* flex-shrink on an aspect-ratio box lets it give up height when squeezed */
.fs-viz[data-v="3"] .v4-img{flex:0 1 auto; min-height:104px}
.fs-viz[data-v="3"] .v4-img img{width:100%; height:100%; object-fit:cover}

/* ============================================================
   MOBILE — grid resets, source order takes over:
   step copy, then that step's graphic, four times.
   ============================================================ */
@media (max-width:900px){
  /* minmax(0,1fr) not 1fr: a bare 1fr means minmax(AUTO,1fr), so a panel
     whose min-content is wider than the screen grows the column past the
     container and its contents spill outside the section. */
  .fs-grid{grid-template-columns:minmax(0,1fr); grid-template-rows:none; column-gap:0}
  .fs{padding-block:clamp(46px,8vw,72px)}
  .fs-step,.fs-viz{min-width:0}
  .fs-panel{max-width:100%}
  /* no sticky travel on mobile, so the reserved band would only add dead space */
  .fs-step{grid-column:1; border-left:0; padding-left:0; padding-bottom:14px; min-height:0}
  .fs-step h3{color:var(--ink)}
  .fs-step .fs-n{opacity:1}
  .fs-step p{max-height:none; opacity:1; margin-top:11px}
  .fs-viz{
    grid-column:1; grid-row:auto; position:static;
    margin:4px 0 clamp(34px,7vw,52px);
  }
  /* The desktop swap rule `.fs-grid > .fs-viz:not(.is-on)` is (0,3,0) and
     `is-on` is only ever applied to a panel on desktop (site.js gates it
     behind desktop()). So on mobile panels 2-4 stayed visibility:hidden —
     only panel 1 showed, because its is-on is hardcoded in the markup.
     This override has to MATCH that specificity to win, which a bare
     `.fs-viz` does not. Every panel is simply visible here; there is no
     swapping on mobile. */
  .fs-grid > .fs-viz:not(.is-on){
    opacity:1; visibility:visible; pointer-events:auto; transform:none;
  }
  /* on mobile each panel reveals as it scrolls in, rather than swapping.
     Also (0,3,0), but later in source, so it takes the opacity back. */
  .fs-grid > .fs-viz[data-animate]{opacity:0; transform:translateY(20px)}
  .fs-grid > .fs-viz[data-animate].is-in{opacity:1; transform:none}
  .v3{grid-template-columns:minmax(0,1fr)}
  .v3-out{height:auto; aspect-ratio:4/3; min-height:0}
  .fs-viz[data-v="3"]{max-height:none}
  .fs-viz[data-v="3"] > .fs-panel{max-height:none; display:block}
  .fs-viz[data-v="3"] .v4-img{flex:none}
  .fb{width:40px; border-radius:13px}

  /* every flex row in the panels was nowrap — fine at 700px of panel,
     not at 280px. Let them wrap and let their text shrink. */
  .v3-hd,.v4-foot,.v2-dots,.v1-chips,.v3-bar{flex-wrap:wrap; row-gap:7px}
  /* .v4-saved is deliberately NOT in that list — its only flex children are a
     13px tick and the text, so wrapping just pushed the tick onto a line of
     its own above the copy. Top-align instead, so the tick sits on the first
     line rather than centred against a three-line paragraph. */
  .v4-saved{align-items:flex-start}
  .v4-saved svg{margin-top:3px}
  /* the 2.4/1 crop above is tuned for the height-capped sticky panel on
     short laptops; mobile has no cap, so the frame goes back to 16/9 */
  .v4-img{aspect-ratio:16/9}
  .v3-hd .st{margin-left:0}
  .v2-pill{width:auto}
  .v2-pill span,.v3-hd b,.v4-row span,.v4-saved span,.v4-sel{min-width:0}
  .v1-prompt,.v3-prompt,.v2-pill span{overflow-wrap:anywhere}
  .v4-row b,.v4-row span span{overflow-wrap:anywhere}
}
/* the window + result image sit side by side until roughly 700px, below
   which the window drops under ~280px and the prompt text starts to
   wrap every second word */
@media (max-width:700px){
  .v1{flex-direction:column}
  .v1-out{flex:0 0 auto; width:64%; margin:0 0 0 auto; aspect-ratio:4/3}
}
@media (max-width:640px){
  /* decorative only, and at this width they crowd the mock UI rather
     than framing it — the badge at left:-2% was also half-clipped */
  .fs-arrow,.fb{display:none}
  /* the carousel clips to the rail, so cards keep a fixed width here and
     the row simply shows fewer of them */
  .v2{--v2-w:clamp(64px,19vw,92px); --v2-gap:7px}
  .v2-card.on{transform:scale(1.1)}
  /* a 9.5px label cannot fit a ~54px card; only the active one is labelled */
  .v2-card b{display:none}
  .v2-card.on b{display:block}
  .v4-tools{gap:0}
  .v4-tool{padding:7px 9px; font-size:11.4px}
  .v4-fmt{grid-template-columns:repeat(2,minmax(0,1fr))}
  .v4-actions{flex-wrap:wrap}
  .v4-cp{flex:1 1 auto}
  /* reclaim 10px a side for content */
  .fs-panel{padding:15px; border-radius:18px}
  .v3-card,.v4-side{padding:13px}
  .v1-out{width:74%}
}
@media (prefers-reduced-motion:reduce){
  .fb,.fs-arrow path,.v1-prompt .cur{animation:none}
  .v3-item.now .dot{animation:none; border-color:var(--saf)}
  .fs-viz{transition:none}
}
