/* ---------------------------------------------------------------
   The Loop: the decode box (lo-ix, below), then one heading, then a
   deck of four sticky module cards: Actions, Script, Ad Generation,
   Ask Galvor. Namespace: every selector is .lo / .lo-*.

   A card is one screen. Left: kicker, title, one line, checks, a link.
   Right: one panel in window chrome. Inside the panel the small
   visuals and their data sit left, a real screen of the product sits
   right. The sticky-stack mechanic is unchanged: all cards are sticky
   inside one .lo-track, each pinned while the next climbs over it;
   --d is the stack depth written by loop.js.
   --------------------------------------------------------------- */

.loop.lo{
  position:relative;z-index:2;isolation:isolate;
  background:transparent;  /* the site ground is the fixed .gv-aurora field */
  /* the dot grid moved to ::before so it can be MASKED at the edges rather
     than veiled — see the note there */
  padding-block:clamp(72px,9vh,120px) clamp(32px,5vh,56px);
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Helvetica Neue",Inter,system-ui,Arial,sans-serif;
  color:#24202d;
  --lo-nav:96px;
  --lo-step:14px;
  --lo-pin:calc(var(--lo-nav) + 3 * var(--lo-step));
  /* image3: a card is about 1240 x 510. Height is fixed so the deck math
     in loop.js (one height for every card) holds; the panel fills it.

     The binding card is 02, the two scripts: at 500px its green "why" pill was
     cut by the card's bottom edge three reviews running, so the card went to
     540. RD now wants the stack shorter, and 04 in particular is mostly air.
     Rather than take it out of the card alone — which would put 02 back over
     the edge — the 30px comes out of three places at once: the card is 510, the
     panel starts 40px below the card top instead of 52 (it only has to clear
     the numeral), and the card's own vertical padding is 32 rather than 36.

     The arithmetic for 02, the tightest: 510 - 64 (card padding) - 40 (panel
     offset) - 34 (title bar) - 36 (body padding) = 336px of room for content
     that measures about 306. Roughly 30px of headroom, where the 540px card
     had 40. Nothing is cut; the card is just carrying less air. */
  --lo-card-h:min(510px,calc(100vh - var(--lo-pin) - 28px));
  --lo-ease:cubic-bezier(.16,1,.3,1);
  --lo-green:#1e9678;--lo-green-bg:#e7f6f1;
  --lo-red:#d9435e;--lo-red-bg:#fdeaee;
}
/* RD round 7: there was a visible seam where this section met the one above
   it. It was not a gap — it was this layer. To fade its own dot grid at the
   top and bottom, the section used to lay an 80%-opaque #f7f6fa wash over its
   first and last fifth, and an opaque wash starts at the section's edge, so it
   covered the fixed aurora field with a flat pale panel and drew a hard line
   across the page exactly at the boundary.

   The dots are now painted here and MASKED instead: the mask fades the grid
   itself to nothing at both ends and paints no colour at all, so the aurora
   runs through the section unbroken and there is no edge to see. */
