/* ============================================================
   Shared scroller engine — the LTP explainer series
   Form reference: skills/scrollable-explainer/SKILL.md
   Pinned stages via CSS position:sticky. No scrolljacking.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Figtree:wght@400;600;700&family=Literata:opsz,wght@7..72,400;7..72,600;7..72,700&display=swap');

/* Colour and the sans face come from the Organic design system that the rest
   of the site runs on — the styles.css under story/_ds/organic-… . Its tokens
   are restated here rather than imported, because these pages are standalone
   and don't pull in the system's stylesheet; the values below are copied from
   it, and the names beneath them are what the drawings actually use.

   The serif is deliberately not the system's display face. The register for
   this series was settled as hand-drawn-on-paper, which wants a book serif for
   running text; Caprasimo is a poster face and fights it. */
:root{
  --color-bg:#f5ead8;
  --color-surface:#ebddc5;
  --color-text:#201e1d;
  --color-accent:#c67139;
  --color-accent-2:#7a8a5e;
  --color-accent-200:#ffe1d0;
  --color-neutral-500:#a19786;
  --color-neutral-700:#645c50;

  --paper:var(--color-bg);
  --paper-2:var(--color-surface);
  --ink:var(--color-text);
  --ink-soft:var(--color-neutral-700);
  --ink-faint:var(--color-neutral-500);
  --mark:var(--color-accent);  /* the constraint / the thing at issue */
  --mark-2:var(--color-accent-2);
  /* text highlight block: the accent's lightest tint, dropped onto the paper */
  --hl:color-mix(in srgb, var(--color-accent-200) 62%, var(--color-surface));
  /* Literata is a book serif built for long-form reading: warmer and rounder
     than the Iowan/Palatino stack this used to fall back through, and — the
     real reason — the same on every machine. That stack rendered as Iowan on a
     Mac, Georgia on Windows and Noto on Android, which is three different
     pieces. Local faces stay as the fallback. */
  --serif:"Literata","Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  --sans:"Figtree",system-ui,-apple-system,"Segoe UI",sans-serif;
}

*{box-sizing:border-box}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--serif);font-size:17px;line-height:1.5;
  overflow-x:clip;-webkit-font-smoothing:antialiased;text-wrap:pretty;
}
body::before{
  content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  opacity:.5;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='220' height='220' filter='url(%23n)' opacity='0.32'/></svg>");
}

/* ---------- progress ---------- */
.progress{position:fixed;top:0;left:0;height:2px;background:var(--mark);
          width:0;z-index:50;transition:width .1s linear}

/* ---------- pinned stage ----------
   The sticky child would otherwise take a screen of document flow of its own
   *before* the first trigger begins, and a step only fires when its trigger
   crosses the middle band of the viewport — so the second beat of a section
   did not arrive until about 1.45 screens of scrolling. The reader scrolls a
   screen and a half of an already-finished drawing and concludes the page is
   broken. The negative margin takes that screen back, so the triggers start at
   the section's own top and the first change lands at about 0.45 screens.
   The padding then extends the sticky's travel past the last trigger, so the
   final beat is not unpinning at the moment it appears: the dead screen moves
   from the head of the section, where it reads as broken, to the tail, where
   it reads as a hold on a finished drawing. */
.scroll-item{position:relative;padding-bottom:55svh}
.sticky-item{position:sticky;top:0;height:100svh;overflow:hidden;z-index:1;
             margin-bottom:-100svh}
.stage{position:relative;width:100%;height:100%;display:grid;place-items:center}
.stage svg{width:min(100%,1100px);height:100%;display:block}
.trigger{height:100svh}

.layer{opacity:0;transition:opacity .55s ease}
.layer.on{opacity:1}

/* ---------- text steps ---------- */
.steps{position:absolute;inset:0;z-index:3;pointer-events:none}
.step{position:absolute;max-width:23rem;opacity:0;transition:opacity .5s ease;
      font-size:clamp(1.05rem,1.5vw,1.32rem);line-height:1.42}
