/* ==========================================================================
   Block: scroll-stack — "Numbered scroll stack" (src/blocks/scroll-stack.html, js/blocks/scroll-stack.js)
   Figma "Social Media Advertising" 4506:165 at 1920 (page y; rule y = top edge of the 2px line):
     eyebrow  x105 y2243 (dot) · title x99 y2289, 80px, 2 lines (152) · intro x974 y2294, 849 wide
     rules    y2505 (list top) / 2799 / 2993 / 3190 — open row 294, peek rows 194 / 197 (built 195 + 195)
     open row numeral 250px, box +23 (ink +58) · label +48 · ± icon +44 (33px, right edge 1820) ·
              title 48px +88 · body +162, 849 wide, 57px above the next rule; content column x680
     peek row label + icon +125 (Figma: 125 on row 02, 137 on row 03 — built as row 02), numeral cut by
              the next row's rule (Figma draws bg-coloured rectangles over it; here the next row / the end
              mask covers it)
   Gaps to the neighbours are split half each side: work-showcase phones end 2103 → eyebrow 2243 (70 + 70);
   last rule 3191 → device-mockup image 3459 (134 + 134).
   Units: --u is one Figma px at 1920, scaling with the viewport below that (calc(N * var(--u))).
   Type sizes that the site keeps fixed (20px body/labels, the section title's --fs-h1 scale) stay fixed.

   Three renderings (the class is set by js/blocks/scroll-stack.js):
     (none)        static — reduced motion / no JS: every row open, a plain list with a rule under it
     .is-live      rows absolutely positioned by the script (GSAP y), .is-open / .is-active per row, one
                   .block-scroll-stack__end mask per column (rule + page-coloured block) under the last row
       .is-stack      pinned, wheel/trackpad screens > 640px
       .is-accordion  touch or ≤640px: tap a row to open it
     .is-cols-2    5+ rows on screens > 1024px: two half-width columns (Figma SEO 4641:2 / Media Buying)
   Variants (data fields, see the partial):
     --no-intro    intro[] empty (Paid Search / Photography / Videography): the title runs in a 1217px box
     --split       item_layout "split" (Paid Search 4665:482): label | heading, body, media side by side
   ========================================================================== */

.block-scroll-stack {
  --u: min(1px, 0.0520833vw);              /* 1 Figma px at 1920 */
  --rule: 2px;
  --open: calc(294 * var(--u));            /* open row: rule top → next rule top */
  --peek: calc(195 * var(--u));            /* peek row (the script may shrink it to fit a short viewport) */
  --num-size: calc(250 * var(--u));
  --num-col: calc(580 * var(--u));         /* numeral column: labels start at x680 = 100 + 580 */
  --row-top: calc(44 * var(--u));          /* open row: ± icon top under the rule top */
  --pad-bottom: calc(57 * var(--u));       /* body bottom → next rule */
  --icon: 33px;
  padding: calc(70 * var(--u)) 0 calc(134 * var(--u));
}

.block-scroll-stack__pin { position: relative; }   /* the script reads the list's offsetTop against it */

/* ---- Header: eyebrow, then heading | intro (.grid-2, x100 | x971) ----------------------------- */
.block-scroll-stack__eyebrow { margin-left: calc(5 * var(--u)); }            /* dot at x105 */
.block-scroll-stack__top { margin-top: calc(21 * var(--u)); }                /* eyebrow bottom 2268 → title 2289 */
.block-scroll-stack__title { margin: 0; font-size: var(--fs-h1); }
.block-scroll-stack__intro {
  max-width: 849px;
  margin: calc(5 * var(--u)) 0 0 calc(3 * var(--u));                        /* x974 y2294 */
}
.block-scroll-stack__intro p { font-size: var(--fs-body); line-height: var(--lh-body); }
.block-scroll-stack__intro p + p { margin-top: 1em; }

/* No intro (Figma Paid Search 4665:482 y3753, Photography 5041:2 y5145, Videography 5050:499 y4686): the title
   is set in a 1217px box at x100 instead of the left half — 15.21em of the 80px title, so it wraps the same at
   every type step. The header → first rule gap stays the block's 64 (the three frames drift: 43 / 47 / 77). */