.loop.lo::before{content:"";position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(#17121f14 1px,transparent 1.2px);
  background-size:28px 28px;
  -webkit-mask-image:linear-gradient(180deg,#0000 0,#000 11%,#000 89%,#0000 100%);
  mask-image:linear-gradient(180deg,#0000 0,#000 11%,#000 89%,#0000 100%)}
/* no mask support: keep the dots, skip the fade — a hard-edged grid is a far
   smaller problem than the wash was */
@supports not ((mask-image:linear-gradient(#000,#0000)) or (-webkit-mask-image:linear-gradient(#000,#0000))){
  .loop.lo::before{-webkit-mask-image:none;mask-image:none}
}

.lo-inner{position:relative;z-index:1;width:min(1560px,calc(100% - 2*clamp(20px,4vw,72px)));margin-inline:auto}

/* --- the one heading, between the box and the deck --- */
.lo-head{max-width:880px;margin:0 auto clamp(36px,5vh,60px);text-align:center}
.lo-h2{margin:0 0 12px;font-size:var(--gv-h2);font-weight:700;letter-spacing:-.04em;
  line-height:1.05;color:#17121f;text-wrap:balance}

/* --- the deck --- */
.lo-track{position:relative;padding-bottom:16vh}
/* .lo-slot adds no box; .lo-sent is a zero-width marker that reports the
   card's position in flow. Spacing lives in the marker, never in a card
   margin: a sticky element releases when its MARGIN box hits the edge. */
.lo-slot{display:contents}
.lo-sent{display:block;height:36vh}
.lo-slot:first-child .lo-sent{height:0}

.lo-card{position:sticky;top:var(--lo-pin);--d:0;
  display:grid;grid-template-columns:minmax(280px,.62fr) minmax(0,1.38fr);
  gap:clamp(24px,3vw,44px);align-items:stretch;
  width:min(1240px,100%);margin-inline:auto;
  height:var(--lo-card-h);
  padding:clamp(20px,2.4vw,32px) clamp(24px,3.2vw,44px);
  border-radius:26px;background:#fff;overflow:hidden;
  box-shadow:inset 0 0 0 1px #fff,0 0 0 1px #17121f0d,0 -18px 44px -26px #17121f4d,0 30px 70px -40px #2a1a5a33;
  /* each level behind steps up and shrinks, so older cards fan out above */
  transform-origin:50% 0;
  transform:translateY(calc(var(--d) * -1 * var(--lo-step))) scale(calc(1 - var(--d) * .04));
  will-change:transform}
.lo-card::after{content:"";position:absolute;inset:0;border-radius:26px;background:#f3f1f7;
  opacity:calc(var(--d) * .3);pointer-events:none;transition:opacity .15s linear}

/* the big numeral, top right, behind the panel. RD round-3 note: it read as
   ~50% visible because top:-.1em pushed most of a 140-190px glyph above the
   card's own clipped edge; smaller + nudged down shows ~80% of it. */
.lo-num{position:absolute;top:6px;right:clamp(18px,2.6vw,40px);z-index:0;
  font-size:clamp(72px,7.4vw,104px);font-weight:700;letter-spacing:-.05em;line-height:1;
  color:#17121f;opacity:.09;pointer-events:none;user-select:none}

/* --- copy column --- */
.lo-copy{position:relative;z-index:1;align-self:center;max-width:420px}
.lo-kicker{margin:0 0 10px;font-family:ui-monospace,Menlo,monospace;font-size:var(--gv-eyebrow);font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:#7c3aed}
.lo-h3{margin:0 0 8px;font-size:clamp(36px,3.4vw,46px);font-weight:700;letter-spacing:-.045em;
  line-height:1.02;color:#17121f}
.lo-sub{margin:0 0 18px;font-size:clamp(15px,1.15vw,17px);font-weight:500;line-height:1.4;color:#2a2235}

/* --- tags: a compact grid of small pills, replacing the checkmark list --- */
.lo-tags{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.lo-tags li{padding:6px 12px;border-radius:999px;background:#f2eaff;color:#5b2fa8;
  font-size:12.5px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;
  box-shadow:inset 0 0 0 1px #7c3aed22}

/* --- panel: a window --- */
/* the panel starts a little below the card top, so the numeral shows above
   it and runs behind its top edge (image3) */
.lo-panel{position:relative;z-index:1;min-width:0;min-height:0;margin-top:clamp(24px,3.4vw,40px);
  display:flex;flex-direction:column;border-radius:16px;background:#fff;
  box-shadow:inset 0 0 0 1px #17121f0f,0 24px 60px -30px #2a1a5a4d}
.lo-bar{flex:none;display:flex;align-items:center;gap:12px;height:34px;padding:0 14px;
  border-bottom:1px solid #17121f0a;border-radius:16px 16px 0 0;background:#faf8fe}
.lo-dots{flex:none;width:8px;height:8px;margin-right:26px;border-radius:50%;background:#e3dfea;
  box-shadow:13px 0 0 #e3dfea,26px 0 0 #e3dfea}
.lo-bar-t{font-family:ui-monospace,Menlo,monospace;font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:#8d84a0}
.lo-live{margin-left:auto;display:inline-flex;align-items:center;gap:6px;padding:3px 9px;
  border-radius:999px;background:var(--lo-green-bg);color:var(--lo-green);
  font-family:ui-monospace,Menlo,monospace;font-size:9.5px;letter-spacing:.1em;text-transform:uppercase}
.lo-live i{width:6px;height:6px;border-radius:50%;background:currentColor}

/* the right-hand screenshot mockup is gone (RD round 3: "why two mockups?"
   — removed the smaller one); .lo-viz now owns the full panel width. */
.lo-body{flex:1;min-height:0;display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(14px,1.6vw,22px);padding:clamp(12px,1.4vw,18px)}
/* `safe` matters here: with the right-hand mockup removed the scripts grew,
   and a plain `center` overflows in BOTH directions — the first child was
   pushed up over the window's title bar. `safe center` centres only while
   the content fits, then falls back to start alignment. */
.lo-viz{min-width:0;min-height:0;display:flex;flex-direction:column;justify-content:safe center}
.lo-viz-t{margin:0 0 8px;font-family:ui-monospace,Menlo,monospace;font-size:9.5px;
  letter-spacing:.14em;text-transform:uppercase;color:#8d84a0}
.lo-foot{margin:8px 0 0;font-size:11px;line-height:1.4;color:#8d84a0}

/* image boxes: fixed ratio + a fill colour, so a missing file never collapses */
.lo-shot{position:relative;margin:0;overflow:hidden;border-radius:8px;background:#efeaf7;
  box-shadow:inset 0 0 0 1px #17121f0f;aspect-ratio:4/5}
.lo-shot img{display:block;width:100%;height:100%;object-fit:cover;background:#efeaf7;color:transparent;font-size:0}
/* one grade on every creator/creative frame, so different generations read
   as one shoot. The generated ads are the product's own output: no tint. */
.lo-shot:not(.lo-ad)::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  mix-blend-mode:multiply;opacity:.14;
  background:linear-gradient(155deg,#8b52e7,#ca7dab 52%,#89a6e6)}

/* status colours: green = worked, red = did not. Nothing else uses them. */
.lo-g{font-style:normal;color:var(--lo-green);font-weight:600}
.lo-r{font-style:normal;color:var(--lo-red);font-weight:600}

/* ---- 01 Actions: three moves, each with the creatives it is about ---- */
.lo-moves{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.lo-move{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:center;
  padding:12px 14px;border-radius:12px;background:#faf8fe;box-shadow:inset 0 0 0 1px #17121f08}
.lo-thumbs{display:flex;gap:4px}
.lo-thumbs .lo-shot{width:44px;border-radius:6px}
.lo-move-h{display:flex;align-items:center;gap:9px;margin:0 0 4px;font-size:12.5px;
  letter-spacing:.03em;text-transform:uppercase;color:#8d84a0;white-space:nowrap;overflow:hidden}
.lo-move-h span{overflow:hidden;text-overflow:ellipsis}
.lo-badge{display:inline-block;padding:3px 8px;border-radius:6px;font-size:11px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase}
.lo-badge.lo-scale{color:var(--lo-green);background:var(--lo-green-bg)}
.lo-badge.lo-cut{color:var(--lo-red);background:var(--lo-red-bg)}
.lo-badge.lo-shift{color:#7c3aed;background:#f2eaff}
.lo-move-s{margin:0;font-size:14.5px;line-height:1.4;color:#2a2235}
.lo-stake{margin:0;text-align:right;white-space:nowrap}
.lo-stake b{display:block;font-size:20px;font-weight:700;letter-spacing:-.03em;line-height:1;color:#17121f}
.lo-stake span{display:block;margin-top:3px;font-size:11px;color:#8d84a0}

/* ---- 02 Script: two scripts, laid out wide and horizontal (RD round 3:
   "less width, longer" — the freed right-hand column goes to the scripts,
   not to a taller card) ---- */
/* The two script blocks are 6px taller than the card can hold at a 950px-tall
   window, and the card clips: the second one's green "why" pill was being cut
   in half by the bottom edge. The 8px this takes back off the gap and the
   blocks' own padding is the whole of it — same class of bug as the winning
   formula below, and it wants the same fix, not a taller card. */
/* RD round 7: it was still being cut at the bottom. The previous pass took
   8px off a budget that needed 30, so this one is not a trim — the block gives
   up a thumbnail size, two type steps and its padding, which leaves the pair
   about 30px inside the card instead of 6. min-height:0 on the rows is the
   belt: if a quote ever wraps to a third line the block clips inside its own
   rounded corner, not across the card's bottom edge. */
.lo-scripts{display:grid;gap:7px;min-height:0}
.lo-script{display:grid;grid-template-columns:auto minmax(0,1fr);gap:16px;align-items:start;
  min-height:0;overflow:hidden;
  padding:10px 14px;border-radius:12px;background:#faf8fe;box-shadow:inset 0 0 0 1px #17121f08}
.lo-script-thumb{width:60px;border-radius:8px}
.lo-script-body{min-width:0}
.lo-script-h{margin:0 0 5px;font-size:15.5px;font-weight:700;letter-spacing:-.02em;color:#17121f}
.lo-beats{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}
.lo-beats li{display:flex;flex-direction:column;gap:2px;font-size:12.5px;line-height:1.3;color:#4d4560}
.lo-beats span{font-family:ui-monospace,Menlo,monospace;font-size:10px;color:#a79ec0}
.lo-beats b{font-weight:700;color:#17121f;font-size:11.5px;letter-spacing:.02em}
.lo-beats i{font-style:normal}
.lo-why{display:flex;align-items:center;gap:6px;margin:7px 0 0;width:max-content;max-width:100%;
  padding:4px 10px 4px 8px;border-radius:999px;background:var(--lo-green-bg);color:var(--lo-green);
  font-size:11px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lo-why i{flex:none;width:6px;height:6px;border-radius:50%;background:currentColor}

/* ---- 03 Generate: the three ads, then the formula they came from ---- */
.lo-ads{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0}

/* The formula is a strip at the foot of the app window, captioned, so it reads
   as the recipe the three ads above it were built from rather than a caption
   floating under the card. flex:none is what keeps it whole: the ads give up
   the space, never this. */
.lo-formula-note{flex:none;margin-top:10px;padding:9px 12px 10px;border-radius:10px;
  background:#f1fbf7;box-shadow:inset 0 0 0 1px #1e967826}
.lo-formula-note .lo-viz-t{margin:0 0 4px}
.lo-formula{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0;
  font-size:clamp(14px,1.2vw,17px);font-weight:700;letter-spacing:-.02em;color:var(--lo-green)}
.lo-formula i{font-style:normal;color:#8d84a0;font-weight:600}

/* Above 1100 a card is a fixed --lo-card-h, and this panel is far wider than
   it is tall: three 4:5 ads sized from the panel's WIDTH came out about 45px
   taller than the body had room for, which is what pushed the formula past the
   card's clipped bottom edge. So here the ads are sized from the height left
   after the strip instead — same 4:5, just smaller, centred.

   max-height is the other half of it. Whichever of the two runs out first has
   to win, or the ads stop being 4:5: near 1100 the panel is narrow enough that
   three full-height ads would be wider than it. 100cqi is the width .lo-viz
   actually has, so that cap is exactly the height at which three 4:5 tiles and
   their two gaps fill the row, and the ratio holds either way.

   Below 1100, and under reduced motion, the card grows to fit its content, so
   there is no fixed height to divide up and the plain grid above is right. */
@media (min-width:1101px){
  .lo-body-ads .lo-viz{justify-content:flex-start;container-type:inline-size}
  .lo-body-ads .lo-ads{display:flex;justify-content:center;gap:10px;flex:1 1 auto;min-height:0;
    max-height:calc((100cqi - 20px)/3*1.25)}
  .lo-body-ads .lo-ad{flex:none;height:100%;width:auto;aspect-ratio:4/5}
}
/* no container units: fall back to the width-driven grid, which is always 4:5
   even though the strip then has less room above it */
@supports not (container-type:inline-size){
  .lo-body-ads .lo-ads{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
    flex:none;max-height:none}
  .lo-body-ads .lo-ad{height:auto;width:auto}
}

/* ---- 04 Ask Galvor: one turn, three legible strands of source ---- */
.lo-chat{gap:10px}
.lo-q{width:max-content;max-width:92%;margin:0 0 0 auto;padding:10px 14px;
  border-radius:14px 14px 3px 14px;background:#17121f;color:#fff;font-size:14.5px;line-height:1.4}
.lo-a{padding:14px 16px;border-radius:3px 14px 14px 14px;background:#f4f1fb;font-size:13.5px;line-height:1.5;color:#2a2235}
.lo-a p{margin:0 0 10px}
.lo-a p:last-of-type{margin-bottom:0}
.lo-a b{font-weight:600;color:#17121f}
/* one colour per strand, so Brand Memory / the question / industry data
   stay legible at a glance rather than blending into one paragraph */
.lo-src{display:inline-block;margin:0 7px 2px 0;padding:2px 8px;border-radius:999px;
  font-family:ui-monospace,Menlo,monospace;font-size:9.5px;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;vertical-align:middle}
.lo-src-mem{color:#7c3aed;background:#f2eaff}
.lo-src-q{color:#17121f;background:#e9e6f0}
.lo-src-ind{color:#5f9de0;background:#e9f1fc}
.lo-ev{display:flex;gap:5px;flex-wrap:wrap;margin-top:11px}
.lo-ev span{padding:2px 7px;border-radius:999px;background:#fff;color:#7c3aed;
  box-shadow:inset 0 0 0 1px #7c3aed22;font-family:ui-monospace,Menlo,monospace;font-size:9px}

/* --- narrow: the deck becomes a plain list --- */
/* below 1100 the card cannot hold the visuals and the real screen side by
   side inside a fixed 500px, so the deck becomes a plain list here, not at
   960: the list layout shows both. loop.js uses the same 1100. */
@media(max-width:1100px){
  /* the single-column card, at every width below 1100 */
  .lo-card{height:auto;grid-template-columns:1fr;gap:20px;padding:24px 18px 22px}
  .lo-num{font-size:88px;top:4px;right:14px}
  .lo-panel{margin-top:0}
  .lo-copy{max-width:none}
  .lo-body{grid-template-columns:minmax(0,1fr)}
}
/* tablet only: a plain list. A single-column card here is not trimmed, so it
   is taller than the viewport and cannot pin; loop.js skips the stack for the
   same band. */
@media(min-width:641px) and (max-width:1100px){
  .lo-track{padding-bottom:0}
  .lo-sent{height:0!important}
  .lo-card{position:relative;top:auto;margin-bottom:16px;transform:none!important}
  .lo-card::after{display:none}
}
/* phone: the deck stacks again (RD). Cards are content-height here, not the
   fixed --lo-card-h — the trimmed phone card is ~500px, which pins under a
   62px nav with room to spare on any portrait phone — and each one climbs
   over the last after a shorter run than on desktop. */
@media(max-width:640px){
  .loop.lo{--lo-nav:70px;--lo-step:10px}
  .lo-track{padding-bottom:10vh}
  .lo-sent{height:22vh}
  .lo-slot:first-child .lo-sent{height:0}
  .lo-card{position:sticky;top:var(--lo-pin);margin-bottom:0}
}
/* the phone count in a caption is hidden unless a phone is showing fewer */
.lo-n-m{display:none}

/* RD (phone): "these actions and other cards are too long — show less info
   on phone". Each window keeps its first item, not its whole list: two moves
   instead of three, one script instead of two, the thumbnails come off the
   moves (a 3-up strip was a third of every row's height), and the chat drops
   its tool-call chips. The captions switch to the phone count so "3 of 11"
   never sits over two rows. The card itself tightens: smaller numeral,
   smaller title, less padding. */
@media(max-width:640px){
  .lo-card{padding:20px 16px 18px;gap:14px}
  .lo-num{font-size:64px;top:6px;right:12px}
  .lo-h3{font-size:30px;margin-bottom:6px}
  .lo-sub{font-size:14.5px;margin-bottom:12px}
  .lo-tags li{padding:5px 10px;font-size:12px}
  .lo-body{padding:10px}
  .lo-n-d{display:none}.lo-n-m{display:inline}
  .lo-thumbs{display:none}
  .lo-move{grid-template-columns:minmax(0,1fr) auto;gap:10px;padding:10px 12px}
  .lo-move:nth-child(n+3){display:none}
  .lo-move-s{font-size:13.5px}
  .lo-stake b{font-size:17px}
  .lo-script:nth-child(n+2){display:none}
  .lo-script{gap:12px;padding:10px 12px}
  .lo-script-thumb{width:52px}
  .lo-beats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .lo-ev{display:none}
  .lo-q{font-size:13.5px}
  .lo-a{font-size:13px;padding:12px}
}

@media(prefers-reduced-motion:reduce){
  .lo-track{padding-bottom:0}
  .lo-sent{height:0!important}
  .lo-card{position:relative;top:auto;height:auto;transform:none!important;margin-bottom:16px}
  .lo-card::after{display:none}
  /* the card is a plain block here at any width, so the height-driven ad
     sizing has no fixed height to divide and would collapse the row */
  .lo-body-ads .lo-ads{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));flex:none}
  .lo-body-ads .lo-ad{height:auto;width:auto;max-width:none}
}

/* ===========================================================================
   lo-ix — the combined read that replaces the three pillar cards.

   Geometry and treatment are lifted from Brand Memory (section.memory /
   .bm-*) on purpose: it is the same operation, so it should look like the
   same component. The difference is that three corpora fall at once and the
   box resolves into three columns instead of one list.

   Nothing here reuses a .lo-card / .lo-sent / .lo-stage / .lo-chip name —
   loop.js queries those for the deck-stack below and would pick these up.
   =========================================================================== */

.loop .lo-ix{
  /* Box height, and the clear air above it. Cards fall from the top of the
     scene to the floor of the glass, so the only stretch where a fall is
     actually SEEN is scene-top to box-top — at 430px the box came up so far
     that a card was behind glass almost as soon as it appeared. Shorter box,
     and --ix-drop states the runway as its own number instead of leaving it as
     whatever happened to be left over. */
  --ix-boxh:348px;
  --ix-drop:104px;
  --ix-boxw:1320px;
  --ix-rowh:26px;
  --ix-cardw:88px;
  --ix-green:#1e9678;  --ix-green-bg:#e7f6f1;
  --ix-red:#d9435e;    --ix-red-bg:#fdeaee;
  /* one colour per corpus, used by the cards, the legend, the count split
     and the result columns, so a reader can follow one stream through */
  --ix-v:#8b52e7;      /* your creative */
  --ix-r:#e0899b;      /* your creators */
  --ix-c:#5f9de0;      /* competitor ads */
  position:relative;
  /* the scrub finishes at 62% of this (loop.js HOLD_AT); the rest holds the
     finished read on screen, so it is never mid-sentence when it unpins */
  height:320vh;
  margin-bottom:clamp(40px,6vw,88px);
}
/* pins BELOW the fixed nav, not under it — at top:0 the act's own heading
   scrolled behind the navbar */
.loop .lo-ix-sticky{
  position:sticky;top:var(--lo-nav);
  height:calc(100vh - var(--lo-nav));min-height:600px;overflow:hidden;
}
.loop .lo-ix-stage{
  height:100%;
  display:flex;flex-direction:column;
  gap:clamp(10px,1.6vh,20px);
  padding:clamp(40px,4.6vh,64px) 0 clamp(20px,2.8vh,32px);
}

/* RD round 7, notes 8 + 13 + 16: every section title on the page is centred
   and set at the shared --gv-h2, measured off the "One loop." line he signed
   off on. This one used to be left-aligned at its own smaller clamp, which is
   what made the eye re-anchor halfway down the page. */
.loop .lo-ix-head{flex:none;max-width:900px;margin-inline:auto;text-align:center}
.loop .lo-ix-eyebrow{
  font-family:ui-monospace,Menlo,monospace;
  font-size:var(--gv-eyebrow);letter-spacing:.14em;text-transform:uppercase;
  color:#7c3aed;margin:0 0 12px;font-weight:600;
}
.loop .lo-ix-h{
  font-size:var(--gv-h2);font-weight:700;
  letter-spacing:-.04em;line-height:1.05;margin:0;text-wrap:balance;
}
.loop .lo-ix-legend{flex:none;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:16px;font-size:11.5px;color:#91889d}
/* RD round 7: the read is not one channel. The three marks sit on the end of
   the legend, behind a divider, so the line says "these three corpora, across
   these three channels" in one pass. */
.loop .lo-ix-chan{display:inline-flex;align-items:center;gap:14px;padding-left:16px;
  border-left:1px solid #17121f1a}
.loop .lo-ix-ch{display:inline-flex;align-items:center;gap:6px;color:#6f6579}
.loop .lo-ix-ch svg{width:15px;height:15px;flex:none;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
.loop .lo-ix-ch b{font-weight:600;letter-spacing:-.01em;font-size:11.5px}
.loop .lo-ix-key{display:inline-flex;align-items:center;gap:7px}
.loop .lo-ix-key i{width:8px;height:8px;border-radius:2px;flex:none}
.loop .lo-ix-k-v i{background:var(--ix-v)}
.loop .lo-ix-k-r i{background:var(--ix-r)}
.loop .lo-ix-k-c i{background:var(--ix-c)}

/* The <svg> at the top of loop.html holds nothing but the refraction filter,
   so it is taken out of layout entirely. It cannot be display:none — a filter
   inside a display:none subtree is not resolvable in every engine. */
.loop .lo-ix-defs{position:absolute;width:0;height:0;overflow:hidden;pointer-events:none}

/* ---- the scene ---- */
.loop .lo-ix-scene{position:relative;flex:1;min-height:0}

/* The drop line sits --ix-drop ABOVE the box's top edge, not straddling it.
   It used to overlap, which is why the ads appeared to start already inside. */
.loop .lo-ix-well{
  position:absolute;left:0;right:0;margin:0 auto;
  max-width:var(--ix-boxw);height:52px;
  bottom:calc(var(--ix-boxh) - 22px + var(--ix-drop) - 52px);
  z-index:1;background:none;box-shadow:none;
}
.loop .lo-ix-flash{
  position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,transparent,#a97cf0,transparent);
  opacity:0;pointer-events:none;
}

/* This layer paints BEHIND the box (z-index 2 against the face's 3), which is
   what the act is built on: a card stays sharp all the way down while it is
   still in the air above the box, then goes frosted the moment it lands inside
   it, because it is now sitting behind the glass. perspective here is what
   lets the landed-card bend (rotateX/skew, set inline by loop.js) read as
   lying flat rather than just tilted 2D. */
.loop .lo-ix-fall{position:absolute;inset:0;z-index:2;overflow:hidden;pointer-events:none;
  perspective:1100px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 58px);
  mask-image:linear-gradient(180deg,transparent 0,#000 58px)}

.loop .lo-ix-fc{
  position:absolute;top:0;left:0;
  transform-origin:50% 100%;   /* cards hinge onto the floor, not their middle */
  width:var(--ix-cardw);aspect-ratio:4/5;
  border-radius:9px;overflow:hidden;
  background:var(--ix-tint,#d6d1de);
  box-shadow:0 14px 30px -14px #2411384d, inset 0 0 0 1px #ffffff8c;
  will-change:transform,opacity;opacity:0;
}
.loop .lo-ix-fc img{width:100%;height:100%;object-fit:cover;display:block}
/* the corpus each falling card belongs to, marked on the card itself */
.loop .lo-ix-fc::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:4px;
  background:var(--ix-src,var(--ix-v));
}
.loop .lo-ix-fc[data-src="v"]{--ix-src:var(--ix-v)}
.loop .lo-ix-fc[data-src="r"]{--ix-src:var(--ix-r)}
.loop .lo-ix-fc[data-src="c"]{--ix-src:var(--ix-c)}

/* ---- the box: a slab of glass (RD round 5) ----

   Round 4 made this frosted glass: the site's one light-ground recipe, a 26px
   backdrop blur. The client's note on it was that it still reads as a flat
   translucent panel rather than a three-dimensional box, and that the ads
   landing inside it are not visible — a 26px blur turns the pile on the floor
   into coloured fog, which is the one thing the act exists to show.

   Both of those come off the same lever. Thickness is not a blur; it is the
   way glass bends what is behind it, hard at the rim and hardly at all through
   the middle. So this rule is now in two halves:

     - the rule below is the everywhere version, and stays on the shell tokens:
       the same frosted recipe as round 4, plus the bevel and the specular
     - the @supports block after it cuts the 26px blur down to 2.4px and adds
       an SVG refraction filter (#lo-ix-refract, at the top of loop.html)
       wherever backdrop-filter can take one

   Firefox does not render an SVG filter through backdrop-filter. Whether it
   also reports that in @supports could not be checked here — there is no
   Firefox on this machine — so the refractive block is written to degrade
   either way: if @supports says no, Firefox lands on the frosted rule below;
   if it says yes and then drops the url(), the blur() and saturate() next to
   the url() still apply and it gets a clear, lightly blurred pane. The bevel
   and the specular are plain CSS and show up in every case.

   The drop shadow stays deliberately small and close. The old
   0 30px 70px -30px #24113899 was 0.6-alpha dark purple thrown 30px DOWN and
   blurred 70px, so it pooled well past the box's bottom edge — and because
   that edge sits on the floor of .lo-ix-sticky, which clips at
   overflow:hidden, the pool was sliced off square at both bottom corners.
   Everything here has blur/2 well under its own spread, so no shadow reaches
   past the box's sides at all and the ground under the corners stays flat.

   Only the material changes here. The animated width/height/radius scrub on
   --ix-t / --ix-w is exactly as it was. */
.loop .lo-ix-face{
  --ix-t:0;
  --ix-w:0;
  position:absolute;left:0;right:0;margin:0 auto;bottom:0;
  width:calc(min(var(--ix-boxw),100%)*(1 - var(--ix-w)) + 100%*var(--ix-w));
  height:calc((var(--ix-boxh) - 22px)*(1 - var(--ix-t)) + (100% - 10px)*var(--ix-t));
  z-index:3;
  border-radius:calc(5px + 21px*var(--ix-t)) calc(5px + 21px*var(--ix-t)) calc(26px + 2px*var(--ix-t)) calc(26px + 2px*var(--ix-t));
  background:var(--gl-l-bg);
  -webkit-backdrop-filter:var(--gl-blur);
  backdrop-filter:var(--gl-blur);
  border:1px solid var(--gl-l-border);
  box-shadow:var(--gl-l-shadow);
  display:flex;align-items:flex-start;justify-content:center;
  padding:calc(20px + 14px*var(--ix-t)) 18px;
  overflow:hidden;
  will-change:width,height;
}

/* The lit bevel and the specular edge. Both are absolutely positioned, so they
   are not flex items of the box, and both sit at z-index 0 — under the dark
   .lo-ix-plate at z-index 1, which has to stay solid and untinted.

   The page's light comes from the upper left (it is where every card shadow on
   this section falls from), so the bright hairline runs along the top and left
   and the shaded one along the bottom and right. Each is an inset shadow with
   a 1.5px offset and a -1px spread: the negative spread is what keeps it to an
   arc on two sides instead of ringing the whole box. */
.loop .lo-ix-face::before,
.loop .lo-ix-face::after{
  content:"";position:absolute;inset:0;z-index:0;
  border-radius:inherit;pointer-events:none;
}
.loop .lo-ix-face::before{
  box-shadow:
    inset 0 0 0 1px #ffffffd9,              /* light piped along the whole rim */
    inset 0 0 14px -6px #ffffffe6,          /* and a little way into the body, which is the thickness */
    inset 2px 2px 1px -1px #ffffff,         /* lit edge, top and left */
    /* The shaded bottom and right. This is the only dark thing on the box and
       it does most of the work: the page ground here is near-white, so a white
       hairline on a white page says nothing, and a body is only believable if
       one pair of sides is turned away from the light. */
    inset -3px -3px 4px -3px #33215cb3,
    inset 0 -16px 18px -20px #33215c47,
    inset 0 28px 36px -34px #ffffffe6;      /* light carrying a little way in from the top */
}
/* The specular: a white highlight riding the top edge and gone within about
   18px. It is masked off at both ends because a highlight that runs edge to
   edge reads as a painted line rather than light catching a surface, and it is
   weighted left because that is where the light comes from. */
.loop .lo-ix-face::after{
  background:linear-gradient(180deg,#ffffffe6 0,#ffffff99 2px,#ffffff00 20px);
  -webkit-mask-image:linear-gradient(90deg,#0000,#000 9%,#00000073 62%,#0000 92%);
  mask-image:linear-gradient(90deg,#0000,#000 9%,#00000073 62%,#0000 92%);
}

/* ---- the refractive version ----

   @supports on backdrop-filter:url() rather than on a browser name. Note this
   is checked in BOTH forms: Safari needs the -webkit- prefix on every
   backdrop-filter, including the one being tested for.

   The fill drops from the token's flat 36% white to a gradient of 32% at the
   top down to 7% at the bottom, because with the blur down to 2.4px the fill
   is the only thing still standing between a reader and the landed pile. */
@supports ((-webkit-backdrop-filter:url(#lo-ix-refract)) or (backdrop-filter:url(#lo-ix-refract))){
  .loop .lo-ix-face{
    /* Heavier at the top, almost clear at the bottom. The pile lands on the
       FLOOR of the box, so the clearest part of the glass is exactly where the
       ads are, and the empty top still has enough fill to read as a surface
       rather than a hole. It also agrees with the light: brightest where the
       light lands, thinning as the surface turns away. */
    background:linear-gradient(168deg,#ffffff52 0%,#ffffff24 40%,#ffffff12 100%);
    /* The blur and the saturation are CSS functions rather than primitives
       inside the filter, so a browser that accepts url() here but cannot
       actually render an SVG filter through backdrop-filter still ends up with
       a real blurred glass instead of a clear pane. 2.4px is the number the
       screenshots landed on: any more and the pile turns back into the
       coloured fog the client complained about, any less and the box stops
       being a material at all. */
    -webkit-backdrop-filter:blur(2.4px) saturate(145%) url(#lo-ix-refract);
    backdrop-filter:blur(2.4px) saturate(145%) url(#lo-ix-refract);
    border:1px solid #ffffff73;
    box-shadow:
      /* A hairline of ink just outside the white border. Without it the box has
         no silhouette at all on this near-white ground — the white-on-white
         rim was most of why round 4 read as a flat panel. */
      0 0 0 1px #2b1b4326,
      /* contact, then the token's soft one: set down on the ground, not
         floating over a dark pool */
      0 4px 10px -6px #2411384d,
      0 22px 48px -34px #2411384d;
  }
}

/* ---- the label: sits ON TOP of the glass, centred, black background
   (RD round 3) — everything the box has to say lives in here now: the
   count, then four bar rows read like headings, nothing else. ---- */
.loop .lo-ix-plate{
  position:relative;z-index:1;
  /* narrow while it is just a count and four bars; wide once it holds
     three columns — wide means one line per finding, which is what
     keeps it from growing into a slab down the middle of the page */
  width:min(calc(560px + 500px * var(--ix-w,0)),100%);
  border-radius:18px;
  background:#0c0813;
  box-shadow:0 24px 50px -24px #00000080,inset 0 0 0 1px #ffffff14;
  padding:22px 26px 20px;
  color:#efe9f7;
}

.loop .lo-ix-count{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding-bottom:16px;margin-bottom:16px;border-bottom:1px solid #ffffff1c;
}
.loop .lo-ix-count>b{
  font-size:clamp(44px,4.6vw,60px);
  font-weight:800;letter-spacing:-.045em;line-height:1;color:#fff;
  font-variant-numeric:tabular-nums;
}
.loop .lo-ix-count-label{font-size:15px;font-weight:600;color:#b6a3ce;letter-spacing:-.005em}

/* chart and out crossfade in the same box (loop.js drives opacity), so both
   stay absolutely stacked the way the two states did before this pass. Sized
   to fit the taller of the two: three headed columns of three findings. */
.loop .lo-ix-body{position:relative;
  /* short while the ads fall (so the pile on the floor is visible),
     tall once it has to hold the three insight columns */
  height:calc(126px + 54px * var(--ix-w,0))}

.loop .lo-ix-chart{position:absolute;inset:0;overflow:hidden}
.loop .lo-ix-rows{position:relative;height:calc(4 * var(--ix-rowh))}
/* four rows only (RD round 3: "not this much data") — bigger and higher
   contrast than the old nine-row breakdown, read like short headings. */
.loop .lo-ix-row{
  position:absolute;left:0;right:0;top:0;height:var(--ix-rowh);
  display:grid;grid-template-columns:8px minmax(0,1fr) 92px 34px;
  align-items:center;gap:12px;border-radius:8px;
  opacity:0;will-change:transform,opacity;
}
.loop .lo-ix-row:nth-child(n+5){display:none}
.loop .lo-ix-dot{width:8px;height:8px;border-radius:2px;background:var(--ix-c2)}
.loop .lo-ix-label{font-size:17px;font-weight:650;letter-spacing:-.015em;color:#f7f2fc;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.loop .lo-ix-bar{position:relative;height:6px;border-radius:4px;background:#ffffff1c;overflow:hidden}
.loop .lo-ix-bar i{position:absolute;inset:0;border-radius:4px;background:var(--ix-c2);
  transform-origin:0 50%;transform:scaleX(0);transition:transform .5s cubic-bezier(.16,1,.3,1)}
.loop .lo-ix-n{font-family:ui-monospace,Menlo,monospace;font-size:14px;font-weight:600;color:#e7ddf5;text-align:right;font-variant-numeric:tabular-nums}
.loop .lo-ix-row.is-top .lo-ix-label{color:#fff;font-weight:700}

/* the resolved answer: top three hooks / narratives / creator types */
.loop .lo-ix-out{
  position:absolute;inset:0;opacity:0;pointer-events:none;overflow:hidden;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:26px;
}
.loop .lo-ix-col{min-width:0;display:flex;flex-direction:column}
.loop .lo-ix-col-h{
  font-family:ui-monospace,Menlo,monospace;
  font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:#b69ae0;margin:0 0 8px;font-weight:700;
}

.loop .lo-ix-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.loop .lo-ix-list li{opacity:0;will-change:transform,opacity}
.loop .lo-ix-list b{display:block;font-size:14px;font-weight:650;
  letter-spacing:-.015em;line-height:1.26;color:#f7f2fc}
.loop .lo-ix-list em{display:block;font-style:normal;font-size:11.5px;
  color:#b6a3ce;margin-top:2px;line-height:1.35}

/* ---- verdict chips ---- */
.loop .lo-ix-chips{position:absolute;inset:0;z-index:2;pointer-events:none}
.loop .lo-ix-chip{
  position:absolute;top:0;left:0;display:inline-flex;align-items:center;gap:7px;
  white-space:nowrap;padding:7px 12px;border-radius:99px;
  font-size:11.5px;font-weight:550;letter-spacing:-.005em;
  box-shadow:0 10px 24px -12px #24113866;opacity:0;will-change:transform,opacity;
}
.loop .lo-ix-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.loop .lo-ix-chip.is-g{color:var(--ix-green);background:var(--ix-green-bg);box-shadow:0 10px 24px -14px #1e967866,inset 0 0 0 1px #1e967826}
.loop .lo-ix-chip.is-r{color:var(--ix-red);background:var(--ix-red-bg);box-shadow:0 10px 24px -14px #d9435e66,inset 0 0 0 1px #d9435e26}

/* ---- narrower ---- */
@media (max-width:1100px){
  .loop .lo-ix{--ix-boxh:274px;--ix-drop:84px;--ix-cardw:80px;--ix-rowh:25px}
  .loop .lo-ix-out{grid-template-columns:repeat(2,minmax(0,1fr))}
  .loop .lo-ix-out .lo-ix-col:nth-child(3){display:none}
}
@media (max-width:860px){
  .loop .lo-ix{--ix-boxh:258px;--ix-drop:70px;--ix-cardw:70px;--ix-rowh:24px}
  .loop .lo-ix-out{grid-template-columns:minmax(0,1fr)}
  .loop .lo-ix-out .lo-ix-col:nth-child(2),
  .loop .lo-ix-out .lo-ix-col:nth-child(3){display:none}
  .loop .lo-ix-body{height:auto;min-height:clamp(150px,20vh,196px)}
}

/* ---- phone: the scrub runs here too (RD: "the ads falling down doesn't
   work for mobile phones"). A smaller box, smaller cards, a shorter runway and
   a shorter track; the floating chips come off (they were landing on the box
   at this width) and so does the refraction filter — a plain 2.4px blur is
   the same glass at a phone's pixel budget. The answer columns already reduce
   to one under 860px, which is what the old "collapsing into one" note was
   guarding against. ---- */
@media (max-width:640px){
  .loop .lo-ix{--ix-boxh:224px;--ix-drop:56px;--ix-cardw:56px;--ix-rowh:22px;height:240vh}
  .loop .lo-ix-sticky{min-height:0}
  .loop .lo-ix-stage{padding:clamp(24px,3.4vh,40px) 0 clamp(14px,2vh,22px);gap:10px}
  .loop .lo-ix-legend{gap:10px 12px;font-size:10.5px}
  .loop .lo-ix-chan{padding-left:0;border-left:0;flex-basis:100%;justify-content:center}
  .loop .lo-ix-chips{display:none}
  .loop .lo-ix-face{padding:calc(14px + 10px*var(--ix-t)) 12px;
    -webkit-backdrop-filter:blur(2.4px) saturate(145%);backdrop-filter:blur(2.4px) saturate(145%)}
  .loop .lo-ix-count>b{font-size:44px}
  .loop .lo-ix-count-label{font-size:13px}
}

/* ---- static fallback: reduced motion and short (landscape) viewports ---- */
@media (prefers-reduced-motion:reduce),(max-height:620px){
  .loop .lo-ix{height:auto;margin-bottom:clamp(32px,5vw,64px)}
  .loop .lo-ix-sticky{position:static;height:auto;min-height:0;overflow:visible}
  .loop .lo-ix-stage{height:auto}
  .loop .lo-ix-scene{min-height:0;display:flex;flex-direction:column;gap:16px}
  .loop .lo-ix-well,.loop .lo-ix-fall,.loop .lo-ix-chips{display:none}
  /* no pile and no aurora movement behind the box here, so there is nothing
     for a blur to frost — an opaque card is both cheaper on a phone and
     easier to read than 36% white with the blur switched off */
  .loop .lo-ix-face{position:static;width:100%;height:auto;--ix-t:0;--ix-w:1;
    -webkit-backdrop-filter:none;backdrop-filter:none;background:#fff;border-color:#17121f1a}
  /* an opaque white card has no thickness to light, and a white specular on
     white is invisible anyway — both layers come off here */
  .loop .lo-ix-face::before,.loop .lo-ix-face::after{display:none}
  /* .lo-ix-plate, not .lo-ix-label: the dark read is the plate, and
     .lo-ix-label is a row label inside the chart this block hides anyway */
  .loop .lo-ix-plate{background:#0c0813}
  .loop .lo-ix-body{height:auto}
  .loop .lo-ix-chart{display:none}
  .loop .lo-ix-out{position:static;opacity:1}
  .loop .lo-ix-list li{opacity:1}
}

/* scroll targets only — never painted */
.loop .lo-ix-anchor{position:absolute;left:0;top:32%;width:1px;height:1px;opacity:0;pointer-events:none}
.loop .lo-ix-anchor-end{top:78%}