.step.on{opacity:1}
.step p{margin:0;background:var(--hl);padding:.6em .8em;
        box-decoration-break:clone;-webkit-box-decoration-break:clone}
.step.plain p{background:none;padding:0}
/* A full-screen statement that lands on top of the drawing rather than on
   empty paper. The highlight tint is for annotations; at display size across
   34rem it reads as a slab, so this one takes the paper itself as its ground
   and the drawing goes quiet behind it. */
.step.onpaper p{background:var(--paper);padding:.5em .7em}
.step.lead{left:8vw;top:34vh}
.step.tl{left:8vw;top:14vh}   .step.tr{right:8vw;top:14vh}
.step.bl{left:8vw;bottom:16vh} .step.br{right:8vw;bottom:16vh}
/* Vertically centred in the side gutter, and centred at the top or foot of the
   frame. Between them, every drawing has somewhere to put a caption that isn't
   on top of the thing the caption is about. */
.step.cl{left:8vw;top:50%;transform:translateY(-50%)}
.step.cr{right:8vw;top:50%;transform:translateY(-50%)}
.step.tc{left:50%;top:7vh;transform:translateX(-50%);text-align:center;max-width:32rem}
.step.bc{left:50%;bottom:7vh;transform:translateX(-50%);text-align:center;max-width:32rem}
.step.mid{left:50%;top:50%;transform:translate(-50%,-50%);text-align:center;max-width:34rem}
.step.big p{font-size:clamp(1.7rem,4.2vw,2.9rem);line-height:1.14}

/* ---------- stacked steps ----------
   Opt-in with <div class="steps stack">. Instead of each beat replacing the
   last in the same spot, the blocks accumulate down a column, so the reader
   can see a sequence unfolding and read back over it rather than trusting
   their memory of a sentence that has now vanished. The ones already read
   stay, dimmed; scroller.js marks the live one .cur.

   Only wide screens get the column. A 20rem column beside a drawing that is
   1000 units across needs about 1200px before the drawing's 12.5px labels
   start rendering below 10px, and an unreadable diagram costs more than the
   sequence gains. Below that the group falls back to one block at a time, in
   whatever position its own class asks for — so keep the tl/bc/etc. classes on
   stacked steps too, they are what the narrow layout uses.

   The stage is padded out of the column's way rather than the drawings being
   redrawn around it, so any section can opt in without moving coordinates. */
.steps.stack .step{opacity:0}
.steps.stack .step.cur{opacity:1}

@media (min-width:1200px){
  .steps.stack{display:flex;flex-direction:column;align-items:flex-start;gap:.5rem;
               inset:10vh auto auto 6vw;width:min(20rem,26vw)}
  .steps.stack .step{position:static;transform:none;width:100%;max-width:100%;
                     text-align:left;font-size:clamp(1rem,1.2vw,1.16rem)}
  .steps.stack .step.on{opacity:.5}
  .steps.stack .step.cur{opacity:1}
  .sticky-item:has(.steps.stack) .stage{padding-left:calc(6vw + min(20rem,26vw) + 2vw)}
}

/* ---------- flow (prose) sections ---------- */
.flow{position:relative;z-index:2;background:var(--paper);padding:13vh 1.25rem}
.wrap{max-width:37rem;margin:0 auto}
/* Set to match the annotation captions inside the drawings rather than a
   default article size — the piece reads as one voice that way, and the
   running text stops feeling like the small print between the graphics.
   The measure widens with it to hold ~68 characters a line. */
.flow p{font-size:clamp(1.12rem,1.5vw,1.3rem);line-height:1.6;margin:0 0 1.1em}
.flow p:last-child{margin-bottom:0}
.flow a{color:var(--ink);text-decoration-color:var(--mark);text-underline-offset:.18em}
.flow a:hover{color:var(--mark)}
/* A quoted voice, not a figure: a rule at the left rather than a box. Used by
   the Second Renaissance piece, where the quotes are the evidence. */