.block-scroll-stack--no-intro .block-scroll-stack__top { display: block; }
.block-scroll-stack--no-intro .block-scroll-stack__title { max-width: 15.2125em; }

/* ---- The list ------------------------------------------------------------------------------- */
.block-scroll-stack__stack { position: relative; margin-top: calc(64 * var(--u)); }   /* title bottom 2441 → rule 2505 */
.block-scroll-stack__list { border-bottom: var(--rule) solid var(--fg); }

.block-scroll-stack__item {
  /* derived here, not on the block, so a --peek set on the list by the script flows through */
  --head-shift: calc(var(--peek) - 114 * var(--u));   /* peek row: label + icon 81px lower (at 195) */
  --num-shift: 0px;
  position: relative;
  display: grid;
  grid-template-columns: var(--num-col) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas: "num row" "num panel";
  min-height: var(--open);
  padding-bottom: var(--pad-bottom);
  border-top: var(--rule) solid var(--fg);
  background: var(--bg);
}

/* Blauer Nue: ascent .94 / descent .26 / cap .70 em → at line-height 1 the digits' top sits .14em under
   the box top, so a 23px box offset puts the ink 58px under the rule (Figma "01" ink y2563). Light (300)
   has not been supplied: the browser uses Regular until a 300 face is added to css/base.css.
   The negative bottom margin ends the box at the digits' baseline (+233), so the row height comes from
   the text column (294 at 1920), as in the Figma, not from the numeral's line box (+273). */
.block-scroll-stack__num {
  grid-area: num;
  align-self: start;
  margin: calc(23 * var(--u) - var(--rule)) 0 calc(-40 * var(--u)) calc(2 * var(--u));
  font-family: var(--font-display);
  font-weight: 300;
  font-size: var(--num-size);
  line-height: 1;
  letter-spacing: 0;
  color: var(--fg);
  user-select: none;
  transition: color .45s ease, translate .5s cubic-bezier(.22, 1, .36, 1);
}

.block-scroll-stack__row {
  grid-area: row;
  align-self: start;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  min-height: var(--icon);
  margin-top: calc(var(--row-top) - var(--rule));
  transition: translate .5s cubic-bezier(.22, 1, .36, 1);
}
.block-scroll-stack__label {
  display: flex;
  align-items: center;
  gap: 15px;
  margin: 0;
  color: var(--accent);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.24;
}
.block-scroll-stack__label::before {
  content: "";
  flex: 0 0 6px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* ± icon: 33px green ring, 15px strokes; the upright stroke folds away when the row is open (−).
   Static rows are all open and not interactive, so the icon only shows in the live renderings. */
.block-scroll-stack__icon {
  position: relative;
  display: none;
  flex: 0 0 var(--icon);
  width: var(--icon);
  height: var(--icon);
  margin-left: auto;
  border: 1px solid var(--accent);
  border-radius: 50%;
}
.block-scroll-stack__icon::before,
.block-scroll-stack__icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 1px;
  margin: -0.5px 0 0 -7.5px;
  background: var(--accent);
  transition: transform .4s cubic-bezier(.22, 1, .36, 1), background-color .3s ease;
}
.block-scroll-stack__icon::after { transform: rotate(90deg); }