.flow blockquote{margin:0 0 1.3em;padding:.1em 0 .1em 1.2rem;
  border-left:2px solid var(--mark);font-size:clamp(1.16rem,1.6vw,1.36rem);line-height:1.54}

.kicker{font-family:var(--sans);text-transform:uppercase;letter-spacing:.14em;
        font-size:.72rem;color:var(--ink-faint);margin:0 0 2.2em !important}
.title{font-family:var(--serif);font-weight:700;letter-spacing:-.02em;
       font-size:clamp(3rem,10vw,7.5rem);line-height:.94;margin:0 0 .28em}
.dek{font-family:var(--sans);font-size:1.02rem;color:var(--ink-soft);
     max-width:26rem;line-height:1.45;margin:0 !important}

/* ---------- hero ----------
   These pieces get linked to cold, and a reader who lands inside a pinned
   stage has no title, no orientation and no way of knowing that scrolling is
   the interaction — they arrive, nothing happens, and they leave. The hero is
   the cost of that: a screen that says what this is and points down. */
.hero{position:relative;z-index:2;min-height:100svh;display:grid;place-items:center;
      padding:11vh 1.25rem 13vh}
.hero .wrap{max-width:37rem;margin:0 auto;width:100%}
/* a shade under the standalone title card's scale: some of these titles run to
   four lines, and at the larger size the dek and the standfirst fall off the
   first screen — which loses exactly the reader the hero exists for */
.hero .title{font-size:clamp(2.8rem,8vw,6.2rem)}
.hero .dek{font-size:1.16rem;max-width:30rem;line-height:1.5}
.hero .note{font-family:var(--sans);font-size:.84rem;color:var(--ink-faint);
            margin:2.4em 0 0;max-width:26rem;line-height:1.5}
.hero .note a{color:var(--ink-soft);text-decoration-color:var(--mark);
              text-underline-offset:.18em}
.hero .note a:hover{color:var(--mark)}
/* One cue, one behaviour, whether the piece lands on a hero or straight on a
   drawing: fixed at the foot of the first screen, over whatever is behind it,
   and gone for good once the reader has scrolled a third of a screen — by then
   they know the page moves and it has nothing left to say. Fixed rather than
   parked inside the hero because a long title pushes the hero past a screen
   and takes an absolutely positioned cue below the fold with it, which is
   precisely the reader this is for. */
.scrollcue{position:fixed;left:50%;transform:translateX(-50%);bottom:5vh;
           z-index:35;pointer-events:none;
           display:flex;align-items:center;gap:.6rem;
           font-family:var(--sans);font-size:.72rem;letter-spacing:.14em;
           text-transform:uppercase;color:var(--ink-faint);
           transition:opacity .45s ease}
.scrollcue.gone{opacity:0}
.scrollcue svg{display:block;animation:cuebob 2.1s ease-in-out infinite}
@keyframes cuebob{0%,100%{transform:translateY(-2px)}50%{transform:translateY(4px)}}


/* ---------- top bar ----------
   Nothing over the hero; it fades in once the hero has gone, so there is
   always a way back to the site and always a name for where you are. */
.topnav{position:fixed;top:0;left:0;right:0;z-index:40;display:flex;
        align-items:center;justify-content:space-between;gap:1rem;
        padding:.62rem clamp(1rem,4vw,2.2rem);
        background:var(--paper);border-bottom:1px solid rgba(34,32,29,.14);
        font-family:var(--sans);font-size:.76rem;letter-spacing:.08em;
        opacity:0;visibility:hidden;transition:opacity .35s ease,visibility .35s}