.block-scroll-stack__panel {
  grid-area: panel;
  align-self: end;                         /* body sits a fixed distance above the next rule, title or not */
  transition: opacity .45s ease .12s, translate .6s cubic-bezier(.22, 1, .36, 1) .08s;
}
.block-scroll-stack__item-title {
  margin: 0 0 calc(15 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: max(28px, calc(48 * var(--u)));
  line-height: 1.229;                      /* Figma box 59 at 48px */
}
.block-scroll-stack__text {
  max-width: 849px;
  margin: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  white-space: pre-line;                   /* a blank line in the textarea = a new paragraph (Figma Graphic 01) */
}

/* Stacked rows without a heading: keep the body clear of the label line when the row outgrows its design
   height (tablet / narrow desktop). At 1920 the body sits well below the label (aligned to the row bottom),
   so this never moves it there; rows with a heading (SMA) are untouched. */
@media (min-width: 641px) {
  .block-scroll-stack__panel > .block-scroll-stack__text:first-child { margin-top: max(12px, calc(20 * var(--u))); }
}

/* Optional per-row media (Figma Paid Search "Screenshot 2026-08-06 …" 710×130, 22 under the body) */
.block-scroll-stack__media {
  width: 100%;
  max-width: 710px;
  margin: max(14px, calc(22 * var(--u))) 0 0;
}
.block-scroll-stack__media img,
.block-scroll-stack__media video { display: block; width: 100%; height: auto; }
.block-scroll-stack__media video { aspect-ratio: var(--ar, 16 / 9); object-fit: cover; }   /* the box never changes when the clip loads */
@media (min-width: 1025px) {
  .block-scroll-stack__media { width: calc(710 * var(--u)); max-width: 100%; }
}

/* Full-width hit area over the row's top band (the part a peek row shows). Hidden in the markup; the
   script shows it: stack → scrolls to that row, accordion → opens it, or — on the open row — closes it. */
.block-scroll-stack__hit {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--peek);
  cursor: pointer;
}
.block-scroll-stack__hit[hidden] { display: none; }
.block-scroll-stack__hit:focus-visible { outline-offset: -3px; }
/* Open row (client #29): the hit shrinks to the label + − icon band, so pressing the minus (or the label) closes
   the row, while the heading, text and media below stay selectable. The open panel sits above the band, so a
   split row's body (it starts level with the label) is never a close target. */
.block-scroll-stack__item.is-open > .block-scroll-stack__hit { height: calc(var(--row-top) + var(--icon) + 12px); }
.block-scroll-stack__item.is-open > .block-scroll-stack__panel { position: relative; z-index: 3; }

/* ---- Live renderings (script-driven) -------------------------------------------------------- */
.block-scroll-stack.is-live .block-scroll-stack__stack {
  clip-path: inset(-200px -40px 0 -40px);  /* cut the end masks at the list bottom, let a bounce overshoot the top */
}
.block-scroll-stack.is-live .block-scroll-stack__list { position: relative; height: 100%; border-bottom: 0; }
.block-scroll-stack.is-live .block-scroll-stack__item {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}
.block-scroll-stack.is-live .block-scroll-stack__icon { display: block; }
.block-scroll-stack.is-live .block-scroll-stack__item:not(.is-open) .block-scroll-stack__row { translate: 0 var(--head-shift); }
.block-scroll-stack.is-live .block-scroll-stack__item:not(.is-open) .block-scroll-stack__num { translate: 0 var(--num-shift); }
/* Hover a closed row (fine pointers): the numeral lifts a touch — a subtle hint that more is there — and the
   ± toggle reverses to a filled green disc with a black plus (like the site's filled buttons). The rows do
   not move and the panel stays shut; only a click opens the row. */
.block-scroll-stack.is-live .block-scroll-stack__item.is-peek:not(.is-open) .block-scroll-stack__num {
  translate: 0 calc(var(--num-shift) - 16 * var(--u));
}
.block-scroll-stack__icon { transition: background-color .3s ease, border-color .3s ease; }
.block-scroll-stack.is-live .block-scroll-stack__item.is-peek:not(.is-open) .block-scroll-stack__icon {
  background: var(--accent);
}
.block-scroll-stack.is-live .block-scroll-stack__item.is-peek:not(.is-open) .block-scroll-stack__icon::before,
.block-scroll-stack.is-live .block-scroll-stack__item.is-peek:not(.is-open) .block-scroll-stack__icon::after {
  background: var(--black);
}
.block-scroll-stack.is-live .block-scroll-stack__item:not(.is-open) .block-scroll-stack__panel {
  opacity: 0;
  translate: 0 16px;
  transition: opacity .2s ease, translate .3s ease;
}
.block-scroll-stack.is-live .block-scroll-stack__item.is-open .block-scroll-stack__icon::after { transform: rotate(90deg) scaleX(0); }
/* Hovering the open row's band (it closes the row) fills the − the same way a closed row's + fills. */
@media (hover: hover) {
  .block-scroll-stack.is-live .block-scroll-stack__item.is-open > .block-scroll-stack__hit:hover ~ .block-scroll-stack__row .block-scroll-stack__icon { background: var(--accent); }
  .block-scroll-stack.is-live .block-scroll-stack__item.is-open > .block-scroll-stack__hit:hover ~ .block-scroll-stack__row .block-scroll-stack__icon::before { background: var(--black); }
}
.block-scroll-stack.is-live .block-scroll-stack__item.is-active .block-scroll-stack__num { color: var(--accent); }

/* End mask: the closing rule plus a page-coloured block that hides whatever of the last row lies below
   its peek band (the Figma's Rectangle 201/202 do the same). One per column, above every row. */
.block-scroll-stack__end {
  position: absolute;
  z-index: 20;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-top: var(--rule) solid var(--fg);
  background: var(--bg);
  pointer-events: none;
}

/* Script helper: reads var(--peek) in px */
.block-scroll-stack__probe { position: absolute; top: 0; left: 0; width: 0; height: var(--peek); visibility: hidden; pointer-events: none; }

/* Paging stops added by the script (js/main.js treats any .section[data-scroll-stop] as one) */
.block-scroll-stack .block-scroll-stack__stop {
  position: absolute;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  visibility: hidden;
}

/* ---- Two columns: 5+ rows on screens > 1024px (Figma SEO 4641:2) -----------------------------
   Columns 850 wide, rows as above; inside a column the label sits 433px in, the icon 13px short of the
   column edge and the body 415 wide, its bottom 43 above the next rule (Content Writing 5160:659 / Web
   4816:2: 43 · Organic 39 · Media Buying 48 · SEO 53 — the frames drift, 43 is their median). */
.block-scroll-stack.is-cols-2 .block-scroll-stack__item,
.block-scroll-stack.is-cols-2 .block-scroll-stack__end { width: calc(50% - 10 * var(--u)); }
.block-scroll-stack.is-cols-2 .is-col-2 { left: calc(50% + 10 * var(--u)); }
.block-scroll-stack.is-cols-2 .block-scroll-stack__item { --num-col: calc(433 * var(--u)); --pad-bottom: calc(43 * var(--u)); }
.block-scroll-stack.is-cols-2 .block-scroll-stack__row { padding-right: calc(13 * var(--u)); }
.block-scroll-stack.is-cols-2 .block-scroll-stack__text { max-width: 415px; }
.block-scroll-stack.is-cols-2 .block-scroll-stack__item-title { font-size: max(24px, calc(36 * var(--u))); }

/* Static rendering with 5+ rows on wide screens: the same two columns, as a grid (rows all open) */
@media (min-width: 1025px) {
  .block-scroll-stack:not(.is-live) .block-scroll-stack__list:has(> li:nth-child(5)) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(3, auto);
    grid-auto-flow: column;
    column-gap: calc(20 * var(--u));
    border-bottom: 0;
  }
  .block-scroll-stack:not(.is-live) .block-scroll-stack__list:has(> li:nth-child(5)) > li {
    --num-col: calc(433 * var(--u));
    --pad-bottom: calc(43 * var(--u));
    border-bottom: var(--rule) solid var(--fg);
    margin-bottom: calc(var(--rule) * -1);
  }
  .block-scroll-stack:not(.is-live) .block-scroll-stack__list:has(> li:nth-child(5)) .block-scroll-stack__item-title {
    font-size: max(24px, calc(36 * var(--u)));
  }
  .block-scroll-stack:not(.is-live) .block-scroll-stack__list:has(> li:nth-child(5)) .block-scroll-stack__text { max-width: 415px; }
}

/* ---- Split rows: item_layout "split", 2–4 rows on screens ≥ 1280px (Figma Paid Search 4665:482) --
   rules y3873 / 4167 (open 294) · label x700 (dot x679 → built x680) +48 · body x970 (705 wide) top-aligned
   with the label · media 710×130 x970, 22 under the body, 44 above the next rule. The panel shares the
   label's grid row: it starts 290px into the content column (680 + 290 = 970) and stops short of the ± icon.
   The label column stays 290px below 1920 (the 20px labels don't shrink — "YouTube & video campaigns" needs
   266), so split starts at 1280 (body ≥ 417 wide); 5+ rows (two columns) and < 1280px keep the stacked layout. */