.topnav.on{opacity:1;visibility:visible}
.topnav a{color:var(--ink);text-decoration:none}
.topnav a:hover{color:var(--mark)}
.topnav .crumb{white-space:nowrap}
.topnav .here{color:var(--ink-faint);text-transform:uppercase;letter-spacing:.14em;
              white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* One line, always: a bar that wraps to two eats the top of the drawing
   underneath it, which on a phone is most of the drawing. */
@media (max-width:640px){
  .topnav{font-size:.68rem;padding:.5rem .9rem}
  .topnav .up{display:none}
  .topnav .here{letter-spacing:.1em}
  .topnav .part{display:none}
  /* the word goes: on a phone the caption is already at the foot, and the
     arrow on its own carries it in the gap beneath */
  .scrollcue{bottom:2vh}
  .scrollcue span{display:none}
}

/* big statement screens */
.statement{min-height:100svh;display:grid;place-items:center;text-align:center;
           padding:0 1.25rem;position:relative;z-index:2}
.statement p{max-width:22ch;font-size:clamp(1.85rem,4.8vw,3.2rem);
             line-height:1.13;margin:0;letter-spacing:-.015em}
.statement.sm p{max-width:30ch;font-size:clamp(1.3rem,3vw,2rem)}

/* pull number */
.figure-num{font-family:var(--sans);font-weight:700;font-variant-numeric:tabular-nums;
            font-size:clamp(3rem,9vw,6rem);color:var(--mark);line-height:1}
.figure-cap{font-family:var(--sans);font-size:.78rem;letter-spacing:.1em;
            text-transform:uppercase;color:var(--ink-soft);margin-top:.5em}

/* ---------- sources ---------- */
.sources{position:relative;z-index:2;background:var(--paper-2);padding:11vh 1.25rem}
.sources .wrap{max-width:40rem}
.sources h2{font-family:var(--sans);font-size:.8rem;letter-spacing:.14em;
            text-transform:uppercase;color:var(--ink-soft);margin:0 0 1.6em;font-weight:600}
.sources p{font-size:1.02rem;line-height:1.62;color:var(--ink-soft)}

/* ---------- series nav ---------- */
.seriesnav{position:relative;z-index:2;background:var(--paper);
           padding:9vh 1.25rem 14vh;border-top:1px solid rgba(34,32,29,.14)}
.seriesnav .wrap{max-width:34rem}
.seriesnav a{display:block;text-decoration:none;color:var(--ink);
             border:1px solid rgba(34,32,29,.2);padding:1.15em 1.3em;margin-bottom:.8em}
.seriesnav a:hover{border-color:var(--mark);color:var(--mark)}
.seriesnav .n{font-family:var(--sans);font-size:.7rem;letter-spacing:.14em;
              text-transform:uppercase;color:var(--ink-faint);display:block;margin-bottom:.3em}
.seriesnav .t{font-size:1.2rem}

@media (max-width:640px){
  .step{max-width:min(86vw,22rem);font-size:1.02rem}
  /* In portrait the drawing needs the upper area; captions go to the foot
     of the screen and get an opaque ground so nothing shows through. */
  .step.lead{left:6vw;right:auto;top:auto;bottom:8vh}
  .step.tl,.step.tr,.step.bl,.step.br,
  .step.cl,.step.cr,.step.tc,.step.bc{
    left:6vw;right:auto;top:auto;bottom:6vh;transform:none;text-align:left;
    max-width:min(88vw,22rem)}
  .step p{background:var(--paper-2)}
  /* The full-screen statement steps stay centred horizontally but drop below
     the drawing band; dead centre put them straight across the drawing. */
  .step.mid{top:auto;bottom:24vh;transform:translateX(-50%)}
  /* Wide diagrams shrink to an unreadable ribbon in portrait, because a
     drawing 800 units across is squeezed into 390px and its 13px labels come
     out at 6px. scroller.js re-fits each stage's viewBox to its own content
     and parks it in the upper band, clear of the caption at the foot. */
  .stage{padding:0 3vw}
  /* the fixed bar would otherwise sit on the top edge of the drawing */
  body:has(.topnav) .stage{padding-top:2.2rem}
  .flow{padding:10vh 1.25rem}
  .sources{padding:9vh 1.25rem}
}

@media (prefers-reduced-motion:reduce){
  .layer,.step,.progress,.topnav{transition:none}
  .scrollcue svg{animation:none}
}

/* landscape-only annotations: hidden where a portrait layout carries the point */
@media (max-width:640px){ .wide-only{display:none} }