@media (min-width: 1280px) {
  .block-scroll-stack--split .block-scroll-stack__list:not(:has(> li:nth-child(5))) > li {
    --split-col: 290px;
    --pad-bottom: calc(44 * var(--u));
  }
  .block-scroll-stack--split .block-scroll-stack__list:not(:has(> li:nth-child(5))) .block-scroll-stack__label {
    max-width: calc(var(--split-col) - 20px);
  }
  .block-scroll-stack--split .block-scroll-stack__list:not(:has(> li:nth-child(5))) .block-scroll-stack__panel {
    grid-row: 1 / -1;
    align-self: start;
    min-width: 0;
    /* the row's top margin + the label's centring in the 33px icon line → the body's first line sits on the label's */
    margin: calc(var(--row-top) - var(--rule) + (var(--icon) - var(--fs-body) * 1.24) / 2) calc(var(--icon) + 20px) 0 var(--split-col);
  }
  .block-scroll-stack--split .block-scroll-stack__list:not(:has(> li:nth-child(5))) .block-scroll-stack__panel > .block-scroll-stack__text {
    max-width: 705px;
    margin-top: 0;
  }
}

/* ---- Tablet ---------------------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .block-scroll-stack__top { row-gap: 24px; }
  .block-scroll-stack__intro { margin: 0; }
}

/* ---- Mobile (Figma "Mobile Category" 4148:2776, 402 wide; rule y = top edge) -----------------
   eyebrow y1792 · title 48px y1827 (3 lines) · intro y1987 · rules 2204 / 2567 / 2645 / 2723
   open row 363: numeral 96px Medium box +26 · label +34 / icon +33 (label x159, icon right x382) ·
     title 28px +135 and body +184 full width under the numeral · body bottom → next rule 29
   peek row 78 (Figma 77 / 79): numeral +16, label + icon +22 */
@media (max-width: 640px) {
  .block-scroll-stack {
    --open: 0px;
    --peek: 78px;
    --num-size: 96px;
    --num-col: 139px;                      /* label dot at x159 = 20 + 139 */
    --row-top: 33px;
    --pad-bottom: 29px;
    padding: 36px 0 46px;                  /* (1792 − 1720) / 2 above · (2816 − 2724) / 2 below */
  }
  .block-scroll-stack__item {
    --head-shift: -11px;
    --num-shift: -10px;
    grid-template-rows: auto auto;
    grid-template-areas: "num row" "panel panel";
  }
  .block-scroll-stack__eyebrow { gap: 12px; margin-left: 2px; }             /* dot x22, text x40 */
  .block-scroll-stack__top { margin-top: 15px; row-gap: 22px; }             /* eyebrow → title 15 · title → intro 22 */
  .block-scroll-stack__stack { margin-top: 42px; }                          /* intro bottom 2162 → rule 2204 */
  .block-scroll-stack__num {
    margin: calc(26px - var(--rule)) 0 0;   /* box 26 → 117: sets the first grid row (the text starts under it) */
    font-weight: 500;                      /* Figma mobile: Blauer Nue Medium */
    line-height: .95;                      /* box 91 */
  }
  .block-scroll-stack__panel { align-self: start; margin-top: 18px; }       /* numeral box bottom 117 → title 135 */
  .block-scroll-stack__item-title { margin-bottom: 15px; font-size: 28px; line-height: 1.214; }
  .block-scroll-stack__media { max-width: none; margin-top: 20px; }         /* split or not: label → body → media, full width */
}

/* Small phones: the label, its ± icon and the 139px numeral column share a row, and a one-word label is up to
   140px ("Programmatic" Media Buying, "Measurement" Organic, "Development" Web) — the icon ran past the content
   edge: 12px into the gutter at 360, off the page at 320 (332–352px wide). ≤374 the label → icon gap drops to
   8px (the row fits at 360); ≤359 the numeral steps down to 80px in a 110px column and the label to 18px (the
   ≤359 pill scale, css/base.css), leaving 170px at 320 for the widest label + icon (≈123 + 8 + 33). */
@media (max-width: 374px) {
  .block-scroll-stack__row { gap: 8px; }
}
@media (max-width: 359px) {
  .block-scroll-stack { --num-size: 80px; --num-col: 110px; }    /* "04" is 104px wide at 80px */
  .block-scroll-stack__label { gap: 10px; font-size: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  .block-scroll-stack__num,
  .block-scroll-stack__row,
  .block-scroll-stack__panel { transition: none; }
}
