/* ==========================================================================
   case.css — a case study, in the draft's own language.

   Each case study is one long page (vicino.html, pantrypal.html,
   nextlevel.html) under the same masthead as the rest of the draft: on the
   left a round back button and the title pill, which names the part of the
   story you are reading as the page scrolls past it (js/case.js); on the
   right the yellow square and its four pages. Everything under it is drawn
   from the same few things the draft already has:
     the reading     a book's sizes, not the frame's one size: the story is
     sizes           read at 18.5, a chapter's first sentence at 26, and its
                     title at 84, so a part of the story can be told from
                     across the room and its words are easy to stay with.
                     (Every word stood at the frame's 36 until October 2026,
                     the small type at 22; Tigo found the pages too big to
                     read through.) Hierarchy within a paragraph is still by
                     ink, never by weight: a key phrase in the page's ink,
                     the words round it a step quieter, as About's letter
                     does it
     the chapters    each story is told in the chapters its milestones name,
                     every one opening on its number, its title, what it is
                     about and when, so where one part ends and the next
                     begins is never in doubt; a list of them in the
                     lane's left margin keeps them all in reach
                     (js/case.js)
     the rhythm      a handful of distances, each kept for one meaning:
                     a caption to its picture, a piece to the next of the
                     same moment, the words to the work, a head to its
                     words, a part, a chapter (--air-*); all of them close,
                     so a part of the story is seen whole in one window
     the tiles       one surface in the case's own colour, lit from its
                     top-left corner and deepening at its foot, the Work
                     tile's own (css/work.css), and lit again wherever the
                     pointer is over it; the work in them stands in plain
                     rounded windows, or on phones, on shadows of the
                     tile's colour. A few moments stand on the work's own
                     surfaces instead (the app's butter kitchen, a white
                     sheet, an editor's dark panel, a kitchen ticket), so
                     the eye can tell the parts apart by surface alone
     the pills       the Work tile's frosted white chip for links and labels,
                     filled with the tile's colour when chosen
     the bubbles     the chat's own, for the few places a story is a
                     conversation: a question in the sender's blue, an
                     answer in the reply grey (css/home.css)
     the motion      pieces rise into place the first time they come into
                     view, on the page's one entrance (js/motion.js rise),
                     and a tile lifts when pointed at, as on Work
   The page opens on the case's Work tile grown to fill the whole window:
   its icon and name, the links to the product, and the product itself. Going from a Work
   tile to its case study, the tile grows into that one (a view transition,
   where the browser has them); coming back, it shrinks home.

   Each case speaks a little of its own product's language in the places
   that number and join the story: PantryPal's chapters are numbered in the
   app's own sticker type, Vicino's are nodes on a board wired one into the
   next, and Next Level's stand in the badge's ring, as a brand book's do.
   The rail that lists them is dressed the same way: the app's recipe, a
   run down a pipeline, a drone's flight plan (below, "the rail").
   ========================================================================== */

/* (the opt-in to carrying views across pages is in each page's head) */

/* Each case's two colours, and a third for ink: --deep-lit is the deep
   colour lifted until it reads on the dark page as the deep reads on the
   paper (about 7:1 on #1c1c1e), for the few words set in it straight on
   the page (--accent, below, and "the case studies in ink" at the foot). */
.cs[data-case='vicino'] { --tint: #c9eff1; --deep: #1c6f78; --deep-lit: #63bcc4; }
.cs[data-case='pantrypal'] { --tint: #ffd9c9; --deep: #a9492a; --deep-lit: #ec9474; }
.cs[data-case='nextlevel'] { --tint: #c9e3fd; --deep: #245f9e; --deep-lit: #72a8e6; }
/* the other two, for the next case at the page's foot */
.cs-next[data-case='vicino'] { --tint: #c9eff1; --deep: #1c6f78; }
.cs-next[data-case='pantrypal'] { --tint: #ffd9c9; --deep: #a9492a; }
.cs-next[data-case='nextlevel'] { --tint: #c9e3fd; --deep: #245f9e; }
/* The deep colour as words standing on the page itself, with nothing of
   their own under them: a part's number, an eyebrow, a date, the phrase
   that carries the overview. It is the deep colour on the paper and on
   every wash, and the lit one on ink; on anything that keeps the paper
   (a tile, a sheet, a ticket), it is the deep colour again. */
.cs { --accent: var(--deep); }

.cs {
  /* where content may begin under the masthead: the square's foot and the
     band's 24 under it, as on Work (css/base.css) */
  --cs-top: calc(var(--top) + 3 * var(--u) + var(--menu-size) + 24 * var(--u));
  --gap: calc(24 * var(--u));
  --pad: calc(28 * var(--u));
  --r-tile: calc(32 * var(--u));
  --r-well: calc(20 * var(--u));
  --r-window: calc(14 * var(--u));
  /* The one column the story keeps to (below, "the page"): its heads,
     its words, its tiles and its pictures, the ones that open included,
     all stand between the same two edges, a channel down the middle of
     the window, 920 frame pixels at the most and 760 at the least where
     the window has the room (below, "the lane"). The words keep to a
     reading measure inside it by standing beside their head rather than
     under it (below, "a head beside its words"), so their lines run about
     fifty to seventy letters and still end on the column's right edge.
     (Until October 2026 there were three widths: the words at 640, the
     work at 880, and a stage of 1192 that a few pieces stepped out onto.
     Down one chapter the eye met three right edges, and Tigo asked for
     one; it was then 640 for everything for a day, which left the lane's
     two sides empty on a large screen, and then the whole lane, up to
     1192, which ran wall to wall on a large screen and stood the story
     right up against the list of chapters.) --measure is for words that
     stand on their own across the column, a caption's. --split-gap is the
     gutter between a head and its words, wherever the two stand side by
     side. */
  --col: calc(920 * var(--u));
  --col-min: calc(760 * var(--u));
  --measure: calc(640 * var(--u));
  --split-gap: calc(56 * var(--u));

  /* The rhythm. How far apart two things stand says how far apart they
     are in the story, so there are only a few distances, each kept for
     one meaning, and each a clear step from the next: a picture's words
     hang just under it; the pieces of one moment stand at the grid's own
     gap, as the tiles of a row do; the words that lead into the work stand
     a little clear of it; a head stands nearer the words it opens than
     those words stand to the work, so a head and its words read as one;
     then a part of a chapter, and a chapter. All of them are kept close,
     so a part of the story, its head, its words and its work, is seen
     together in one window, as a spread of a book is. (Each was chosen
     piece by piece until October 2026, 40 here and 64 there, with 200
     before a chapter and 132 before a part: a part took two windows to
     see on a large screen, its picture in one and its notes in the next.
     A wash of the case's colour behind each chapter's head was tried for
     a day, to tell the chapters apart from afar; it read as a hard band
     across the page, and Tigo wanted the parts drawn together, not cut
     apart.) */
  --air-cap: calc(12 * var(--u));
  --air-stack: var(--gap);
  --air-work: calc(32 * var(--u));
  --air-head: calc(28 * var(--u));
  --air-part-head: calc(18 * var(--u));
  --air-part: calc(88 * var(--u));
  --air-chapter: calc(144 * var(--u));

  /* The reading sizes. Each has a floor in plain pixels, because --u
     follows the window's height as well as its width, and a short window
     would otherwise take the story's words down past what reads easily. */
  /* A chapter's title, and a part's, about half a chapter's and well
     clear of a tile's name, so the three heads are three clear steps. (A
     chapter's stood at 84 until October 2026, and with its number and
     what it is about it took a third of a large screen before a word of
     the chapter was read.) */
  --t-display: calc(64 * var(--u));
  --t-title: calc(36 * var(--u));
  --t-lead: max(19px, calc(26 * var(--u)));
  --t-body: max(15.5px, calc(18.5 * var(--u)));
  --t-name: max(16px, calc(21 * var(--u)));
  --t-small: max(13px, calc(15 * var(--u)));
  --t-micro: max(11px, calc(12.5 * var(--u)));
  --lh-body: 1.56;
  /* SF's own tracking for its text sizes is a hair open; the display
     sizes close up as SF Display does in Apple's own headlines */
  --track-body: -0.006em;
  --track-lead: -0.017em;
  --track-display: -0.038em;
}
/* The deep colour, quieted for words on a tile, as the Work meta is. It is
   worked out again on every tile, not once for the page, so a tile in
   another case's colour (the next case, at the foot) quiets its own.
   The quieter one is mixed with the small print's ink taken a step
   deeper (#5c5b5b, not --ink-3's #6f6e6e): since the case studies' small
   type went down to 15 and 12.5, it has to hold 4.5:1 on its own, and
   with --ink-3 it measured 4.1 to 4.4 on the deepest stop of a tile. */
.cs, .cs-next, .cs-tile, .cs-stat {
  --tile-ink: color-mix(in oklab, var(--deep) 55%, var(--ink));
  --tile-ink-2: color-mix(in oklab, var(--deep) 45%, #5c5b5b);
}

/* ---- the masthead's left side: the way back ----
   A white circle as tall as the index's title pill, with a chevron in it,
   going to Work, and round it a ring that fills as the page is read
   (below, "reading"). (A pill stood beside it that named the part of the
   story being read, the index's own capsule, stretching to each word in
   turn; Tigo wanted its room back for the story, and the rail in the
   lane's margin says where you are now.) */
.cs-head {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  min-width: 0;
  margin-top: calc(3 * var(--u) + (var(--menu-size) - var(--title-h)) / 2);
}
.cs-back {
  flex: none;
  display: grid;
  place-items: center;
  width: var(--title-h);
  height: var(--title-h);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.2s ease, scale var(--t-pop) var(--spring-pop);
}
.cs-back svg { width: calc(26 * var(--u)); height: calc(26 * var(--u)); transition: translate var(--t-snap) var(--spring-snap); }
@media (hover: hover) {
  .cs-back:hover { background: var(--tint); color: var(--pastel-ink); }
  .cs-back:hover svg { translate: calc(-2 * var(--u)) 0; }
}
.cs-back:active { scale: 0.94; transition-duration: 90ms; }

/* Nothing is laid across the masthead, and nothing but the opening tile
   ever scrolls up under its buttons: the story keeps to the lane between
   them (below).
   (For a while the masthead stood on a strip of the paper that thinned to
   nothing where the content began, and what scrolled up faded out under
   it; it cost the page that strip of the window. Then for a while the
   story ran centred across the whole band, and passed behind the back
   button, the title and the square on its way up.) */

/* ---- the lane ----
   The band of the window the story keeps to below its opening tile, so
   nothing in it ever slides up behind a button or under the list of
   chapters (the tile is the one thing as wide as the window: below, "the
   hero"). On the left it starts past the rail, the list of chapters under
   the back button, at its open width and 48 of air more: where a pointer
   can hover, the rail stands folded, as narrow as the button over it, and
   opens to its names when pointed at (below, "the rail, folded"), into a
   margin kept empty for it, so opened it never reaches the story. On a
   touch screen, which cannot hover, it stands open in the same margin. On
   the right the lane ends short of the menu square, with 28 of air.
   The story's column stands in the middle of the window, its two margins
   alike, wherever the left one holds the open rail (--lane-l). Where it
   cannot without the column coming down under 760 (--col-min), the
   column holds at 760 and moves right of the middle, as far as it must,
   its right margin narrowing toward the menu's (--lane-r); and only
   where even that is too little room does it come down under 760. So on
   a large screen the story is a channel in the window's middle with the
   rail well clear of it, and on a laptop the column keeps its width, a
   little right of the middle. (--main-pad-r is that margin, read against
   the window's width: a percentage in a padding is a share of the
   frame's width, and the frame is the window's.) (The left edge was set
   by the title pill at its widest until the pill went, some 140 further
   in at 1440; then by the open rail, 28 past it; then for a day by the
   folded rail, which, opened, lay over the story's first words.)
   A phone has no room for a lane or a rail: there the story keeps to the
   gutters, under the masthead's row. */
@media (min-width: 761px) {
  .cs {
    /* (open, 164 at the least: in a short window the small type stops at
       13 while the rail's own spacing keeps shrinking, and at 152 "Five
       questions" and "The AI guide" lost their last letters) */
    --rail-open: max(164px, calc(184 * var(--u)));
    --rail-w: var(--rail-open);
    --rail-gap: calc(48 * var(--u));
    --lane-gap: calc(28 * var(--u));
    --lane-l: calc(var(--gutter-l) + var(--rail-open) + var(--rail-gap));
    --lane-r: calc(var(--gutter-r) + var(--menu-size) + var(--lane-gap));
    --main-pad-r: clamp(var(--lane-r), 100% - var(--lane-l) - var(--col-min), var(--lane-l));
  }
}
@media (min-width: 761px) and (hover: hover) {
  /* folded, the rail is exactly as wide as the back button over it */
  .cs { --rail-w: var(--title-h); }
}

/* ---- the page ----
   The story is set in one column down the middle of the lane, as a long
   read is (Tigo's reference: a case study that keeps its words and its
   pictures to one centred measure, easier to follow than work spread wall
   to wall). Every section's head, its words and its tiles share the
   column's two edges, so the eye travels down one line instead of across
   the whole band and back. Nothing steps out of it, not the rows read
   across, not the pieces that are software to be used (PantryPal's
   running app, Vicino's component browser), not the windows that open
   the real files; only the opening tile is wider, the whole window.
   (Before the column, everything ran the full band between the gutters,
   the words held to 21em and set to the left of it; then the work ran
   wider than the words, and a few pieces wider still.)
   Each section is a size container, named "lane" as the page's main was
   (@container lane): every piece that lays itself out by how much room it
   has asks the column it stands in, which is narrower than the lane at
   every size of window but the smallest. (When they asked the lane, a
   piece in a 640 column laid itself out for a lane of 1400, and the five
   results stood five across at a fifth of the column each.) The main is
   still a container, for what stands outside the sections. */
.cs-main {
  container: lane / inline-size;
  /* Nothing in the story widens the page. The main runs from the window's
     left edge to its right (the opening tile is exactly that wide), so
     this cuts only what pokes past the window: on a
     phone, PantryPal's rubber stamps, turned on sheets as wide as the
     column, stood 2px past its edge, and 20px while they came down too
     big, and the page could be pushed sideways under a thumb. (A clip and
     not a hidden: it makes no scroll box, so the rail still sticks to the
     window.) */
  overflow-x: clip;
  padding: 0 var(--main-pad-r, var(--gutter-r)) 0 var(--lane-l, var(--gutter-l));
  font-size: var(--t-body);
  line-height: var(--lh-body);
  letter-spacing: var(--track-body);
}
.cs-main > * { max-width: var(--col); margin-inline: auto; }
.cs-main > :is(.cs-sec, .cs-end) { container: lane / inline-size; }
/* A band is the one moment on a page that is the work's own world rather
   than the page's (the running app, in PantryPal's kitchen), on a surface
   of its own, in the column as everything else is. (It ran the window's
   whole width, edge to edge, until the story kept to the lane, where it
   slid up behind the masthead's buttons; then the stage's.) */
.cs-sec {
  --sec-pad: var(--air-chapter);
  padding-top: var(--sec-pad);
  /* a section reached by its link (the rail, the story map) has its
     opener stand just under the masthead, the air above it scrolled away */
  scroll-margin-top: calc(var(--cs-top) + 24 * var(--u) - var(--sec-pad));
}
/* a part of a chapter follows on a good deal closer than a chapter does:
   under half as far, so a chapter's parts stand together as one block */
.cs-sec.is-part { --sec-pad: var(--air-part); }
.cs-sec:last-child { padding-bottom: calc(120 * var(--u)); }

/* ---- a chapter's opener ----
   Every chapter of a story opens the same way, so the eye learns where one
   begins: its number at the left end of a hairline and when it happened at
   the right, then its title, big, and what it is about, a step quieter
   under it. The hairline draws itself out from the number as the opener
   rises in. The number is each case's own (below, "the chapters' numbers");
   the chapters that are not part of the dated story, the brief before it
   and the outcome after, carry a word in its place.
   (A section's head was two lines in the one size, its name in the ink and
   what it was about under it, the way Home's name is; at 36 against 36 the
   words under a head read as its continuation, and nothing told a new part
   of the story from the next paragraph of the last.) */
.cs-chapter {
  display: grid;
  margin-bottom: var(--air-head);
}
/* a head that opens straight onto the work, with no words between, stands
   as far off it as words would */
:is(.cs-chapter, .cs-part) + :not(.cs-text, .cs-lead) { margin-top: var(--air-work); }
.cs-chapter-top {
  display: flex;
  align-items: center;
  gap: calc(18 * var(--u));
  margin-bottom: calc(18 * var(--u));
}
.cs-chapter-rule {
  flex: 1;
  height: 1px;
  background: color-mix(in oklab, var(--deep) 22%, transparent);
  transform-origin: 0 50%;
}
html.rises .cs-chapter:not(.is-risen) .cs-chapter-rule { scale: 0 1; }
.cs-chapter.is-risen .cs-chapter-rule { transition: scale 1.1s var(--ease-rise) 0.15s; }
.cs-chapter-when, .cs-eyebrow {
  font-size: var(--t-micro);
  line-height: 1.3;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  text-wrap: balance;
}
/* an address or a file's path is set as one, in its own lower case and
   untracked, as the guide's caption sets its file: in small capitals the
   review's 42 letters ran out of their half of the tile and broke at a
   hyphen, "PULSE-ONBOARDING-" over the rest; now it breaks, if it must,
   only before its ".vercel.app" */
.cs-eyebrow.is-url { text-transform: none; letter-spacing: 0; }
/* the date stands on its one line at the hairline's far end; a label on a
   tile can take two, since a tile in a narrow lane is narrower than it */
.cs-chapter-when { white-space: nowrap; }
.cs-chapter-title {
  font-size: var(--t-display);
  font-weight: 400;
  line-height: 1;
  letter-spacing: var(--track-display);
  color: var(--ink);
  text-wrap: balance;
}
.cs-chapter-deck {
  margin-top: calc(8 * var(--u));
  font-size: var(--t-lead);
  line-height: 1.25;
  letter-spacing: var(--track-lead);
  color: var(--ink-3);
  text-wrap: balance;
}

/* A part of a chapter is told under a smaller head: its number within the
   chapter (1.2 is the chapter's second part) on a short hairline of its
   own, its name, and what it is about, one over another on the reading
   column's left edge, the edge its words and its tiles stand on. (The
   number hung out to the left of the name, so the name started 62 in from
   the words under it and the column's edge went in and out again down
   every head.) */
.cs-part {
  display: grid;
  margin-bottom: var(--air-part-head);
}
.cs-part-num {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  margin-bottom: calc(8 * var(--u));
  font-size: var(--t-small);
  line-height: 1;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.cs-part-num::after {
  content: '';
  width: calc(48 * var(--u));
  height: 1px;
  background: color-mix(in oklab, var(--accent) 35%, transparent);
}
.cs-part h3 {
  font-size: var(--t-title);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}
.cs-part > p:not(.cs-text) {
  margin-top: calc(6 * var(--u));
  font-size: var(--t-name);
  line-height: 1.3;
  letter-spacing: -0.012em;
  color: var(--ink-3);
  text-wrap: balance;
}

/* ---- a head beside its words ----
   A chapter's words, and a part's, stand in its head (the pages put them
   there, as the head's last child): under its name where the column is
   narrow, and beside it where the column is wide, the name and what it is
   about on the left and the words on the right, so the head fills the
   column's width as the work under it does, and the words keep to a
   reading measure without stopping short of the column's right edge. The
   chapter's number and its hairline run over both. Everything else in a
   section that stands two things side by side, a quote beside the words
   about it, the people beside the question, a caption under the work,
   keeps to the same line between the two (below, "the same split"), so
   one line runs down the whole page. (The words were the head's next
   sibling, under it, until October 2026; at the lane's whole width their
   lines would have run to a hundred and thirty letters.) */
.cs-chapter > .cs-text { margin-top: var(--air-head); }
.cs-part > .cs-text { margin-top: var(--air-part-head); }
@container lane (min-width: 660px) {
  /* (a head with nothing beside its name, Problem's or Results', keeps the
     whole width, so its deck is not broken early beside an empty column) */
  :is(.cs-chapter, .cs-part):has(> .cs-text) {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    /* the deck's row takes whatever the words need beyond the name's, so
       the deck stays under the name however long the words run */
    grid-template-rows: auto auto 1fr;
    column-gap: var(--split-gap);
  }
  .cs-chapter > .cs-chapter-top, .cs-part > .cs-part-num { grid-column: 1 / -1; }
  :is(.cs-chapter, .cs-part):has(> .cs-text) > :is(.cs-chapter-title, h3) { grid-column: 1; grid-row: 2; }
  :is(.cs-chapter, .cs-part):has(> .cs-text) > :is(.cs-chapter-deck, p:not(.cs-text)) { grid-column: 1; grid-row: 3; align-self: start; }
  :is(.cs-chapter, .cs-part) > .cs-text { grid-column: 2; grid-row: 2 / span 2; align-self: start; max-width: none; margin-top: 0; }
  /* the same split: the pieces that stand two things side by side, and
     the captions, which stand where the words do */
  .cs-sec > .cs-cap-ink { max-width: none; margin-left: calc((100% - var(--split-gap)) * 5 / 12 + var(--split-gap)); }
}

/* Words on the paper, set to the reading measure: the quieter ink, with
   the phrases that carry the meaning in the page's own. At these sizes the
   quiet words are the small print's ink (4.9:1), not the 36's lighter one,
   which is only allowed at 24 and up. */
.cs-text {
  max-width: var(--measure);
  color: var(--ink-3);
  text-wrap: pretty;
}
.cs-text p + p { margin-top: 0.8em; }
.cs-text strong, .cs-lessons strong, .cs-note strong { font-weight: inherit; color: var(--ink); }
.cs-text a { color: var(--ink); text-decoration: underline; text-decoration-thickness: 0.07em; text-underline-offset: 0.14em; text-decoration-color: color-mix(in oklab, var(--accent) 40%, transparent); }
/* a chapter's first sentence, a size up, where the story's thread is */
.cs-lead {
  max-width: calc(760 * var(--u));
  font-size: var(--t-lead);
  line-height: 1.32;
  letter-spacing: var(--track-lead);
  color: var(--ink-3);
  text-wrap: pretty;
}
.cs-lead strong { font-weight: inherit; color: var(--ink); }

.cs-small {
  font-size: var(--t-small);
  line-height: 1.4;
  letter-spacing: 0;
}

/* ---- layouts ---- */
.cs-grid { display: grid; gap: var(--gap); }
.cs-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cs-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* The steps between the pieces of a section (above, "the rhythm"): a
   piece after another of the same moment, at the grid's own gap, so a
   stack of tiles reads as one group as a row of them does; the work after
   the words that lead into it; and a line of words under a picture, which
   is the picture's own, closer still. (They were 40, 64, and the 40 again
   for a caption, which left a picture's words nearer the next piece than
   the picture they were about.) */
.cs-after { margin-top: var(--air-stack); }
.cs-after-lg { margin-top: var(--air-work); }
.cs-cap-ink.cs-after { margin-top: var(--air-cap); }

/* ---- the hero's pieces ----
   The words and the work of a case's own tile, shared by the opening tile
   and the next case's tile at the page's foot, which is drawn the same way
   at a smaller size (below, "the next case"). The opening tile lays them
   out its own way (below, "the hero"). */
.cs-hero-words {
  position: absolute;
  z-index: 2;
  left: calc(40 * var(--u));
  top: calc(40 * var(--u));
  bottom: calc(40 * var(--u));
  width: calc(330 * var(--u));
  display: flex;
  flex-direction: column;
}
.cs-hero-words .ico { --ico: calc(96 * var(--u)); }
/* the name at a headline's size, what it is under it at the lead's, and
   then what Tigo was and when, small, as the Work tile says it */
.cs-hero-name {
  margin-top: calc(30 * var(--u));
  font-size: calc(54 * var(--u));
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.034em;
  color: var(--pastel-ink);
  text-wrap: balance;
}
.cs-hero-sub {
  margin-top: calc(12 * var(--u));
  font-size: var(--t-lead);
  line-height: 1.25;
  letter-spacing: var(--track-lead);
  color: var(--tile-ink);
  text-wrap: balance;
}
.cs-hero-art {
  position: absolute;
  inset: 0 0 0 calc(420 * var(--u));
}
.cs-hero-art .cs-window {
  position: absolute;
  left: 0;
  top: calc(40 * var(--u));
  width: calc(100% + 58 * var(--u));
}
/* ---- the hero: the Work tile, grown to the whole window ----
   The page opens on its case's Work tile grown to fill the window, edge
   to edge, from the very top to the foot: the one thing on the page that
   is not kept to the lane (Tigo wanted the title card to take the whole
   screen). The back button and the menu square stand over its paper, and
   everything it holds stands clear of them, below the masthead's row. Its
   foot is rounded, as a tile's corners are, so it reads as the tile itself
   grown to the window rather than a band laid across it.
   The tile is a size container (hero), so what it holds is measured off
   the window it fills. In a landscape window its words stand in a column
   on the left, on the back button's axis, as one group a steady step
   apart, standing a little above the middle of the room beside the work:
   who it is (the icon, the name, what it is), then the label a gallery
   would hang beside it (the role and when, dressed in the case's own
   product), then the ways in, one of them filled with the case's own deep
   colour as the one to press first. (For a day they stood in two parts,
   who it is at the top and the label at the foot, held apart by whatever
   room the window left, which on a tall window was a gulf between a line
   and the label it led to.)
   The work stands to the right of them, from under the menu square's foot,
   and runs off the tile's foot as it comes up out of the Work tile's:
   Canvas runs off the tile's right edge too, a board going on past the
   window; the website and the phones end at the square's own right edge.
   Canvas and the website are ways in as well (.cs-hero-go): pointed at, a
   chip trails the pointer across them and says where they go, and the
   phones, pressed, come forward (js/case.js). In a window too narrow or
   too tall for that, the words stand across the top and the work fills
   everything under them. (It stood in the band from under the masthead
   to 44 above the window's foot, 1192 at most and rounded all round; then
   for a while in the lane, a poster when the lane was narrow; then all of
   it ran off the right edge, until the website's own buttons were found
   cut in half there.) */
.cs-main > .cs-hero {
  width: 100vw;
  max-width: none;
  margin-left: calc(-1 * var(--lane-l, var(--gutter-l)));
  margin-right: 0;
}
.cs-hero { scroll-margin-top: 0; }
.cs-hero-tile {
  /* where the words begin, under the masthead's row; the work begins at
     the row's foot, a little higher, under the square */
  --hero-top: calc(var(--cs-top) + 20 * var(--u));
  --hero-foot: calc(52 * var(--u));
  /* how far the work runs past the foot */
  --hero-bleed: calc(14 * var(--u));
  /* the words' column and the room after it; these are read where they
     are used, inside the tile, so cqw is the tile's width */
  --words-w: min(34cqw, calc(520 * var(--u)));
  --words-gap: min(5cqw, calc(72 * var(--u)));
  --art-l: calc(var(--gutter-l) + var(--words-w) + var(--words-gap));
  position: relative;
  /* a column, for the poster below, where the words and the work stand in
     the flow; in a landscape window both are placed, and it is nothing.
     (It is set here rather than in the poster's query because the tile is
     the container that query asks, and a query never styles its own
     container.) */
  display: flex;
  flex-direction: column;
  view-transition-name: var(--vt, none);
  container: hero / size;
  height: 100vh;
  height: 100svh;
  min-height: calc(480 * var(--u));
  overflow: hidden;
  isolation: isolate;
  border-radius: 0 0 calc(44 * var(--u)) calc(44 * var(--u));
}
.cs-hero-tile .cs-hero-words {
  left: var(--gutter-l);
  top: var(--hero-top);
  bottom: var(--hero-foot);
  width: var(--words-w);
}
/* The room the group does not fill is shared out over and under it, two
   parts to three, so it stands a little above the measured middle, where
   the eye puts the middle; in a window with no room to spare, the group
   simply starts under the masthead's row. */
.cs-hero-tile .cs-hero-words::before,
.cs-hero-tile .cs-hero-words::after { content: ''; flex: 2 1 0; }
.cs-hero-tile .cs-hero-words::after { flex-grow: 3; }
.cs-hero-tile .cs-hero-words .ico { --ico: calc(104 * var(--u)); }
.cs-hero-tile .cs-hero-name {
  margin-top: calc(34 * var(--u));
  font-size: min(calc(84 * var(--u)), 6cqw);
  line-height: 0.98;
  letter-spacing: -0.04em;
}
/* Next Level's whole name is three words longer than the others, and at
   their size it stood in three lines; at this one it is two, the company's
   name and then what it does */
.cs[data-case='nextlevel'] .cs-hero-tile .cs-hero-name { font-size: min(calc(66 * var(--u)), 4.5cqw); line-height: 1.02; }
.cs-hero-tile .cs-hero-sub {
  margin-top: calc(16 * var(--u));
  font-size: max(19px, calc(28 * var(--u)));
}

/* ---- the label ----
   What Tigo was and when, each under its own small caps, over a hairline
   in the tile's own colour, standing in the middle of the room between
   what it is and the ways in, the same step from each as the eye measures
   it: the step over it is counted from the line the words above stand on,
   not from the foot of their line, which is a further 7 down, so it is 6
   shorter than the step under it. (It stood nearer the ways in, a wider
   step under the words than over the pills, and read as the pills'
   caption rather than a piece of its own.) Each case then dresses it
   in its own product's hand, as the chapters' numbers are dressed (below,
   "the chapters' numbers"): Vicino's is a node on Canvas's board, its
   output wired across into the board itself; PantryPal's is the app's own
   Kitchen Pass, its sign-up card; Next Level's stands on a line of the
   brand book's construction, ticked like a ruler. */
.cs-hero-label { margin-top: calc(30 * var(--u)); }
.cs-hero-facts {
  display: flex;
  flex-wrap: wrap;
  gap: calc(10 * var(--u)) calc(44 * var(--u));
  padding-top: calc(20 * var(--u));
  border-top: 1px solid color-mix(in oklab, var(--deep) 18%, transparent);
}
.cs-hero-facts dt {
  font-size: var(--t-micro);
  line-height: 1.3;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tile-ink-2);
}
.cs-hero-facts dd {
  margin-top: calc(6 * var(--u));
  font-size: max(15px, calc(17.5 * var(--u)));
  line-height: 1.3;
  letter-spacing: -0.012em;
  font-variant-numeric: tabular-nums;
  color: var(--pastel-ink);
  white-space: nowrap;
}

/* Vicino: a node, as Canvas draws one beside it: a white card with its
   header (the text node's glyph, its name, the done chip a node wears
   after a run) and the label in its inset well, its output port on its
   right edge, and the wire leaving it straight across the gap into the
   board's own edge, where an input port takes it, in the colour words
   travel the board in. A spark runs the wire every few seconds, as it
   runs the chapters' wires, and runs it fast while the board is running. */
.cs[data-case='vicino'] .cs-hero-label {
  --port: #9b9cf1;
  display: flex;
  align-items: center;
  /* out across the gap to the board's edge */
  margin-right: calc(-1 * var(--words-gap));
}
.cs-hero-node {
  position: relative;
  flex: none;
  padding: 0 calc(10 * var(--u)) calc(10 * var(--u));
  border-radius: calc(18 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.075),
    inset 0 1px 0 rgb(255 255 255 / 0.88),
    0 calc(16 * var(--u)) calc(32 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 55%, transparent);
}
.cs-hero-node-head {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  height: calc(44 * var(--u));
  padding: 0 calc(4 * var(--u)) 0 calc(6 * var(--u));
  font-size: max(13px, calc(14.5 * var(--u)));
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #1d1d1f;
}
.cs-hero-node-head > svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); }
.cs-hero-node-head i {
  display: grid;
  place-items: center;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  margin-left: auto;
  border-radius: calc(9 * var(--u));
  background: #f0fdff;
  color: #0d7685;
}
.cs-hero-node-head i svg { width: calc(12 * var(--u)); height: calc(12 * var(--u)); }
.cs[data-case='vicino'] .cs-hero-facts {
  flex-wrap: nowrap;
  gap: calc(30 * var(--u));
  padding: calc(12 * var(--u)) calc(16 * var(--u)) calc(13 * var(--u));
  border: 0;
  border-radius: calc(12 * var(--u));
  background: #f7f9f9;
}
.cs-hero-node::after,
.cs-hero-wire::after {
  content: '';
  position: absolute;
  right: calc(-4 * var(--u));
  top: 50%;
  width: calc(8 * var(--u));
  height: calc(22 * var(--u));
  translate: 0 -50%;
  border-radius: calc(4 * var(--u));
  background: var(--port);
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
}
.cs[data-case='vicino'] .cs-hero-facts dt { color: #5f6369; }
.cs[data-case='vicino'] .cs-hero-facts dd { margin-top: calc(4 * var(--u)); font-weight: 500; color: #1d1d1f; }
.cs-hero-wire {
  position: relative;
  flex: 1;
  min-width: calc(24 * var(--u));
  height: calc(2 * var(--u));
  margin-left: calc(4 * var(--u));
  border-radius: 99px;
  background: color-mix(in oklab, var(--port) 70%, #fff);
}
.cs-hero-wire i {
  position: absolute;
  left: 0;
  top: 50%;
  width: calc(9 * var(--u));
  height: calc(9 * var(--u));
  translate: 0 -50%;
  border-radius: 50%;
  background: var(--port);
  box-shadow: 0 0 0 calc(4 * var(--u)) color-mix(in oklab, var(--port) 25%, transparent);
  opacity: 0;
  animation: cs-wire-spark 3.6s var(--ease-draw) 1.4s infinite;
}
.cs-hero-tile:has([data-run].is-running) .cs-hero-wire i { animation-duration: 0.9s; animation-delay: 0s; }

/* PantryPal: the app's Kitchen Pass, as its sign-up card draws it, set
   down a little askew as the app's stickers are, and straightened when it
   is pointed at: the coral band with its ring and the chef's hat, the
   label in the app's prose face on the white, and the pass's number on
   its butter foot, all ringed and shadowed hard in the app's ink. */
.cs-pass {
  align-self: flex-start;
  width: max-content;
  max-width: 100%;
  overflow: hidden;
  border-radius: calc(18 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 calc(2.5 * var(--u)) var(--mark),
    0 calc(5 * var(--u)) 0 calc(2.5 * var(--u)) var(--mark);
  /* turned about its middle, so it leans as far over the words as under
     the ways in */
  rotate: -1.6deg;
  transition: rotate var(--t-pop) var(--spring-pop), translate var(--t-pop) var(--spring-pop);
}
@media (hover: hover) {
  .cs-pass:hover { rotate: 0deg; translate: 0 calc(-3 * var(--u)); }
}
.cs-pass-head {
  display: flex;
  align-items: center;
  gap: calc(10 * var(--u));
  height: calc(42 * var(--u));
  padding: 0 calc(14 * var(--u));
  border-bottom: calc(2.5 * var(--u)) solid var(--mark);
  background: #ff7e7d url(../assets/case/pantrypal/app/hat.webp) no-repeat right calc(12 * var(--u)) center / auto calc(30 * var(--u));
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-size: calc(19 * var(--u));
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
  -webkit-text-stroke: calc(4 * var(--u)) var(--mark);
  paint-order: stroke fill;
}
.cs-pass-head i {
  flex: none;
  width: calc(18 * var(--u));
  height: calc(18 * var(--u));
  border-radius: 50%;
  background: #fff;
  box-shadow: inset 0 0 0 calc(2.5 * var(--u)) var(--mark);
}
.cs-pass .cs-hero-facts { gap: calc(8 * var(--u)) calc(34 * var(--u)); padding: calc(14 * var(--u)) calc(18 * var(--u)) calc(16 * var(--u)); border-top: 0; }
.cs-pass .cs-hero-facts dt {
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-size: max(11px, calc(12 * var(--u)));
  letter-spacing: 0.05em;
  color: rgb(0 0 0 / 0.55);
}
.cs-pass .cs-hero-facts dd {
  margin-top: calc(3 * var(--u));
  font-family: 'PP Faustina', Georgia, serif;
  font-weight: 600;
  font-size: max(16px, calc(19 * var(--u)));
  letter-spacing: 0;
  color: var(--mark);
}
.cs-pass-foot {
  display: flex;
  align-items: center;
  height: calc(32 * var(--u));
  padding: 0 calc(18 * var(--u));
  border-top: calc(2.5 * var(--u)) solid var(--mark);
  background: #ffd67e;
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-size: calc(13 * var(--u));
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--mark);
}

/* Next Level: the brand book's construction. The icon is drawn over it as
   the badge is in the book, a hairline circle of the badge's blue round it
   and the badge's second ring arcing round its right side in the navy, and
   the lines through its centre running on past it; the label's hairline is
   a construction line, ticked like a ruler, a long tick every fourth. */
/* (it stands in the column's flow just before the icon, as tall as the
   icon and taken back again by its own margin, so it is always exactly
   where the icon is, wherever the group stands) */
.cs-hero-plan {
  --plan: calc(104 * var(--u));
  position: relative;
  z-index: -1;
  flex: none;
  width: var(--plan);
  height: var(--plan);
  margin-bottom: calc(-1 * var(--plan));
  pointer-events: none;
}
.cs-hero-plan::before,
.cs-hero-plan::after {
  content: '';
  position: absolute;
  border-radius: 50%;
}
.cs-hero-plan::before { inset: calc(var(--plan) * -0.22); border: 1px solid rgb(4 149 235 / 0.45); }
.cs-hero-plan::after {
  inset: calc(var(--plan) * -0.38);
  border: calc(1.5 * var(--u)) solid transparent;
  border-right-color: #0d2a4d;
  rotate: -24deg;
  opacity: 0.7;
}
.cs-hero-plan i::before,
.cs-hero-plan i::after {
  content: '';
  position: absolute;
  background: rgb(4 149 235 / 0.4);
}
/* across, from before the rings to past the name's width, fading */
.cs-hero-plan i::before {
  left: calc(var(--plan) * -0.5);
  top: 50%;
  width: calc(var(--words-w) + var(--plan) * 0.5);
  height: 1px;
  -webkit-mask: linear-gradient(90deg, transparent, #000 10%, #000 55%, transparent);
  mask: linear-gradient(90deg, transparent, #000 10%, #000 55%, transparent);
}
/* and down, from above the rings to just short of the name */
.cs-hero-plan i::after {
  left: 50%;
  top: calc(var(--plan) * -0.42);
  width: 1px;
  height: calc(var(--plan) * 1.67);
  -webkit-mask: linear-gradient(transparent, #000 15%, #000 80%, transparent);
  mask: linear-gradient(transparent, #000 15%, #000 80%, transparent);
}
.cs[data-case='nextlevel'] .cs-hero-facts {
  padding-top: calc(22 * var(--u));
  border-top: 0;
  background:
    linear-gradient(#0495eb, #0495eb) 0 0 / 100% 1px no-repeat,
    repeating-linear-gradient(90deg, rgb(4 149 235 / 0.6) 0 1px, transparent 1px calc(48 * var(--u))) 0 0 / 100% calc(10 * var(--u)) no-repeat,
    repeating-linear-gradient(90deg, rgb(4 149 235 / 0.4) 0 1px, transparent 1px calc(12 * var(--u))) 0 0 / 100% calc(5 * var(--u)) no-repeat;
}
.cs[data-case='nextlevel'] .cs-hero-facts dt { color: #0b6db0; }
.cs[data-case='nextlevel'] .cs-hero-facts dd { font-weight: 500; color: #0d2a4d; }

/* The paper each case's words stand on, under the words only and fading
   out before the work: Canvas's own dot grid, so the board runs on under
   the words, and the badge's blue grid, the brand book's plate, which the
   flight plan in the rail is drawn on too. PantryPal's words stand on the
   tile alone, beside the pass. */
.cs[data-case='vicino'] .cs-hero-tile::after,
.cs[data-case='nextlevel'] .cs-hero-tile::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  -webkit-mask: radial-gradient(ellipse 40% 62% at 15% 58%, #000 25%, transparent);
  mask: radial-gradient(ellipse 40% 62% at 15% 58%, #000 25%, transparent);
}
.cs[data-case='vicino'] .cs-hero-tile::after {
  background: radial-gradient(circle, color-mix(in oklab, var(--deep) 26%, transparent) calc(1.1 * var(--u)), transparent calc(1.6 * var(--u))) calc(var(--gutter-l) - 11 * var(--u)) 0 / calc(22 * var(--u)) calc(22 * var(--u));
}
.cs[data-case='nextlevel'] .cs-hero-tile::after {
  background:
    linear-gradient(rgb(4 149 235 / 0.1) 1px, transparent 1px) 0 0 / calc(24 * var(--u)) calc(24 * var(--u)),
    linear-gradient(90deg, rgb(4 149 235 / 0.1) 1px, transparent 1px) var(--gutter-l) 0 / calc(24 * var(--u)) calc(24 * var(--u));
}

/* the ways in: the one to press first filled with the case's deep colour,
   the next in the frosted pill, and a way out to the product's own site
   quietest of all, its words alone */
.cs-hero-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(8 * var(--u));
  margin-top: calc(36 * var(--u));
}
/* The pass's ink ring stands 2.5 outside it and its hard shadow 7.5 under
   it, so the step to the ways in is counted from the shadow's foot, and the
   pass still stands the same step from each, as the eye measures it */
.cs-pass + .cs-hero-links { margin-top: calc(41 * var(--u)); }
.cs-hero-links .cs-pill {
  height: max(40px, calc(44 * var(--u)));
  gap: calc(8 * var(--u));
  padding: 0 calc(16 * var(--u)) 0 calc(20 * var(--u));
  font-size: max(14px, calc(15.5 * var(--u)));
  letter-spacing: -0.006em;
}
/* a pill that starts on its icon is padded the other way round */
.cs-hero-links .cs-pill[data-run] { padding: 0 calc(20 * var(--u)) 0 calc(16 * var(--u)); }
.cs-hero-links .cs-pill[data-run] svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); }
.cs-pill.is-primary {
  background: var(--deep);
  color: #fff;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.14),
    0 1px 2px color-mix(in oklab, var(--deep) 40%, transparent),
    0 calc(10 * var(--u)) calc(22 * var(--u)) calc(-10 * var(--u)) color-mix(in oklab, var(--deep) 75%, transparent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.cs-pill.is-quiet {
  margin-left: calc(8 * var(--u));
  padding: 0 !important;
  background: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  color: var(--tile-ink);
}
@media (hover: hover) {
  .cs-pill.is-primary:hover { background: color-mix(in oklab, var(--deep) 86%, #000); }
  .cs-pill.is-quiet:hover { background: transparent; color: var(--pastel-ink); }
  /* an arrow down the page leans down, the run's triangle forward */
  .cs-pill[href^='#']:hover svg { translate: 0 calc(2 * var(--u)); }
  .cs-pill[data-run]:hover svg { translate: calc(1.5 * var(--u)) 0; }
}
.cs-pill:focus-visible, .cs-badge:focus-visible { outline: 2px solid var(--deep); outline-offset: 3px; }

/* Apple's badge, at the pills' height, and otherwise exactly as Apple
   draws it: nothing laid over it, no shadow, no colour of the case's */
.cs-badge {
  position: relative;
  z-index: 3;
  display: block;
  flex: none;
  height: max(40px, calc(44 * var(--u)));
  border-radius: calc(max(40px, calc(44 * var(--u))) * 0.22);
  -webkit-tap-highlight-color: transparent;
  transition: scale var(--t-pop) var(--spring-pop);
}
.cs-badge img { display: block; width: auto; height: 100%; }
.cs-badge:active { scale: 0.96; transition-duration: 90ms; }

/* the work, from under the square's foot to its right edge */
.cs-hero-tile .cs-hero-art {
  display: block;
  inset: var(--cs-top) var(--gutter-r) 0 var(--art-l);
  -webkit-tap-highlight-color: transparent;
}
/* A window of the work (the website), as wide as the room and at least
   tall enough to run off the foot: the website stands at the window's top
   on its own white, its foot fading into it, so it reads as the page going
   on. */
.cs-hero-tile .cs-hero-art .cs-window {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: max(calc(100% + var(--hero-bleed)), calc((100cqw - var(--art-l) - var(--gutter-r)) / 1.2571));
  aspect-ratio: auto;
}
.cs-hero-tile .cs-hero-art .cs-window > img {
  -webkit-mask: linear-gradient(#000 82%, transparent);
  mask: linear-gradient(#000 82%, transparent);
}
/* Canvas runs off the tile's right edge as well as its foot, as it does on
   the Work tile, so what is in view is some of a board that goes on past
   the window: as wide as it needs to be to run off both, whatever shape
   the window is (the board is 1100 by 875) */
.cs[data-case='vicino'] .cs-hero-tile .cs-hero-art { right: 0; }
.cs[data-case='vicino'] .cs-hero-tile .cs-hero-art .cs-window {
  width: max(calc(100% + 40 * var(--u)), calc((100cqh - var(--cs-top) + 12 * var(--u)) * 1.2571));
  height: auto;
  aspect-ratio: var(--live-w) / var(--live-h);
}
.cs-hero-tile .cs-live { background-color: #eff3f4; }

/* PantryPal: the app on three phones, one in front and the other two
   either side of it behind, in the order they are used. Pressing one at
   the back brings it to the front, the one in front stepping back to its
   side and the third going round behind them both (js/case.js, the fan):
   each phone is placed by its slot alone, so the move between slots is
   one transition. They are as large as the room allows with the front one
   standing clear of the foot. */
.cs-hero-tile .cs-hero-phones {
  --phone: min(calc((100cqw - var(--art-l) - var(--gutter-r)) / 2.12), calc((100cqh - var(--cs-top) - var(--hero-foot)) / 2.045));
  --side-x: 0.63;
  --side-y: 0.2;
  --side-s: 0.86;
}
.cs-fan-phone {
  position: absolute;
  left: calc(50% - var(--phone) / 2);
  top: 0;
  width: var(--phone);
  padding: 0;
  border: 0;
  border-radius: calc(var(--phone) * 0.16);
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transform-origin: 50% 0;
  -webkit-tap-highlight-color: transparent;
  transition:
    transform var(--t-settle) var(--spring-settle),
    translate 0.9s var(--ease-rise);
}
.cs-fan-phone img { display: block; width: 100%; height: auto; }
.cs-fan-phone[data-slot='front'] { z-index: 3; cursor: default; }
.cs-fan-phone[data-slot='left'],
.cs-fan-phone[data-slot='right'] { z-index: 1; }
/* the one stepping back stays over the one going round behind */
.cs-fan-phone.was-front { z-index: 2; }
.cs-fan-phone[data-slot='left'] { transform: translate(calc(-1 * var(--side-x) * var(--phone)), calc(var(--side-y) * var(--phone))) scale(var(--side-s)); }
.cs-fan-phone[data-slot='right'] { transform: translate(calc(var(--side-x) * var(--phone)), calc(var(--side-y) * var(--phone))) scale(var(--side-s)); }
.cs-fan-phone:focus-visible { outline: 2px solid var(--deep); outline-offset: calc(4 * var(--u)); }
@media (hover: hover) {
  .cs-hero-tile .cs-hero-art > :not(.cs-hero-cue, .cs-fan-phone) { transition: translate 0.9s var(--ease-rise); }
  .cs-hero-tile:hover .cs-hero-art > :not(.cs-hero-cue) { translate: 0 calc(-8 * var(--u)); }
  .cs-hero-tile:hover .cs-fan-phone[data-slot='left'] { transition-delay: 0s, 60ms; }
  .cs-hero-tile:hover .cs-fan-phone[data-slot='right'] { transition-delay: 0s, 120ms; }
  /* one at the back, pointed at, rises to be picked */
  .cs-hero-tile .cs-hero-phones .cs-fan-phone:not([data-slot='front']):hover { translate: 0 calc(-18 * var(--u)); transition-delay: 0s; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-fan-phone { transition: none; }
}

/* The chip that trails the pointer over the work (js/case.js moves it):
   the primary pill's deep colour, frosted, a little behind the hand. It
   comes up as the pointer comes onto the work and goes as it leaves; a
   phone, which cannot point, has the pills above instead. */
.cs-hero-cue {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: max(34px, calc(40 * var(--u)));
  padding: 0 calc(13 * var(--u)) 0 calc(16 * var(--u));
  border-radius: 999px;
  background: color-mix(in oklab, var(--deep) 88%, transparent);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.16),
    0 calc(12 * var(--u)) calc(28 * var(--u)) calc(-12 * var(--u)) color-mix(in oklab, var(--deep) 80%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  font-size: var(--t-small);
  line-height: 1;
  color: #fff;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  scale: 0.86;
  transform-origin: 0 0;
  transition: opacity 0.18s ease, scale var(--t-out) var(--spring-out);
}
.cs-hero-cue svg { width: 1.1em; height: 1.1em; }
.cs-hero-go.is-pointed .cs-hero-cue {
  opacity: 1;
  scale: 1;
  transition: opacity 0.16s ease, scale var(--t-pop) var(--spring-pop);
}
@media (hover: none) {
  .cs-hero-cue { display: none; }
}
/* where the column is too narrow for all three ways in, the quiet one
   goes under the others, and starts on the column's edge */
@container hero (max-width: 1100px) {
  .cs-pill.is-quiet { margin-left: 0; }
}
/* A short window for its width has less room down the column than the
   words and the label take at their full size: the icon comes down a size,
   the space round the name closes up, and the pass loses its foot. Short
   is under 770 frame pixels of height, which is any window wider than 5:3
   (--u follows the width there, or the height at 700), except a big one
   where --u has reached its ceiling and the frame pixels are counted off
   the height alone, 962 and up. */
@container hero (min-aspect-ratio: 5 / 3) and (max-height: 961px) {
  .cs-hero-tile .cs-hero-words .ico { --ico: calc(84 * var(--u)); }
  .cs-hero-tile .cs-hero-plan { --plan: calc(84 * var(--u)); }
  .cs-hero-tile .cs-hero-name { margin-top: calc(24 * var(--u)); }
  .cs-hero-tile .cs-hero-label { margin-top: calc(23 * var(--u)); }
  .cs-hero-tile .cs-hero-links { margin-top: calc(28 * var(--u)); }
  .cs-hero-tile .cs-pass + .cs-hero-links { margin-top: calc(33 * var(--u)); }
  .cs-pass-foot { display: none; }
}

/* the poster: the words across the top, the label and the ways in on one
   line under them, and the work filling the rest */
@container hero (max-width: 860px) or (max-aspect-ratio: 11 / 10) {
  .cs-hero-tile .cs-hero-words {
    position: relative;
    inset: auto;
    width: auto;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: 'ico name name' 'ico sub sub' 'label label links';
    align-items: start;
    column-gap: calc(28 * var(--u));
    padding: var(--hero-top) var(--gutter-r) 0 var(--gutter-l);
  }
  .cs-hero-tile .cs-hero-words .ico { grid-area: ico; --ico: calc(92 * var(--u)); }
  .cs-hero-tile .cs-hero-name { grid-area: name; margin-top: calc(-4 * var(--u)); font-size: min(calc(72 * var(--u)), 8.4cqw); }
  .cs[data-case='nextlevel'] .cs-hero-tile .cs-hero-name { font-size: min(calc(60 * var(--u)), 6.6cqw); }
  .cs-hero-tile .cs-hero-sub { grid-area: sub; margin: calc(10 * var(--u)) 0 0; }
  .cs-hero-tile .cs-hero-label { grid-area: label; align-self: end; margin: calc(32 * var(--u)) 0 0; }
  .cs-hero-tile .cs-hero-links {
    grid-area: links;
    align-self: end;
    justify-content: flex-end;
    margin-top: calc(32 * var(--u));
  }
  /* no gap to cross here: the node stands on its own, and the
     construction, whose lines would run through the name beside it, is
     left to the landscape window and the phone */
  .cs-hero-wire, .cs-hero-plan { display: none; }
  .cs-hero-tile .cs-hero-words::before,
  .cs-hero-tile .cs-hero-words::after { content: none; }
  .cs[data-case='vicino'] .cs-hero-label { margin-right: 0; }
  .cs-hero-node::after { display: none; }
  .cs[data-case='vicino'] .cs-hero-tile::after,
  .cs[data-case='nextlevel'] .cs-hero-tile::after {
    -webkit-mask: radial-gradient(ellipse 75% 28% at 25% 14%, #000 25%, transparent);
    mask: radial-gradient(ellipse 75% 28% at 25% 14%, #000 25%, transparent);
  }
  .cs-pass-foot { display: flex; }
  .cs-hero-tile .cs-hero-art {
    position: relative;
    inset: auto;
    flex: 1;
    min-height: 0;
    margin: calc(36 * var(--u)) var(--gutter-r) 0 var(--gutter-l);
  }
  .cs-hero-tile .cs-hero-art .cs-window { height: max(calc(100% + var(--hero-bleed)), calc((100cqw - var(--gutter-l) - var(--gutter-r)) / 1.2571)); }
  .cs[data-case='vicino'] .cs-hero-tile .cs-hero-art { margin-right: 0; }
  .cs[data-case='vicino'] .cs-hero-tile .cs-hero-art .cs-window { width: calc(100% + 40 * var(--u)); height: auto; }
  .cs-hero-tile .cs-hero-phones { --phone: min(calc((100cqw - var(--gutter-l) - var(--gutter-r)) / 2.12), 60cqh); }
}
/* and narrower again, a phone's: the words one over another, the ways in
   under them, and the three phones drawn closer together */
@container hero (max-width: 560px) {
  .cs-hero-tile .cs-hero-words {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'ico' 'name' 'sub' 'label' 'links';
    padding-top: var(--hero-top);
  }
  .cs-hero-tile .cs-hero-words .ico { --ico: 64px; }
  .cs-hero-tile .cs-hero-plan { --plan: 64px; display: block; position: absolute; margin: 0; left: var(--gutter-l); top: var(--hero-top); }
  .cs-hero-tile .cs-hero-plan i::before { width: calc(100cqw - 2 * var(--gutter-l)); }
  .cs-hero-tile .cs-hero-name { margin-top: 22px; font-size: min(46px, 11.5cqw); }
  .cs[data-case='nextlevel'] .cs-hero-tile .cs-hero-name { font-size: min(40px, 10cqw); }
  .cs-hero-tile .cs-hero-sub { font-size: 20px; }
  .cs-hero-tile .cs-hero-label { margin-top: 17px; }
  .cs-hero-tile .cs-hero-facts { gap: 8px 28px; }
  .cs-pass .cs-hero-facts dd { font-size: 16px; }
  .cs-hero-tile .cs-hero-links { justify-content: flex-start; margin-top: 22px; }
  .cs-hero-tile .cs-pass + .cs-hero-links { margin-top: 27px; }
  .cs-hero-tile .cs-hero-art { margin-top: 28px; }
  .cs-hero-tile .cs-hero-phones { --phone: calc((100cqw - var(--gutter-l) - var(--gutter-r)) / 1.86); --side-x: 0.52; --side-y: 0.14; --side-s: 0.82; }
}

/* ---- tiles ---- */
.cs-lit {
  background:
    radial-gradient(130% 75% at 0% 0%, color-mix(in oklab, var(--tint), #fff 70%), transparent 72%),
    linear-gradient(to bottom, color-mix(in oklab, var(--tint), #fff 38%), var(--tint) 62%);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent);
}
.cs-tile {
  position: relative;
  min-width: 0;
  padding: var(--pad);
  border-radius: var(--r-tile);
  overflow: hidden;
  isolation: isolate;
}
.cs-tile-name {
  font-size: var(--t-name);
  line-height: 1.2;
  letter-spacing: -0.014em;
  color: var(--pastel-ink);
}
.cs-tile-meta {
  font-size: var(--t-small);
  line-height: 1.42;
  letter-spacing: 0;
  color: var(--tile-ink);
  text-wrap: pretty;
}
.cs-tile-meta + .cs-tile-meta { color: var(--tile-ink-2); }
.cs-tile > * + * { margin-top: calc(14 * var(--u)); }
.cs-tile > .cs-tile-meta { margin-top: calc(4 * var(--u)); }
.cs-tile > .cs-well, .cs-tile > .cs-window { margin-top: calc(22 * var(--u)); }

/* A well is a place sunk into a tile, a shade deeper than it, for a
   picture that brings its own paper (a sketch, a logo, a wireframe). */
.cs-well {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: var(--r-well);
  background: #fff;
}
.cs-well::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 0 0 1px color-mix(in oklab, var(--deep) 12%, transparent),
    inset 0 calc(2 * var(--u)) calc(6 * var(--u)) color-mix(in oklab, var(--deep) 8%, transparent);
}
.cs-well > img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* A window is a screen of the work itself: the picture, its corners
   rounded and lifted on a shadow of the tile's colour, and nothing drawn
   round it. */
.cs-window {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--r-window);
  background: #fff;
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent),
    0 calc(2 * var(--u)) calc(4 * var(--u)) color-mix(in oklab, var(--deep) 8%, transparent),
    0 calc(28 * var(--u)) calc(56 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
}
.cs-window > img { display: block; width: 100%; height: auto; }

/* A document: a window that is the real file, and opens it in its own
   tab. Pointed at or focused, it lifts a little onto a deeper shadow and a
   frosted chip in its corner says what it opens; on a phone, which cannot
   point, the chip is there from the start. */
a.cs-doc {
  -webkit-tap-highlight-color: transparent;
  transition:
    translate var(--t-settle) var(--spring-settle),
    box-shadow 0.45s ease;
}
.cs-doc-open {
  position: absolute;
  top: calc(12 * var(--u));
  right: calc(12 * var(--u));
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: calc(4 * var(--u));
  height: calc(40 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(16 * var(--u));
  border-radius: 999px;
  background: rgb(255 255 255 / 0.82);
  box-shadow:
    inset 0 0 0 1px rgb(255 255 255 / 0.7),
    0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-6 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  font-size: var(--t-small);
  line-height: 1;
  letter-spacing: 0;
  color: var(--pastel-ink);
  white-space: nowrap;
  opacity: 0;
  translate: 0 calc(-6 * var(--u));
  scale: 0.96;
  transition:
    opacity 0.2s ease,
    translate var(--t-out) var(--spring-out),
    scale var(--t-out) var(--spring-out);
}
.cs-doc-open svg { width: calc(19.84 * var(--u)); height: calc(19.84 * var(--u)); }
/* the wide tiles' documents run off the tile's right edge, so there the
   chip stands in from the tile's edge, not the window's */
.cs-wide-art .cs-doc-open, .cs-wide-art.cs-doc .cs-doc-open { right: calc(24 * var(--u)); }
a.cs-doc:focus-visible { outline: 2px solid var(--deep); outline-offset: 3px; }
a.cs-doc:is(:hover, :focus-visible) .cs-doc-open {
  opacity: 1;
  translate: 0 0;
  scale: 1;
  transition:
    opacity 0.16s ease,
    translate var(--t-pop) var(--spring-pop),
    scale var(--t-pop) var(--spring-pop);
}
@media (hover: hover) {
  a.cs-doc:hover {
    translate: 0 calc(-4 * var(--u));
    box-shadow:
      0 0 0 1px color-mix(in oklab, var(--deep) 14%, transparent),
      0 calc(2 * var(--u)) calc(4 * var(--u)) color-mix(in oklab, var(--deep) 8%, transparent),
      0 calc(36 * var(--u)) calc(64 * var(--u)) calc(-20 * var(--u)) color-mix(in oklab, var(--deep) 55%, transparent);
  }
}
@media (hover: none) {
  .cs-doc-open { opacity: 1; translate: 0 0; scale: 1; }
}
@media (prefers-reduced-motion: reduce) {
  a.cs-doc:hover { translate: 0 0; }
  .cs-doc-open { translate: 0 0; scale: 1; }
}

/* A board that runs (canvas.html?parked), held at its own size in a frame
   and scaled down whole (js/case.js), with its still as the poster until
   it has painted. */
/* (the poster is given on the element as background-image: a url() in a
   custom property would be read against this stylesheet, not the page) */
.cs-live { aspect-ratio: var(--live-w) / var(--live-h); background: #eef3f3 0 0 / 100% auto no-repeat; }
.cs-live iframe {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(var(--live-w) * 1px);
  height: calc(var(--live-h) * 1px);
  border: 0;
  transform-origin: 0 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.cs-live iframe.is-ready { opacity: 1; }

.cs-phone {
  display: block;
  height: auto;
  filter:
    drop-shadow(0 calc(2 * var(--u)) calc(3 * var(--u)) color-mix(in oklab, var(--deep) 14%, transparent))
    drop-shadow(0 calc(20 * var(--u)) calc(26 * var(--u)) color-mix(in oklab, var(--deep) 30%, transparent));
}

/* the captions under a window or a picture: small, in the tile's ink */
.cs-cap {
  display: block;
  margin-top: calc(12 * var(--u));
  font-size: var(--t-small);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--tile-ink-2);
}
.cs-cap-ink { color: var(--ink-3); }
/* a caption never ends on one word alone ("the grid by food type never /
   did") */
.cs-cap, .cs-cap-ink { text-wrap: pretty; }

/* a tile that is a link lifts when pointed at, as the Work tiles do */
.cs-lift {
  transition:
    translate var(--t-settle) var(--spring-settle),
    box-shadow 0.45s ease;
}
@media (hover: hover) {
  .cs-lift:hover {
    translate: 0 calc(-4 * var(--u));
    box-shadow:
      inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent),
      0 calc(26 * var(--u)) calc(48 * var(--u)) calc(-22 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  }
}

/* ---- the icon, in an app icon's superellipse (css/work.css) ---- */
.ico {
  --ico: calc(60 * var(--u));
  display: block;
  flex: none;
  width: var(--ico);
  height: var(--ico);
  filter:
    drop-shadow(0 1px 1px rgb(0 0 0 / 0.06))
    drop-shadow(0 calc(var(--ico) * 0.1) calc(var(--ico) * 0.2) color-mix(in oklab, var(--deep) 22%, transparent));
}
.ico img {
  width: 100%;
  height: 100%;
  -webkit-mask: url(../assets/squircle.svg) center / 100% 100% no-repeat;
  mask: url(../assets/squircle.svg) center / 100% 100% no-repeat;
}
[data-case='pantrypal'] .ico img { scale: 1.07; }

/* ---- pills ----
   The Work tile's link, frosted white on a tile's colour; on the paper it
   is the title pill's plain white. A chip is the same capsule with a label
   rather than a link in it; chosen, it fills with the case's colour. */
.cs-pill, .cs-chip {
  position: relative;
  z-index: 3;
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: calc(6 * var(--u));
  height: max(30px, calc(38 * var(--u)));
  padding: 0 calc(15 * var(--u));
  border-radius: 999px;
  background: rgb(255 255 255 / 0.62);
  box-shadow:
    inset 0 0 0 1px rgb(255 255 255 / 0.7),
    0 1px 2px color-mix(in oklab, var(--deep) 12%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font-size: var(--t-small);
  line-height: 1;
  letter-spacing: 0;
  color: var(--pastel-ink);
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
.cs-pill { padding-right: calc(11 * var(--u)); transition: background-color 0.2s ease, scale var(--t-pop) var(--spring-pop); }
.cs-pill svg { width: 1.1em; height: 1.1em; transition: translate var(--t-snap) var(--spring-snap); }
@media (hover: hover) {
  .cs-pill:hover { background: #fff; }
  .cs-pill:hover svg { translate: calc(1.5 * var(--u)) calc(-1.5 * var(--u)); }
}
.cs-pill:active { scale: 0.96; transition-duration: 90ms; }
/* on the paper, the capsule is white and flat, like the title pill */
.cs-paper .cs-pill, .cs-paper .cs-chip { background: var(--surface); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.cs-paper .cs-pill:hover { background: var(--tint); }

.cs-chips { display: flex; flex-wrap: wrap; gap: calc(8 * var(--u)); }
.cs-chip i {
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  margin-left: calc(-2 * var(--u));
  border-radius: 50%;
  background: var(--dot, var(--deep));
}
button.cs-chip { cursor: pointer; transition: background-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease, scale var(--t-pop) var(--spring-pop); }
button.cs-chip:active { scale: 0.95; transition-duration: 90ms; }
@media (hover: hover) {
  button.cs-chip:not([aria-selected='true']):hover { background: #fff; }
}
button.cs-chip[aria-selected='true'] {
  background: color-mix(in oklab, var(--tint), var(--deep) 12%);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 18%, transparent);
  color: var(--pastel-ink);
}
.cs-paper button.cs-chip[aria-selected='true'] { background: var(--tint); }
.cs-chip-num {
  display: grid;
  place-items: center;
  min-width: 1.6em;
  height: 1.6em;
  margin-left: calc(-7 * var(--u));
  padding: 0 0.4em;
  border-radius: 999px;
  background: rgb(30 30 30 / 0.07);
  font-size: 0.8em;
  font-variant-numeric: tabular-nums;
}

/* ---- the facts under the overview: what, when, with what, where ----
   Four across, between two hairlines, each its small capital label over
   its value, the way a film's credits run along the foot of its poster.
   The values are a size up from the story's words, at a tile name's, and
   the second hairline closes the row, so the four can be taken in at a
   glance as one thing, the job in brief. (They stood at the story's size
   on one hairline, and ran on into the story map under them.) */
.cs-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: calc(20 * var(--u)) var(--gap);
  padding: calc(24 * var(--u)) 0;
  border-block: 1px solid rgb(var(--line) / 0.1);
}
.cs-facts dt { margin-bottom: calc(8 * var(--u)); }
.cs-facts dd { font-size: var(--t-name); line-height: 1.3; letter-spacing: -0.012em; color: var(--ink); text-wrap: balance; }
/* A fact that is a list (the stack, the tools) keeps each of its items
   whole and sets a dot between two items on one line, never at a line's
   end: every item carries the dot before it, and the list is drawn a
   dot's width out to the left, into a margin its fact cuts off, so the
   dot of whichever item starts a line is cut away with it. (They were
   one run of words with the dots typed in, and in the overview's narrow
   column "Illustrator ·" and "Figma ·" ended their lines on a dot.) */
.cs-facts > div { overflow-x: clip; }
.cs-facts dd.cs-list {
  display: flex;
  flex-wrap: wrap;
  margin-left: -0.7em;
}
.cs-list > span { white-space: nowrap; }
.cs-list > span::before {
  content: '·';
  content: '·' / '';
  display: inline-block;
  width: 0.7em;
  text-align: center;
}
/* a compound word that would break at its hyphen, kept to one line */
.cs-nw { white-space: nowrap; }

/* ---- steppers: a row of chips, and the stage they choose for ----
   All the panels stand in one cell; the chosen one is shown, and the one
   it replaces lifts away through a little blur as it rises in, on the
   settle spring (js/case.js marks which). */
.cs-stage { display: grid; }
.cs-stage > * {
  grid-area: 1 / 1;
  min-width: 0;
  opacity: 0;
  visibility: hidden;
  translate: 0 calc(12 * var(--u));
  filter: blur(calc(6 * var(--u)));
  transition:
    opacity 0.22s ease,
    translate 0.3s var(--ease-exit),
    filter 0.22s ease,
    visibility 0s linear 0.3s;
}
.cs-stage > [data-on] {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  filter: none;
  transition:
    opacity 0.35s ease 0.06s,
    translate var(--t-settle) var(--spring-settle) 0.06s,
    filter 0.35s ease 0.06s,
    visibility 0s;
}

/* ---- the chat's bubbles, for a question and its answer ----
   A size under the lead: the chat's own shapes, at a size that still
   reads as speech next to the story's words. A one-line bubble is a true
   pill; a long answer is a block with the same corners. */
.cs-bubbles { display: grid; gap: calc(12 * var(--u)); }
.cs-bubble {
  --b-lh: 1.36;
  --b-py: calc(12 * var(--u));
  max-width: 26em;
  padding: var(--b-py) calc(20 * var(--u));
  border-radius: calc((var(--b-lh) * 1em + 2 * var(--b-py)) / 2);
  font-size: max(16px, calc(22 * var(--u)));
  line-height: var(--b-lh);
  letter-spacing: -0.012em;
  color: var(--bubble-ink);
  text-wrap: pretty;
}
.cs-bubble.is-q { justify-self: end; background: var(--bubble); }
.cs-bubble.is-a { justify-self: start; background: var(--pill); }
.cs-bubble.is-a.is-long { border-radius: calc(26 * var(--u)); }
.cs-who {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  font-size: var(--t-small);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--ink-3);
}
.cs-who img {
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 20%;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgb(var(--line) / 0.1);
}
/* the question a section raises, standing alone on the right, as a
   question does in the chat */
.cs-ask { display: grid; justify-items: end; gap: calc(10 * var(--u)); }
.cs-ask .cs-small { color: var(--ink-3); }

/* ---- numbers: what shipped, what moved ---- */
.cs-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap);
}
.cs-stats > :last-child:nth-child(odd) { grid-column: 1 / -1; }
/* A number is the biggest thing on its tile, set at a headline's size in
   the tile's ink with its unit beside it a third as big, and what it
   counts small at the tile's foot. */
.cs-stat {
  display: grid;
  align-content: space-between;
  gap: calc(28 * var(--u));
  min-height: calc(230 * var(--u));
  padding: calc(30 * var(--u));
  border-radius: var(--r-tile);
}
.cs-stat b {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  font-weight: inherit;
  font-size: calc(84 * var(--u));
  line-height: 0.95;
  letter-spacing: -0.045em;
  color: var(--pastel-ink);
  font-variant-numeric: tabular-nums;
}
.cs-stat b small {
  margin-left: 0.2em;
  font-size: 0.3em;
  letter-spacing: -0.01em;
  color: var(--tile-ink);
}
.cs-stat > span:last-child {
  max-width: 24em;
  font-size: var(--t-small);
  line-height: 1.42;
  letter-spacing: 0;
  color: var(--tile-ink);
  text-wrap: pretty;
}

/* ---- what I learned ----
   Each lesson a column on a hairline, all of them in one row: its number,
   the lesson itself in the ink at a tile's name size, and why, small,
   under it. (They were one long list of sentences at the one size, the
   lesson and its reason run together; then two to a row.) */
.cs-lessons {
  /* the air between two rows of lessons is each lesson's own, under it,
     and the list gives the last row's back: a lesson shares its rows
     with its neighbours (below), and a row gap round shared rows is
     spread into them by the browser, which set each reason far from its
     lesson */
  --lesson-gap: calc(40 * var(--u));
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--gap);
  margin-bottom: calc(-1 * var(--lesson-gap));
  list-style: none;
  counter-reset: lesson;
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--ink-3);
}
.cs-lessons li {
  counter-increment: lesson;
  padding-top: calc(20 * var(--u));
  border-top: 1px solid rgb(var(--line) / 0.12);
  text-wrap: pretty;
}
/* the lessons in a row share three rows, their numbers, the lessons and
   the reasons, so a reason starts level with its neighbour's however many
   lines the lesson over it takes ("Build the system before the screens."
   ran to two lines, and its reason started a line lower than the one
   beside it) */
.cs-lessons li { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; align-content: start; margin-bottom: var(--lesson-gap); }
.cs-lessons li::before {
  content: counter(lesson, decimal-leading-zero);
  display: block;
  margin-bottom: calc(14 * var(--u));
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.cs-lessons strong {
  display: block;
  margin-bottom: calc(8 * var(--u));
  font-size: var(--t-name);
  line-height: 1.25;
  letter-spacing: -0.014em;
}

/* ---- notes: a numbered list, one chosen, beside a picture ---- */
.cs-notes { display: grid; gap: calc(4 * var(--u)); list-style: none; }
.cs-note {
  display: grid;
  grid-template-columns: calc(30 * var(--u)) minmax(0, 1fr);
  column-gap: calc(12 * var(--u));
  width: 100%;
  padding: calc(12 * var(--u)) calc(14 * var(--u));
  border-radius: calc(20 * var(--u));
  font-size: var(--t-body);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink-3);
  text-align: left;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease;
}
.cs-note-num {
  display: grid;
  place-items: center;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  margin-top: calc(-3 * var(--u));
  border-radius: 50%;
  background: rgb(var(--line) / 0.06);
  font-size: var(--t-micro);
  letter-spacing: 0;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  transition: background-color 0.25s ease, color 0.25s ease;
}
.cs-note-body { display: grid; }
.cs-note-more {
  display: grid;
  grid-template-rows: 0fr;
  font-size: var(--t-small);
  line-height: 1.45;
  letter-spacing: 0;
  color: var(--ink-3);
  transition: grid-template-rows var(--t-settle) var(--spring-settle), opacity 0.3s ease;
  opacity: 0;
}
.cs-note-more > span { overflow: hidden; }
.cs-note-more > span > span { display: block; padding-top: calc(8 * var(--u)); }
@media (hover: hover) {
  .cs-note:not([aria-selected='true']):hover { background: rgb(var(--line) / 0.04); color: var(--ink); }
}
.cs-note[aria-selected='true'] { background: var(--surface); color: var(--ink); }
.cs-note[aria-selected='true'] .cs-note-num { background: var(--tint); color: var(--pastel-ink); }
.cs-note[aria-selected='true'] .cs-note-more { grid-template-rows: 1fr; opacity: 1; }

/* ---- swatches ---- */
.cs-swatch { display: grid; justify-items: start; gap: calc(10 * var(--u)); }
.cs-swatch i {
  width: calc(var(--sw, 76) * var(--u));
  height: calc(var(--sw, 76) * var(--u));
  border-radius: 50%;
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08);
}
.cs-swatch span { font-size: var(--t-small); line-height: 1.25; letter-spacing: 0; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.cs-swatch b { display: block; font-weight: inherit; color: var(--ink); }

/* ---- the verdicts on an idea: set aside, or shipped ---- */
.cs-verdict {
  flex: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  height: max(22px, calc(26 * var(--u)));
  padding: 0 calc(11 * var(--u));
  border-radius: 999px;
  background: rgb(255 255 255 / 0.62);
  font-size: var(--t-micro);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--tile-ink-2);
}
.cs-verdict.is-yes { background: var(--deep); color: #fff; }
.cs-idea-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(6 * var(--u)) calc(12 * var(--u)); }
/* ---- the next case, and the ways to reach him ---- */
.cs-end { padding-top: var(--air-chapter); padding-bottom: calc(96 * var(--u)); }
/* the foot's head is one quiet line over the next case, not a chapter */
.cs-end-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(16 * var(--u));
  margin-bottom: calc(22 * var(--u));
  padding-top: calc(18 * var(--u));
  border-top: 1px solid rgb(var(--line) / 0.1);
}
.cs-end-head h2 { font-size: var(--t-micro); font-weight: 400; letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-3); }
.cs-end-head p { font-size: var(--t-small); color: var(--ink-3); }
.cs-next {
  position: relative;
  display: block;
  height: calc(380 * var(--u));
  overflow: hidden;
  isolation: isolate;
  border-radius: calc(40 * var(--u));
  -webkit-tap-highlight-color: transparent;
}
.cs-next .cs-hero-words { bottom: calc(40 * var(--u)); }
.cs-next .cs-hero-words .ico { --ico: calc(72 * var(--u)); }
.cs-next .cs-hero-name { margin-top: calc(22 * var(--u)); font-size: calc(44 * var(--u)); }
.cs-next-go { margin-top: auto; align-self: flex-start; }
.cs-next .cs-tile-meta:first-of-type { margin-top: calc(10 * var(--u)); }
.cs-next .cs-hero-art > * { transition: translate 0.9s var(--ease-rise); }
@media (hover: hover) {
  .cs-next:hover .cs-hero-art > * { translate: 0 calc(-12 * var(--u)); }
  .cs-next:hover .cs-hero-art > * + * { transition-delay: 60ms; }
}
.cs-contact { display: flex; flex-wrap: wrap; align-items: center; gap: calc(8 * var(--u)); margin-top: calc(32 * var(--u)); }
.cs-contact a {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: max(36px, calc(44 * var(--u)));
  padding: 0 calc(18 * var(--u));
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.2s ease, color 0.2s ease, scale var(--t-pop) var(--spring-pop);
}
.cs-contact a svg { width: 1.1em; height: 1.1em; }
@media (hover: hover) {
  .cs-contact a:hover { background: var(--tint); color: var(--pastel-ink); }
}
.cs-contact a:active { scale: 0.96; transition-duration: 90ms; }

/* ======================================================================
   The pieces a story is told with
   ====================================================================== */
.cs-label { margin-bottom: calc(14 * var(--u)); }

/* A tile with its words beside its work, and the work running off the
   tile's right edge and foot, as the hero's does. (The words stood over
   the work, and the work under them was 480 tall, so one tile was more
   than a window; then the tile stepped out onto the stage to make room
   for the two side by side.) --ah is the least height the work stands at;
   beside taller words it is as tall as they are. */
.cs-wide {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: calc(36 * var(--u));
  padding: calc(36 * var(--u)) 0 0 calc(36 * var(--u));
}
.cs-wide-words {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  padding-bottom: calc(36 * var(--u));
}
.cs-wide-words > * + * { margin-top: calc(4 * var(--u)); }
.cs-wide-words > .cs-pill { margin-top: calc(24 * var(--u)); align-self: flex-start; }
.cs-tile > .cs-wide-art { margin-top: 0; }
.cs-wide-art {
  position: relative;
  align-self: stretch;
  width: calc(100% + 1px);
  min-height: calc(var(--ah, 360) * var(--u));
  border-radius: var(--r-window) 0 0 0;
}
/* the picture hangs from the window's top and is cut off at its foot: it
   is the words beside it that say how tall the window is, not the page
   in the picture. Where the page is shorter than the window (the review's
   is nearly square, and the words beside it are long) it is drawn taller,
   from its top left corner, its right side running off the tile instead
   (it stopped two thirds of the way down, over a blank window) */
.cs-wide-art > img { position: absolute; left: 0; top: 0; width: 100%; height: auto; min-height: 100%; object-fit: cover; object-position: 0 0; }
@media (hover: hover) {
  .cs-wide .cs-wide-art { transition: translate 0.9s var(--ease-rise); }
  .cs-wide:hover .cs-wide-art { translate: 0 calc(-8 * var(--u)); }
}

/* ---- Vicino: the sketchbook, a sheet at a time ---- */
.cs-sheets {
  display: grid;
  grid-template-columns: calc(280 * var(--u)) minmax(0, 1fr);
  gap: var(--gap);
  align-items: center;
}
.cs-tile.cs-sheets > * { margin-top: 0; }
.cs-sheet-well { aspect-ratio: 3724 / 2112; }
.cs-sheet-well > img { object-fit: cover; }

/* ---- Vicino: two ways to build ----
   Each tile holds a picture of the tool, drawn at the tool's own small
   sizes: on the left the agent's panel, answering a brief with its working
   and a plan; on the right the board, the same plan built by hand. (The
   agent's side was two chat bubbles, a brief and a plan three words long,
   in a tile that was otherwise empty, and the board's video was a bottle
   held up in a hand, which barely moved and so read as a still.) The two
   stand as tall as the agent's finished panel, and the board stands in the
   middle of whatever height that leaves it. Each tile is a container, so
   the board can be measured against its own width. */
.cs-way { display: flex; flex-direction: column; container-type: inline-size; }

/* the agent's panel, after Canvas's own (Figma 140:511): a white sheet, a
   head with the agent's gradient spark and what it is doing, then the
   brief, the agent's working, and its plan */
.cs-copilot {
  display: grid;
  align-content: start;
  gap: calc(8 * var(--u));
  flex: 1;
  padding: 0 calc(12 * var(--u)) calc(12 * var(--u));
  border-radius: calc(20 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.07),
    0 calc(16 * var(--u)) calc(32 * var(--u)) calc(-20 * var(--u)) color-mix(in oklab, var(--deep) 50%, transparent);
  font-size: max(12px, calc(12.5 * var(--u)));
  line-height: 1.36;
  letter-spacing: 0;
  color: #44464a;
}
.cs-copilot-head {
  display: flex;
  align-items: center;
  gap: calc(9 * var(--u));
  height: calc(42 * var(--u));
  margin: 0 calc(-12 * var(--u));
  padding: 0 calc(10 * var(--u)) 0 calc(12 * var(--u));
  border-bottom: 1px solid rgb(15 23 42 / 0.07);
  font-weight: 650;
  color: #1d1d1f;
}
.cs-copilot-mark {
  display: grid;
  place-items: center;
  flex: none;
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: calc(8 * var(--u));
  background: linear-gradient(to bottom right, #3b82f6, #8b5cf6);
  box-shadow: 0 calc(2 * var(--u)) calc(8 * var(--u)) rgb(139 92 246 / 0.4);
  color: #fff;
}
.cs-copilot-mark svg { width: calc(13 * var(--u)); height: calc(13 * var(--u)); fill: currentColor; }
/* what the agent is doing, in the head's far corner: planning while it
   works, ready once the plan is in (at rest, ready) */
.cs-copilot-state { display: grid; margin-left: auto; font-size: max(11px, calc(11.5 * var(--u))); font-weight: 600; }
.cs-copilot-state > span {
  grid-area: 1 / 1;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  padding: calc(3 * var(--u)) calc(9 * var(--u)) calc(3 * var(--u)) calc(8 * var(--u));
  border-radius: 999px;
  background: #e5fbff;
  color: #0d7685;
}
.cs-copilot-state > span::before { content: ''; width: calc(6 * var(--u)); height: calc(6 * var(--u)); border-radius: 50%; background: currentColor; }
.cs-copilot-state > span:first-child { visibility: hidden; background: #eef0fe; color: #5457d6; }
/* the brief, as the panel sets a message of yours: on the right, in the
   board's cyan chip */
.cs-copilot-ask {
  justify-self: end;
  max-width: 88%;
  margin-top: calc(3 * var(--u));
  padding: calc(7 * var(--u)) calc(11 * var(--u));
  border-radius: calc(14 * var(--u)) calc(14 * var(--u)) calc(4 * var(--u)) calc(14 * var(--u));
  background: #e5fbff;
  color: #063a42;
  text-wrap: pretty;
}
/* its working: a line for each thing it did, each ticked off */
.cs-copilot-think { display: grid; }
.cs-copilot-think > * { grid-area: 1 / 1; }
.cs-copilot-trace { display: grid; gap: calc(4 * var(--u)); list-style: none; color: #5f6369; }
.cs-copilot-trace li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-copilot-trace li { display: grid; grid-template-columns: calc(16 * var(--u)) minmax(0, 1fr); column-gap: calc(8 * var(--u)); }
.cs-copilot-trace li > i { position: relative; width: calc(16 * var(--u)); height: calc(16 * var(--u)); margin-top: calc(1 * var(--u)); border-radius: 50%; background: #e5fbff; }
/* the tick, and the turning arc it replaces */
.cs-copilot-trace li > i::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 46%;
  width: calc(3.6 * var(--u));
  height: calc(7 * var(--u));
  border: solid #0d7685;
  border-width: 0 calc(1.6 * var(--u)) calc(1.6 * var(--u)) 0;
  translate: -50% -50%;
  rotate: 42deg;
}
.cs-copilot-trace li > i::after {
  content: '';
  position: absolute;
  inset: calc(3 * var(--u));
  border-radius: 50%;
  border: calc(1.6 * var(--u)) solid #8b8df5;
  border-top-color: transparent;
  opacity: 0;
}
/* the plan: three cards' worth of graph in a list, wired down its left
   side in their ports' colours, and under them its size and cost, and the
   one button it needs */
.cs-copilot-plan {
  display: grid;
  gap: calc(8 * var(--u));
  padding: calc(8 * var(--u));
  border-radius: calc(14 * var(--u));
  background: #f7f9f9;
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.06);
}
.cs-copilot-sum { display: inline-flex; align-items: baseline; gap: calc(7 * var(--u)); padding-left: calc(4 * var(--u)); font-size: max(11px, calc(11.5 * var(--u))); white-space: nowrap; color: #5f6369; }
.cs-copilot-sum b { font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: #1d1d1f; }
.cs-copilot-cost { display: inline-flex; align-items: center; align-self: center; gap: calc(2 * var(--u)); font-weight: 650; font-variant-numeric: tabular-nums; color: #0d7685; }
.cs-copilot-cost svg { width: calc(12 * var(--u)); height: calc(12 * var(--u)); fill: currentColor; }
.cs-copilot-nodes { position: relative; display: grid; gap: calc(4 * var(--u)); padding-left: calc(18 * var(--u)); list-style: none; }
.cs-copilot-nodes::before {
  content: '';
  position: absolute;
  left: calc(5 * var(--u));
  top: calc(14 * var(--u));
  bottom: calc(14 * var(--u));
  width: calc(2 * var(--u));
  border-radius: 1px;
  background: linear-gradient(#9b9cf1, #8bd6d9 50%, #ffb366);
  transform-origin: 50% 0;
}
.cs-copilot-nodes li {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  min-height: calc(29 * var(--u));
  padding: 0 calc(7 * var(--u)) 0 calc(9 * var(--u));
  border-radius: calc(10 * var(--u));
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.06), 0 1px calc(3 * var(--u)) rgb(15 23 42 / 0.05);
  font-weight: 600;
  white-space: nowrap;
  color: #1d1d1f;
}
/* each card's port, on the wire */
.cs-copilot-nodes li::before {
  content: '';
  position: absolute;
  left: calc(-17 * var(--u));
  top: 50%;
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  margin-top: calc(-4 * var(--u));
  border-radius: 50%;
  background: var(--p);
  box-shadow: 0 0 0 calc(2 * var(--u)) #f7f9f9;
}
.cs-copilot-nodes svg { flex: none; width: calc(15 * var(--u)); height: calc(15 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.cs-copilot-nodes li > span { margin-left: auto; overflow: hidden; text-overflow: ellipsis; font-weight: 500; font-size: max(11px, calc(11.5 * var(--u))); color: #8a8e95; }
.cs-copilot-nodes li > .is-model { padding: calc(2 * var(--u)) calc(7 * var(--u)); border-radius: calc(7 * var(--u)); background: #e5fbff; font-weight: 600; color: #0d7685; }
.cs-copilot-go { display: flex; align-items: center; justify-content: space-between; gap: calc(8 * var(--u)); }
.cs-copilot-act { display: grid; justify-items: end; }
.cs-copilot-act > span {
  grid-area: 1 / 1;
  display: inline-flex;
  align-items: center;
  gap: calc(5 * var(--u));
  height: calc(28 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(9 * var(--u));
  border-radius: 999px;
  font-weight: 600;
  white-space: nowrap;
}
.cs-copilot-go svg { width: calc(13 * var(--u)); height: calc(13 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.cs-copilot-add { visibility: hidden; background: #1d1d1f; color: #fff; }
.cs-copilot-added { padding-right: calc(4 * var(--u)) !important; color: #0d7685; }
/* the three dots, while it thinks */
.cs-copilot .cs-typing {
  height: calc(26 * var(--u));
  padding: 0 calc(11 * var(--u));
  gap: calc(4 * var(--u));
  border-radius: calc(13 * var(--u));
  background: #f7f9f9;
  color: #8a8e95;
}
.cs-copilot .cs-typing i { width: calc(6 * var(--u)); height: calc(6 * var(--u)); }

/* the board, by hand: Canvas's own cards, wired, at the board's small
   sizes. It is drawn in its own unit, --bu, one 360th of the tile's width,
   held to no bigger than the page's own, so the whole board shrinks with
   its tile as one picture, rather than being zoomed by a step at a few
   widths. The prompt and the still sit across the top; the video runs
   under them, half again as wide as either card, since it is the payoff,
   and the still's wire comes round under the prompt to reach it. (The
   video stood the size of the other two in the bottom right, beside an
   empty corner, its well 130 wide.) */
@property --bu { syntax: '<length>'; inherits: true; initial-value: 1px; }
.cs-mini {
  --bu: min(100cqw / 360, var(--u));
  position: relative;
  flex: none;
  width: calc(360 * var(--bu));
  height: calc(352 * var(--bu));
  margin: auto;
}
.cs-mini-wires {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  stroke: #9b9cf1;
  stroke-width: 2;
  stroke-linecap: round;
}
.cs-mini-wires path:last-child { stroke: #8bd6d9; }
.cs-node-card {
  position: absolute;
  width: calc(146 * var(--bu));
  padding: calc(9 * var(--bu));
  border-radius: calc(13 * var(--bu));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.075),
    0 calc(2 * var(--bu)) calc(8 * var(--bu)) rgb(15 23 42 / 0.08),
    0 calc(14 * var(--bu)) calc(26 * var(--bu)) calc(-16 * var(--bu)) color-mix(in oklab, var(--deep) 45%, transparent);
}
.cs-node-card > b {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--bu));
  height: calc(18 * var(--bu));
  font-weight: 700;
  font-size: calc(12 * var(--bu));
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: #1d1d1f;
}
.cs-node-card > b > svg { flex: none; width: calc(13 * var(--bu)); height: calc(13 * var(--bu)); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.cs-node-badge { padding: calc(2 * var(--bu)) calc(6 * var(--bu)); border-radius: calc(6 * var(--bu)); background: #e5fbff; font-size: calc(9 * var(--bu)); font-weight: 600; color: #0d7685; }
/* the card's own run button: a play triangle, the dot of a run, and the
   check a finished card earns (at rest, the check) */
.cs-node-chip { display: grid; place-items: center; flex: none; width: calc(18 * var(--bu)); height: calc(18 * var(--bu)); margin-left: auto; border-radius: calc(6 * var(--bu)); background: #f0fdff; color: #0d7685; }
.cs-node-chip > * { grid-area: 1 / 1; }
.cs-node-chip svg { width: calc(9 * var(--bu)); height: calc(9 * var(--bu)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.cs-node-chip svg:first-child { visibility: hidden; fill: currentColor; stroke: none; }
.cs-node-chip i { visibility: hidden; width: calc(6 * var(--bu)); height: calc(6 * var(--bu)); border-radius: 50%; background: #6366f1; }
.cs-node-well {
  position: relative;
  display: block;
  margin-top: calc(8 * var(--bu));
  overflow: hidden;
  aspect-ratio: 3 / 2;
  border-radius: calc(8 * var(--bu));
  background: #f7f9f9;
}
.cs-node-well :is(img, video) { display: block; width: 100%; height: 100%; object-fit: cover; }
.cs-node-well.is-text {
  aspect-ratio: auto;
  padding: calc(7 * var(--bu)) calc(8 * var(--bu));
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.06);
  font-size: calc(10.5 * var(--bu));
  line-height: 1.42;
  letter-spacing: 0;
  color: #44464a;
}
.cs-node-card .port {
  position: absolute;
  top: calc(36 * var(--bu));
  width: calc(7 * var(--bu));
  height: calc(20 * var(--bu));
  border-radius: calc(4 * var(--bu));
  background: var(--p);
  box-shadow:
    0 0 0 calc(2 * var(--bu)) #fff,
    0 calc(1 * var(--bu)) calc(4 * var(--bu)) rgb(15 23 42 / 0.18),
    0 0 calc(7 * var(--bu)) color-mix(in srgb, var(--p) 45%, transparent);
}
.cs-node-card .port.in { left: calc(-3.5 * var(--bu)); }
.cs-node-card .port.out { right: calc(-3.5 * var(--bu)); }
.cs-mini-text { left: 0; top: calc(14 * var(--bu)); }
.cs-mini-image { left: calc(184 * var(--bu)); top: 0; }
.cs-mini-video { left: calc(84 * var(--bu)); top: calc(160 * var(--bu)); width: calc(276 * var(--bu)); }
/* the video, as a finished video node shows one: the clip itself rolling
   in its well (a real video, the loop of Hazard's dribble the board's own
   card plays, so it moves as a video moves), its quality in a chip, and a
   player's bar along its foot whose scrubber is the clip's own clock
   (js/case.js sets --played) */
.cs-node-well.is-clip { aspect-ratio: 16 / 9; }
.cs-clip-chip {
  position: absolute;
  top: calc(6 * var(--bu));
  right: calc(6 * var(--bu));
  padding: calc(2 * var(--bu)) calc(6 * var(--bu));
  border-radius: 999px;
  background: rgb(15 23 42 / 0.55);
  font-size: calc(8.5 * var(--bu));
  font-weight: 600;
  line-height: 1.2;
  color: rgb(255 255 255 / 0.92);
}
.cs-clip-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: calc(6 * var(--bu));
  height: calc(28 * var(--bu));
  padding: calc(8 * var(--bu)) calc(9 * var(--bu)) 0;
  background: linear-gradient(to top, rgb(0 0 0 / 0.6), transparent);
  font-size: calc(8.5 * var(--bu));
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: #fff;
}
.cs-clip-play { flex: none; width: calc(9 * var(--bu)); height: calc(9 * var(--bu)); fill: currentColor; }
.cs-clip-play .is-pause, .is-rolling .cs-clip-play .is-play { display: none; }
.is-rolling .cs-clip-play .is-pause { display: inline; }
.cs-clip-track { position: relative; flex: 1; height: calc(3 * var(--bu)); border-radius: 2px; background: rgb(255 255 255 / 0.32); }
.cs-clip-track i { position: absolute; inset: 0; border-radius: inherit; background: #fff; transform-origin: 0 50%; scale: var(--played, 0) 1; }
.cs-clip-track::after {
  content: '';
  position: absolute;
  top: 50%;
  left: calc(var(--played, 0) * 100%);
  width: calc(7 * var(--bu));
  height: calc(7 * var(--bu));
  margin: calc(-3.5 * var(--bu)) 0 0 calc(-3.5 * var(--bu));
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px calc(3 * var(--bu)) rgb(0 0 0 / 0.35);
}
/* the hand that builds it: a pointer, its tip on the point it is at */
.cs-mini-hand {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
  width: calc(20 * var(--bu));
  height: calc(20 * var(--bu));
  margin: calc(-3 * var(--bu)) 0 0 calc(-5.25 * var(--bu));
  overflow: visible;
  fill: #1d1d1f;
  stroke: #fff;
  stroke-width: 1.1;
  stroke-linejoin: round;
  filter: drop-shadow(0 calc(1.5 * var(--bu)) calc(2 * var(--bu)) rgb(0 0 0 / 0.28));
  transform-origin: 26% 15%;
  opacity: 0;
  pointer-events: none;
}

/* ---- Vicino: one node, read a part at a time ----
   The node is drawn rather than shot: Canvas's Image card at its own
   proportions (320 wide and 340 tall, a header of 48, ports 10 by 28),
   in its own unit, --nu, on a board wider than it, with its two wires in
   and one out. Each part's name stands out in the margin on a hairline
   leader, the way a spec sheet labels a drawing, and the part being read
   does what it does: the verb rolls through the other cards' names, the
   ports take their cargo, the work resolves, the model's menu opens, the
   run runs, the output hands it on. Its sentence is set under the board,
   one of six, with the six as a row of steps that fills as the stepper
   walks. (It was a screenshot of the card, ringed a part at a time with
   the rest of the card washed pale round the ring, beside the six
   sentences as a list: the shot's own type was too small to read, and the
   wash took the life out of the picture the section is about.) */
@property --nu { syntax: '<length>'; inherits: true; initial-value: 1px; }
.cs-tile.cs-spec { display: grid; justify-items: center; padding: 0; container: spec / inline-size; }
/* the leaders lie over the card, so the dot on a leader's end can sit on
   its part; the wires lie under it, into the ports */
.cs-spec-lines.is-over { -webkit-mask: none; mask: none; }
/* the board's own dot grid, faint, under everything */
.cs-spec::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(circle, color-mix(in oklab, var(--deep) 20%, transparent) calc(1.1 * var(--u)), transparent calc(1.6 * var(--u))) 50% 50% / calc(22 * var(--u)) calc(22 * var(--u));
  -webkit-mask: radial-gradient(70% 70% at 50% 50%, #000 30%, transparent);
  mask: radial-gradient(70% 70% at 50% 50%, #000 30%, transparent);
}
/* the board is 760 by 418 of the node's own pixels: the node 320 wide in
   the middle, and 220 either side for its wires and its parts' names. Its
   unit is the page's, a little under it (at the page's own size the board
   and its sentence ran past the foot of a 1910 by 960 window), or less,
   if the tile is narrower than the board and a margin. */
.cs-spec-board {
  --nu: min(var(--u) * 0.94, 100cqw / 800);
  position: relative;
  width: calc(760 * var(--nu));
  height: calc(418 * var(--nu));
  margin: calc(18 * var(--nu)) 0 calc(10 * var(--nu));
}
.cs-spec-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* the wires come in from, and go out to, nowhere in particular */
  -webkit-mask: linear-gradient(to right, transparent, #000 13% 87%, transparent);
  mask: linear-gradient(to right, transparent, #000 13% 87%, transparent);
}
.cs-spec-wire { stroke: var(--p); stroke-width: 2.5; opacity: 0.6; transition: opacity 0.3s ease, stroke-width 0.3s ease; }
.cs-spec-wire[data-on] { opacity: 1; stroke-width: 3; }
.cs-spec-leader { stroke: var(--deep); stroke-width: 1.25; opacity: 0.26; transition: opacity 0.3s ease; }
.cs-spec-leader[data-on] { opacity: 1; stroke-width: 1.5; }
.cs-spec-dot { fill: #fff; stroke: var(--deep); stroke-width: 1.5; opacity: 0.5; transition: opacity 0.3s ease, fill 0.3s ease; }
.cs-spec-dot[data-on] { fill: var(--deep); opacity: 1; }

.cs-spec-node {
  position: absolute;
  left: calc(220 * var(--nu));
  top: calc(64 * var(--nu));
  width: calc(320 * var(--nu));
  height: calc(340 * var(--nu));
  border-radius: calc(16 * var(--nu));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.075),
    0 calc(2 * var(--nu)) calc(8 * var(--nu)) rgb(15 23 42 / 0.08),
    0 calc(30 * var(--nu)) calc(50 * var(--nu)) calc(-26 * var(--nu)) color-mix(in oklab, var(--deep) 55%, transparent);
  letter-spacing: 0;
  color: #1d1d1f;
}
.cs-spec-head { display: flex; align-items: center; gap: calc(8 * var(--nu)); height: calc(48 * var(--nu)); padding: 0 calc(14 * var(--nu)); }
/* the verb: the card's icon and name, in a slot one line tall over a
   column of the others' (Image again at its foot, so a roll ends where it
   began); the slot is as wide as the widest, which is Image's own width
   give or take a letter */
.cs-spec-verb {
  display: inline-block;
  height: calc(22 * var(--nu));
  overflow: hidden;
  border-radius: calc(6 * var(--nu));
  font-size: calc(14.5 * var(--nu));
  font-weight: 700;
  line-height: calc(22 * var(--nu));
  letter-spacing: -0.01em;
  /* a roll passes through soft edges (the glyphs at rest sit inside the
     fade's solid middle) */
  -webkit-mask: linear-gradient(transparent, #000 18% 82%, transparent);
  mask: linear-gradient(transparent, #000 18% 82%, transparent);
}
.cs-spec-verbs { display: flex; flex-direction: column; }
.cs-spec-verbs > span { display: flex; align-items: center; gap: calc(8 * var(--nu)); height: calc(22 * var(--nu)); white-space: nowrap; }
.cs-spec-node svg { flex: none; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.cs-spec-verbs svg { width: calc(17 * var(--nu)); height: calc(17 * var(--nu)); stroke-width: 1.5; }
.cs-spec-badge {
  position: relative;
  padding: calc(2 * var(--nu)) calc(8 * var(--nu));
  border-radius: calc(8 * var(--nu));
  background: #e5fbff;
  font-size: calc(10.5 * var(--nu));
  font-weight: 600;
  line-height: calc(16 * var(--nu));
  white-space: nowrap;
  color: #0d7685;
}
/* the model's menu, the four the card can call, open only while the
   model is the part being read */
.cs-spec-menu {
  position: absolute;
  left: calc(-6 * var(--nu));
  top: calc(100% + 8 * var(--nu));
  z-index: 2;
  display: grid;
  min-width: calc(150 * var(--nu));
  padding: calc(5 * var(--nu));
  border-radius: calc(12 * var(--nu));
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.08), 0 calc(10 * var(--nu)) calc(24 * var(--nu)) rgb(15 23 42 / 0.14);
  font-size: calc(12 * var(--nu));
  font-weight: 500;
  line-height: 1;
  color: #44464a;
  opacity: 0;
  visibility: hidden;
  scale: 0.94;
  transform-origin: 12% 0;
  transition: opacity 0.2s ease, scale var(--t-pop) var(--spring-pop), visibility 0s 0.2s;
}
.cs-spec-menu > span { display: flex; align-items: center; justify-content: space-between; height: calc(28 * var(--nu)); padding: 0 calc(9 * var(--nu)); border-radius: calc(8 * var(--nu)); }
.cs-spec-menu > span:first-child { background: #f0fdff; font-weight: 600; color: #0d7685; }
.cs-spec-menu svg { width: calc(12 * var(--nu)); height: calc(12 * var(--nu)); stroke-width: 2; }
.cs-spec-badge[data-on] .cs-spec-menu { opacity: 1; visibility: visible; scale: 1; transition-delay: 0.15s, 0.15s, 0s; }
.cs-spec-chip {
  display: grid;
  place-items: center;
  flex: none;
  width: calc(26 * var(--nu));
  height: calc(26 * var(--nu));
  margin-left: auto;
  border-radius: calc(9 * var(--nu));
  background: #f0fdff;
  color: #0d7685;
}
.cs-spec-chip > * { grid-area: 1 / 1; }
.cs-spec-chip svg { width: calc(12 * var(--nu)); height: calc(12 * var(--nu)); stroke-width: 2; }
.cs-spec-chip svg:first-child { visibility: hidden; fill: currentColor; stroke: none; }
.cs-spec-chip i { visibility: hidden; width: calc(8 * var(--nu)); height: calc(8 * var(--nu)); border-radius: 50%; background: #6366f1; }
.cs-spec-well {
  position: absolute;
  left: calc(14 * var(--nu));
  right: calc(14 * var(--nu));
  top: calc(48 * var(--nu));
  bottom: calc(14 * var(--nu));
  overflow: hidden;
  border-radius: calc(12 * var(--nu));
  background: #f7f9f9;
}
.cs-spec-well img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cs-spec-bar { position: absolute; left: calc(14 * var(--nu)); right: calc(14 * var(--nu)); bottom: calc(5 * var(--nu)); height: calc(3 * var(--nu)); overflow: hidden; border-radius: 2px; }
.cs-spec-bar i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, rgb(73 224 245 / 0.65), #49e0f5); transform-origin: 0 50%; scale: 0 1; }
.cs-spec-port {
  position: absolute;
  top: calc((var(--y) - 14) * var(--nu));
  z-index: 1;
  width: calc(10 * var(--nu));
  height: calc(28 * var(--nu));
  border: calc(2 * var(--nu)) solid #fff;
  border-radius: calc(6 * var(--nu));
  background: var(--p);
  box-shadow: 0 calc(2 * var(--nu)) calc(5 * var(--nu)) rgb(15 23 42 / 0.16), 0 0 calc(8 * var(--nu)) color-mix(in srgb, var(--p) 40%, transparent);
  transition: scale var(--t-pop) var(--spring-pop), box-shadow 0.3s ease;
}
.cs-spec-port.is-in { left: calc(-5 * var(--nu)); }
.cs-spec-port.is-out { right: calc(-5 * var(--nu)); }
.cs-spec-port[data-on] { scale: 1.14; box-shadow: 0 calc(2 * var(--nu)) calc(5 * var(--nu)) rgb(15 23 42 / 0.16), 0 0 calc(16 * var(--nu)) var(--p); }
/* each port's cargo, named beside it while the ports are read: the two
   inputs' inside the card, over the work, the output's under its wire
   (over it, it stood against the run's leader) */
.cs-spec-port > span {
  position: absolute;
  top: 50%;
  left: calc(100% + 9 * var(--nu));
  padding: calc(3 * var(--nu)) calc(8 * var(--nu));
  border-radius: 999px;
  background: color-mix(in srgb, var(--p) 22%, #fff);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--p) 55%, transparent), 0 calc(4 * var(--nu)) calc(10 * var(--nu)) rgb(15 23 42 / 0.12);
  font-size: calc(11 * var(--nu));
  font-style: normal;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: #1d1d1f;
  opacity: 0;
  translate: calc(-6 * var(--nu)) -50%;
  transition: opacity 0.25s ease, translate var(--t-pop) var(--spring-pop);
}
.cs-spec-port.is-out > span { top: calc(50% + 7 * var(--nu)); translate: calc(-6 * var(--nu)) 0; }
.cs-spec-port[data-on] > span { opacity: 1; translate: 0 -50%; transition-delay: 0.12s; }
.cs-spec-port.is-out[data-on] > span { translate: 0 0; }
/* a quiet ring round the part being read, in the case's ink (a dot on the
   end of a leader names the part; on a phone, with no margin for leaders,
   the ring does) */
.cs-spec-node [data-mark] { outline: calc(1.5 * var(--nu)) solid transparent; outline-offset: calc(2.5 * var(--nu)); transition: outline-color 0.3s ease, scale var(--t-pop) var(--spring-pop), box-shadow 0.3s ease; }
.cs-spec-node [data-mark][data-on]:not(.cs-spec-bar, .cs-spec-port) { outline-color: color-mix(in oklab, var(--deep) 75%, transparent); }
.cs-spec-well[data-on] { outline-offset: calc(-1.5 * var(--nu)); }

/* the parts' names, out in the margin: each a tab, its number on the end
   nearest its leader */
.cs-spec-tabs { list-style: none; }
.cs-spec-tabs li { position: absolute; top: calc(var(--y) * var(--nu)); left: calc(604 * var(--nu)); translate: 0 -50%; }
.cs-spec-tabs li.is-left { left: auto; right: calc(604 * var(--nu)); }
.cs-spec-tabs button {
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--nu));
  padding: calc(4 * var(--nu)) calc(12 * var(--nu)) calc(4 * var(--nu)) calc(4 * var(--nu));
  border-radius: 999px;
  font-size: max(12px, calc(14.5 * var(--nu)));
  line-height: 1.2;
  letter-spacing: -0.005em;
  color: var(--tile-ink-2);
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
}
.cs-spec-tabs .is-left button { flex-direction: row-reverse; padding: calc(4 * var(--nu)) calc(4 * var(--nu)) calc(4 * var(--nu)) calc(12 * var(--nu)); }
.cs-spec-tabs button > span {
  display: grid;
  place-items: center;
  width: calc(22 * var(--nu));
  height: calc(22 * var(--nu));
  border-radius: 50%;
  box-shadow: inset 0 0 0 calc(1.25 * var(--nu)) color-mix(in oklab, var(--deep) 40%, transparent);
  font-size: max(10px, calc(11.5 * var(--nu)));
  font-variant-numeric: tabular-nums;
  color: var(--deep);
  transition: background-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
}
@media (hover: hover) {
  .cs-spec-tabs button:not([aria-selected='true']):hover { background: rgb(255 255 255 / 0.45); color: var(--pastel-ink); }
}
.cs-spec-tabs button[aria-selected='true'] { background: #fff; color: var(--pastel-ink); box-shadow: 0 calc(6 * var(--nu)) calc(16 * var(--nu)) calc(-8 * var(--nu)) color-mix(in oklab, var(--deep) 45%, transparent); }
.cs-spec-tabs button[aria-selected='true'] > span { background: var(--deep); box-shadow: none; color: #fff; }
.cs-spec-tabs button:focus-visible { outline: 2px solid var(--deep); outline-offset: 2px; }

/* the sentence, under the board: the six as a row of steps, the ones read
   filled and the one being read filling for as long as the stepper waits
   on it (data-auto, 4200, on the page), then the sentence itself, each
   stacked in one place so that the board never moves when it changes */
.cs-spec-caption { display: grid; gap: calc(13 * var(--u)); margin-top: calc(14 * var(--u)); }
.cs-spec-steps { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: calc(6 * var(--u)); }
.cs-spec-steps i { position: relative; height: 3px; overflow: hidden; border-radius: 2px; background: rgb(var(--line) / 0.1); }
.cs-spec-steps i::after { content: ''; position: absolute; inset: 0; background: var(--deep); transform-origin: 0 50%; scale: 0 1; transition: scale 0.3s ease; }
.cs-spec-steps i:has(~ [data-on])::after, .cs-spec-steps i[data-on]::after { scale: 1 1; }
.cs-anatomy.is-walking .cs-spec-steps i[data-on]::after { animation: cs-spec-step 4.2s linear both; }
@keyframes cs-spec-step { from { scale: 0 1; } }
.cs-spec-notes { display: grid; }
.cs-spec-notes > p {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: calc(40 * var(--u)) minmax(0, 1fr);
  column-gap: calc(12 * var(--u));
  max-width: 44em;
  font-size: var(--t-body);
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--ink-3);
  text-wrap: pretty;
  opacity: 0;
  visibility: hidden;
  translate: 0 calc(6 * var(--u));
  transition: opacity 0.25s ease, translate 0.45s var(--ease-rise), visibility 0s 0.25s;
}
.cs-spec-notes > p[data-on] { opacity: 1; visibility: visible; translate: 0 0; transition-delay: 0.08s, 0.08s, 0s; }
.cs-spec-notes b { font-weight: 500; font-variant-numeric: tabular-nums; color: var(--accent); }
.cs-spec-notes strong { font-weight: inherit; color: var(--ink); }

/* what each part does while it is read, held at its first frame until
   the stepper is live (js/case.js), so the first part's does not play out
   at the page's load with no one there to see it */
/* (important, since every animation below is a shorthand, which sets its
   play state running at a greater specificity) */
.cs-anatomy:not(.is-live) *, .cs-anatomy:not(.is-live) *::after { animation-play-state: paused !important; }
/* the leader draws itself from the name to the part, and the dot on its
   end rings once */
.cs-spec-leader[data-on] { stroke-dasharray: 1; animation: cs-draw 0.5s var(--ease-draw) both; }
.cs-spec-dot[data-on] { animation: cs-spec-ring 1.4s ease-out 0.4s both; }
@keyframes cs-spec-ring { 0% { stroke-width: 1.5; stroke-opacity: 1; } 100% { stroke-width: 14; stroke-opacity: 0; } }
/* 1 the verb rolls through the other cards' names and comes back */
.cs-spec-verb[data-on] .cs-spec-verbs { animation: cs-spec-verbs 3.4s both; }
@keyframes cs-spec-verbs {
  0%, 12% { translate: 0 0; animation-timing-function: var(--spring-snap); }
  22%, 34% { translate: 0 -20%; animation-timing-function: var(--spring-snap); }
  44%, 56% { translate: 0 -40%; animation-timing-function: var(--spring-snap); }
  66%, 78% { translate: 0 -60%; animation-timing-function: var(--spring-snap); }
  88%, 100% { translate: 0 -80%; }
}
/* 2 the wires carry their cargo in: a bead of their colour down each, a
   wire's width again (a white spark read as a gap in the wire) */
.cs-spec-spark { stroke: var(--p); stroke-width: 6; stroke-dasharray: 0.035 0.965; stroke-dashoffset: 0.035; opacity: 0; }
.cs-spec-spark[data-on] { opacity: 1; animation: cs-spec-flow 1.3s linear infinite; }
@keyframes cs-spec-flow { from { stroke-dashoffset: 0.035; } to { stroke-dashoffset: -0.965; } }
/* 3 the work arrives again, out of a blur, a sheen passing over it */
.cs-spec-well[data-on] img { animation: cs-spec-resolve 1.2s var(--ease-rise) 0.1s both; }
@keyframes cs-spec-resolve { from { filter: blur(calc(10 * var(--nu))) saturate(0.4); scale: 1.06; opacity: 0.4; } }
.cs-spec-well::after { content: ''; position: absolute; inset: 0; background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.5) 50%, transparent 65%); translate: -100% 0; pointer-events: none; }
.cs-spec-well[data-on]::after { animation: cs-spec-sheen 1.1s ease 0.5s both; }
@keyframes cs-spec-sheen { to { translate: 100% 0; } }
/* 4 the model's menu (above) walks its four and comes back to its own */
.cs-spec-menu::before { content: ''; position: absolute; left: calc(5 * var(--nu)); right: calc(5 * var(--nu)); top: calc(5 * var(--nu)); height: calc(28 * var(--nu)); border-radius: calc(8 * var(--nu)); background: rgb(15 23 42 / 0.05); opacity: 0; }
.cs-spec-badge[data-on] .cs-spec-menu::before { animation: cs-spec-hover 2.6s ease-in-out 0.5s both; }
@keyframes cs-spec-hover {
  0% { opacity: 0; translate: 0 0; }
  10% { opacity: 1; translate: 0 0; }
  30% { translate: 0 100%; }
  50% { translate: 0 200%; }
  70% { translate: 0 300%; }
  90% { opacity: 1; translate: 0 0; }
  100% { opacity: 0; translate: 0 0; }
}
/* 5 the run: play, pressed; the dot of a run while the bar paints under
   the work and the work dims to wait for it; then the check */
.cs-spec-chip[data-on] svg:first-child { animation: cs-shown 0.55s linear; }
.cs-spec-chip[data-on] { animation: cs-press-chip 0.55s linear; }
.cs-spec-chip[data-on] i { animation: cs-shown 2.05s linear 0.55s, cs-breathe 0.9s ease-in-out 0.55s infinite; }
.cs-spec-chip[data-on] svg:last-child { animation: cs-swap-in 0.35s var(--spring-pop) 2.6s both; }
.cs-spec-bar[data-on] i { animation: cs-run 2.15s linear 0.5s both; }
.cs-spec-node:has(.cs-spec-chip[data-on]) .cs-spec-well img { animation: cs-spec-wait 2.6s ease both; }
@keyframes cs-spec-wait { 15%, 85% { opacity: 0.45; filter: saturate(0.3); } }
@keyframes cs-press-chip { 70% { scale: 1; } 82% { scale: 0.86; } 100% { scale: 1; } }
/* 6 the output hands it on: a spark out along its wire, a beat quicker */
.cs-spec-spark[data-mark='out'][data-on] { animation-duration: 1.1s; }

/* in a narrow board, no margin for leaders: the node alone, as big as the
   board lets it be, and the six names in a grid under it */
@container spec (max-width: 620px) {
  .cs-spec-board { --nu: min(var(--u), (100cqw - 40px) / 330); display: grid; justify-items: center; gap: 20px; width: calc(330 * var(--nu)); height: auto; margin: 24px 0; }
  .cs-spec-lines { display: none; }
  .cs-spec-node { position: relative; left: auto; top: auto; }
  .cs-spec-tabs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; width: 100%; }
  .cs-spec-tabs li, .cs-spec-tabs li.is-left { position: static; translate: none; }
  .cs-spec-tabs button, .cs-spec-tabs .is-left button { flex-direction: row; width: 100%; padding: 4px 10px 4px 4px; font-size: 13px; }
  .cs-spec-tabs button > span { width: 22px; height: 22px; font-size: 11px; }
}

/* ---- Vicino: the system, in one tile ---- */
.cs-system { --ah: 380; }
/* ---- Vicino: the library, a view at a time, running off the foot ---- */
.cs-components { padding-bottom: 0; }
.cs-components .cs-idea-head { margin-bottom: calc(24 * var(--u)); flex-wrap: wrap; }
.cs-components-path { color: var(--tile-ink-2); text-align: right; }
.cs-components-stage { height: calc(400 * var(--u)); margin-top: 0 !important; }
.cs-components-stage .cs-window { align-self: start; }

/* ---- Vicino: the two files the language was argued with, side by side,
   so the two arguments are read against each other. (They stood one over
   the other, each across the whole column so its numbers could be read,
   which took two windows; each opens in its own tab for that.) ---- */
.cs-decision-docs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* the two read row for row: each its name over its mark (the four accents,
   the verdict), its line, its window and its file, every row level with
   the other's, so the two dashboards stand side by side to be compared
   (the verdict wrapped under one name and stood beside the other's
   accents, and the second window stood 30 lower than the first) */
.cs-decision-docs > .cs-tile { display: grid; grid-row: span 4; grid-template-rows: subgrid; row-gap: 0; align-content: start; }
.cs-decision-docs .cs-idea-head { flex-direction: column; align-items: flex-start; gap: calc(8 * var(--u)); }

/* ---- Vicino: the guide, a window onto its top (the page itself reads on
   down, js/case.js); its never list beside it is further on, "the guide,
   and the list of what it must never do" ---- */
.cs-guide-doc .cs-window { margin-top: 0 !important; aspect-ratio: 16 / 10; }
.cs-review { --ah: 340; }


/* ---- PantryPal: the look, the app's own brand sheet ----
   Three cards made of the app's own things, each ringed in its ink on a
   hard ink shadow, as everything you tap in the app is: the chef on the
   kitchen's butter, and beside him, one over the other, the four colours
   and the two faces. The words are only names. (Until November 2026 the
   look was four of the page's lit tiles, two by two, each under an
   eyebrow and a line of what it was for: the chef stood cut off in one
   corner of his, six of the Figma file's stickers bobbed in a grid
   beside him, and a paragraph over the four and a quote under them said
   what the cards already showed.) */
.cs-look {
  --ring: calc(2.5 * var(--u));
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  grid-template-rows: 1fr 1fr;
  gap: var(--gap);
}
.cs-look-card {
  margin: 0;
  padding: 0;
  border-radius: calc(26 * var(--u));
  box-shadow: 0 0 0 var(--ring) var(--mark), 0 calc(5 * var(--u)) 0 var(--ring) var(--mark);
  color: var(--mark);
  list-style: none;
}
.cs-tile.cs-look-card > * { margin-top: 0; }

/* the chef, on his plate as the app sets a dish on its own: a coral
   ellipse in an ink rim on a white one, on a sunburst of twenty rays
   (pantry-app.css .pp-plate), here a circle, turning slowly. He stands up
   off the card's foot, where his drawing is cut, and his food is laid
   round his plate on one arc, the dish at its top a size up from the
   ingredients, each leaning out along the arc and bobbing a beat after
   the one before. The card is square, so its width measures it both
   ways (cqw). */
.cs-kitchen {
  --cx: 50cqw;
  --cy: 62cqw;
  grid-row: 1 / 3;
  aspect-ratio: 1;
  container-type: inline-size;
  background: radial-gradient(60% 60% at 50% 55%, #ffe3a1, transparent 75%), #ffd67e;
}
.cs-kitchen > * { position: absolute; }
.cs-kitchen-rays {
  left: var(--cx);
  top: var(--cy);
  width: 170cqw;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: repeating-conic-gradient(from 90deg, rgb(255 255 255 / 0.4) 0deg 9deg, transparent 9deg 18deg);
  -webkit-mask: radial-gradient(closest-side, #000 18%, rgb(0 0 0 / 0.55) 46%, transparent 72%);
  mask: radial-gradient(closest-side, #000 18%, rgb(0 0 0 / 0.55) 46%, transparent 72%);
  animation: cs-look-turn 140s linear infinite;
}
@keyframes cs-look-turn { to { rotate: 1turn; } }
.cs-kitchen-plate {
  left: var(--cx);
  top: var(--cy);
  width: 50cqw;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: #ff7e7d;
  box-shadow: inset 0 0 0 var(--ring) var(--mark), 0 0 0 2.2cqw #fff;
}
.cs-kitchen-chef {
  left: 50%;
  bottom: 0;
  width: 54cqw;
  height: auto;
  translate: -50% 0;
}
.cs-kitchen-food { inset: 0; list-style: none; }
.cs-kitchen-food li {
  /* seven stops from a little under the left of the plate's middle to a
     little under its right, 35 degrees apart */
  --a: calc(195deg - var(--i) * 35deg);
  --s: 15cqw;
  position: absolute;
  left: calc(var(--cx) + cos(var(--a)) * 41cqw);
  top: calc(var(--cy) - sin(var(--a)) * 41cqw);
  width: var(--s);
  aspect-ratio: 1;
  translate: -50% -50%;
  rotate: calc((90deg - var(--a)) * 0.14);
}
.cs-kitchen-food li:nth-child(4) { --s: 19cqw; }
.cs-kitchen-food img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 0.8cqw 0 rgb(150 92 0 / 0.22));
  animation: cs-look-bob 3.2s ease-in-out calc(var(--i) * -0.4s) infinite;
}
@keyframes cs-look-bob {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -1.4cqw; }
}
/* coming into view, the chef rises off the card's foot and his food pops
   on round him, left to right */
html.rises .cs-kitchen:not(.is-risen) .cs-kitchen-chef { translate: -50% 18%; }
html.rises .cs-kitchen:not(.is-risen) .cs-kitchen-food li { scale: 0; }
.cs-kitchen.is-risen .cs-kitchen-chef { transition: translate var(--t-pop) var(--spring-pop); }
.cs-kitchen.is-risen .cs-kitchen-food li { transition: scale var(--t-pop) var(--spring-pop) calc(0.18s + var(--i) * 0.06s); }

/* the palette as one strip of four chips, ringed and parted in the ink,
   each colour's name in the app's face over its value; coming into view
   the colours pour up into their chips, one after another */
.cs-look-paint {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--ring);
  background: var(--mark);
}
.cs-look-paint li {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 0;
  padding: calc(12 * var(--u)) calc(11 * var(--u));
  background: linear-gradient(var(--c) 0 0) 0 100% / 100% 100% no-repeat, #fff;
}
.cs-look-paint b {
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-weight: 400;
  font-size: max(12px, calc(15 * var(--u)));
  line-height: 1.2;
}
.cs-look-paint span {
  margin-top: calc(3 * var(--u));
  font-size: max(10px, calc(11 * var(--u)));
  line-height: 1.2;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: rgb(0 0 0 / 0.6);
}
html.rises .cs-look-paint:not(.is-risen) li { background-size: 100% 0%; }
.cs-look-paint.is-risen li { transition: background-size 0.7s cubic-bezier(0.2, 0.7, 0.2, 1); }
.cs-look-paint.is-risen li:nth-child(2) { transition-delay: 0.08s; }
.cs-look-paint.is-risen li:nth-child(3) { transition-delay: 0.16s; }
.cs-look-paint.is-risen li:nth-child(4) { transition-delay: 0.24s; }

/* the two faces, each on the surface the app sets it on: Fugaz One white
   in an ink outline on a coral title band, and Faustina in ink on a
   recipe's white card; each face's name is set in itself */
.cs-faces {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ring);
  background: var(--mark);
}
.cs-faces li {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: calc(14 * var(--u));
}
.cs-faces li.is-display { background: #ff7e7d; }
.cs-faces li.is-prose { background: #fff; }
.cs-faces .cs-type-aa { flex: 1; display: grid; place-items: center; padding-top: calc(8 * var(--u)); font-size: calc(84 * var(--u)); }
.cs-faces .cs-type-aa.cs-type-display { color: #fff; }
.cs-faces b { font-weight: 400; font-size: max(12px, calc(15 * var(--u))); line-height: 1.2; }
.cs-faces .is-display b { font-family: 'PP Fugaz One', system-ui, sans-serif; }
.cs-faces .is-prose b { font-family: 'PP Faustina', Georgia, serif; font-weight: 600; font-size: max(14px, calc(18 * var(--u))); line-height: 1.1; }
.cs-faces li > span:last-child { margin-top: calc(3 * var(--u)); font-size: max(10px, calc(11 * var(--u))); line-height: 1.2; letter-spacing: 0.04em; color: rgb(0 0 0 / 0.6); }

/* The sheet is drawn in the page's unit, so it holds its shape as the
   lane narrows; only the palette's chips run out of room for their names
   first, and under 700 they stand two by two. Under 520, a phone's lane,
   the three stand one over another, the chef first. (It stood in one
   column from 640 down, which on a window of about 1000 by 720 put the
   chef alone on a whole screen.) */
@container lane (max-width: 700px) {
  .cs-look-paint { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container lane (max-width: 520px) {
  .cs-look { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .cs-kitchen { grid-row: auto; }
  .cs-look-paint { grid-template-columns: repeat(4, minmax(0, 1fr)); height: calc(150 * var(--u)); }
  .cs-faces { height: calc(190 * var(--u)); }
}

/* ---- Next Level: Madrid, a map with two prints on it ---- */
/* (560 tall until October 2026: with the chapter's head and its story
   the map was a scroll past the window's foot) */
.cs-madrid { height: calc(440 * var(--u)); padding: 0; }
.cs-tile.cs-madrid > * { margin-top: 0; }
.cs-madrid-map { position: absolute; inset: calc(14 * var(--u)); border-radius: calc(22 * var(--u)); }
.cs-madrid-map > img { object-fit: cover; opacity: 0.9; }
.cs-madrid-pin {
  /* at the map's top right, where the prints leave it clear (it stood at
     the bottom left until the map came down to 440, and then sat on the
     first print's caption) */
  position: absolute;
  right: calc(34 * var(--u));
  top: calc(34 * var(--u));
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--u));
  height: calc(40 * var(--u));
  padding: 0 calc(16 * var(--u)) 0 calc(12 * var(--u));
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-6 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  font-size: var(--t-small);
  line-height: 1;
  letter-spacing: 0;
  color: var(--pastel-ink);
}
.cs-madrid-pin i { width: calc(12 * var(--u)); height: calc(12 * var(--u)); border-radius: 50%; background: #e5484d; box-shadow: 0 0 0 calc(4 * var(--u)) rgb(229 72 77 / 0.2); }
/* the two photos, pinned up over the map like prints, a little askew;
   pointed at, the tile straightens them */
.cs-print {
  position: absolute;
  z-index: 2;
  padding: calc(10 * var(--u)) calc(10 * var(--u)) calc(6 * var(--u));
  border-radius: calc(20 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--deep) 8%, transparent),
    0 calc(24 * var(--u)) calc(44 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 50%, transparent);
  transition: rotate var(--t-settle) var(--spring-settle), translate var(--t-settle) var(--spring-settle);
}
.cs-print .cs-window { border-radius: calc(12 * var(--u)); box-shadow: none; }
.cs-print .cs-cap { margin-top: calc(6 * var(--u)); padding-left: calc(4 * var(--u)); color: var(--ink-3); }
.cs-print-a { left: 8%; top: calc(32 * var(--u)); width: 30%; rotate: -4deg; }
.cs-print-b { right: 7%; top: calc(110 * var(--u)); width: 44%; rotate: 3.5deg; }
@media (hover: hover) {
  .cs-madrid:hover .cs-print { rotate: 0deg; }
  .cs-madrid:hover .cs-print-a { translate: 0 calc(-6 * var(--u)); }
  .cs-madrid:hover .cs-print-b { translate: 0 calc(-10 * var(--u)); }
}

/* ---- Next Level: the interview, as a chat ----
   Set on the paper, not in a tile, so the question stands in the chat's
   own blue and the answer in its own grey, exactly as on Home: on Next
   Level's blue tile the question's blue all but vanished. */
.cs-interview {
  /* the five questions down the left, as a messenger lists its threads,
     and the conversation beside them, who answered under it (the
     questions were a row of chips over the conversation, two lines of
     them in a narrow column, and the chat stood under that) */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: 'ask chat' 'ask who';
  gap: calc(12 * var(--u)) calc(36 * var(--u));
  align-items: start;
}
.cs-interview > .cs-chips { grid-area: ask; flex-direction: column; align-items: flex-start; gap: calc(6 * var(--u)); }
.cs-interview > .cs-interview-stage { grid-area: chat; }
.cs-interview > .cs-who { grid-area: who; }
.cs-interview-stage { min-height: calc(200 * var(--u)); align-items: start; }
.cs-interview .cs-bubble.is-a { max-width: 26em; }

/* ---- Next Level: the mark and its colorways ---- */
.cs-sketch { aspect-ratio: 1004 / 294; max-width: calc(560 * var(--u)); padding: calc(24 * var(--u)) calc(40 * var(--u)); }
.cs-colorways { list-style: none; }
.cs-colorways .cs-well { aspect-ratio: 1; }
/* each colorway's name over its verdict, so the three badges stand level
   (the verdict fitted beside "grey" and wrapped under "dark blue", and
   the first badge stood a line higher than the other two) */
.cs-colorways .cs-idea-head { flex-direction: column; align-items: flex-start; gap: calc(8 * var(--u)); }
.cs-colorways .cs-well > img { padding: 12%; }

/* ---- Next Level: the rollout, one mark on every surface ----
   The website across the whole column, where it reads, and under it the
   quarter-zip and the three socials in a row of four, each on its own
   tile. (In the full band the site took two thirds of the top row beside
   the quarter-zip; in the column that left it too narrow to read.) */
.cs-rollout {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap);
}
.cs-rollout-web { grid-column: 1 / -1; padding-bottom: 0; }
.cs-rollout-web .cs-window { margin-right: calc(-1 * var(--pad) - 1px); border-radius: var(--r-window) 0 0 0; }
.cs-rollout-web .cs-site { margin-bottom: 0; }
.cs-rollout-merch { display: flex; flex-direction: column; padding-bottom: var(--pad); }
.cs-photo { flex: 1; min-height: 0; }
.cs-photo > img { object-fit: cover; object-position: 50% 30%; }
.cs-social {
  display: block;
  width: 84%;
  height: auto;
  margin: calc(22 * var(--u)) auto 0;
  mix-blend-mode: multiply;
  transition: translate 0.7s var(--ease-rise);
}
/* ---- the next case's phones, at the page's foot ---- */
.cs-next-phones img { position: absolute; width: calc(200 * var(--u)); }
.cs-next-phones img:first-child { left: calc(40 * var(--u)); top: calc(40 * var(--u)); z-index: 1; }
.cs-next-phones img:nth-child(2) { left: calc(236 * var(--u)); top: calc(84 * var(--u)); }
.cs-next .cs-hero-art .cs-window { left: 0; top: calc(40 * var(--u)); width: calc(100% + 58 * var(--u)); }

/* ---- the view transition, from a Work tile into its hero and back ---- */
::view-transition-group(*) {
  animation-duration: var(--t-settle);
  animation-timing-function: var(--spring-settle);
}
/* The rest of the page crossfades under the tile. (base.css turns the
   root's own animation off for the colour change's spreading circle, which
   is Home's; there is no colour change here, so it is given one back.) */
::view-transition-old(root) { animation: cs-fade-out 0.24s ease both; }
::view-transition-new(root) { animation: cs-fade-in 0.32s ease both; }
@keyframes cs-fade-out { to { opacity: 0; } }
@keyframes cs-fade-in { from { opacity: 0; } }

/* The tile's two pictures, the Work tile's and the case study's opening
   tile's, are not stretched to the tile as it grows (the browser's own way,
   which blew the small tile's words up to three times their size): each
   stays at its own size, pinned at the top left, where the icon and the
   name are on both, and the growing tile clips them, so it reads as the
   tile opening out onto the case study. The small one lets go quickly.
   Its corners go from the Work tile's to the opening tile's as it grows:
   the opening tile fills the window, square at the top and rounded at its
   foot (above, "the hero"). */
html:active-view-transition-type(case)::view-transition-image-pair(case-vicino),
html:active-view-transition-type(case)::view-transition-image-pair(case-pantrypal),
html:active-view-transition-type(case)::view-transition-image-pair(case-nextlevel) {
  overflow: clip;
  border-radius: 0 0 calc(44 * var(--u)) calc(44 * var(--u));
  animation: cs-tile-open var(--t-settle) var(--spring-settle) both;
}
@keyframes cs-tile-open { from { border-radius: calc(32 * var(--u)); } }
/* The icon travels on its own, from its corner of the Work tile to its
   place on the opening tile, under the masthead's row: the opening tile's
   words stand lower than the Work tile's, so, pinned at the top left with
   the rest, the icon was seen to drop as the tiles crossed. css/work.css
   names the Work tile's icon the same. */
.cs[data-case='vicino'] .cs-hero-tile .ico { view-transition-name: case-vicino-icon; }
.cs[data-case='pantrypal'] .cs-hero-tile .ico { view-transition-name: case-pantrypal-icon; }
.cs[data-case='nextlevel'] .cs-hero-tile .ico { view-transition-name: case-nextlevel-icon; }
/* The tile growing into this page, and its icon, are drawn over the other
   two Work tiles as they let go where they stood: those follow it on the
   page being left, so they were drawn over it, and the last one's icon
   was seen to cross the growing tile. */
html:has(.cs[data-case='vicino'])::view-transition-group(case-vicino),
html:has(.cs[data-case='pantrypal'])::view-transition-group(case-pantrypal),
html:has(.cs[data-case='nextlevel'])::view-transition-group(case-nextlevel) { z-index: 1; }
html:has(.cs[data-case='vicino'])::view-transition-group(case-vicino-icon),
html:has(.cs[data-case='pantrypal'])::view-transition-group(case-pantrypal-icon),
html:has(.cs[data-case='nextlevel'])::view-transition-group(case-nextlevel-icon) { z-index: 2; }
html:active-view-transition-type(case)::view-transition-old(case-vicino),
html:active-view-transition-type(case)::view-transition-old(case-pantrypal),
html:active-view-transition-type(case)::view-transition-old(case-nextlevel),
html:active-view-transition-type(case)::view-transition-new(case-vicino),
html:active-view-transition-type(case)::view-transition-new(case-pantrypal),
html:active-view-transition-type(case)::view-transition-new(case-nextlevel) {
  inset: 0 auto auto 0;
  width: auto;
  height: auto;
  object-fit: none;
}
html:active-view-transition-type(case)::view-transition-old(case-vicino),
html:active-view-transition-type(case)::view-transition-old(case-pantrypal),
html:active-view-transition-type(case)::view-transition-old(case-nextlevel) {
  animation-duration: 0.18s;
}

@media (prefers-reduced-motion: reduce) {
  .cs-stage > *, .cs-stage > [data-on] { translate: 0 0; filter: none; transition-duration: 0.2s; transition-delay: 0s; }
  .cs-lift:hover, .cs-hero-tile:hover .cs-hero-art > *, .cs-next:hover .cs-hero-art > * { translate: 0 0; }
  .cs-kitchen-food img, .cs-kitchen-rays { animation: none; }
}

/* ---- a narrower column ----
   In a column under 500 (a window under about 1000, or a phone), the
   columns come down to one, the next case's words stand over its work
   instead of beside it, and every grid of tiles steps down; the colorways
   keep three to a row down to 440, which only a phone's column is under
   (at 480 they stood one to a row in a desktop's narrowest column). On a
   phone, too, every tile keeps to the words' two edges. (The next case's
   tile and the kitchen's card hung out past them by the chat's amount, as
   Work's tiles do, and were the only two wider than the rest of the
   story.) (These asked the window's
   width, 880, until the story kept to the lane, which is narrower than
   the window by a different amount at every size; then the lane's, 660,
   until the story kept to one column, which on a desktop runs from about
   480 to 800 and was stacked like a phone's from 660 down: at 1280 the
   three sketches stood one over another, three windows tall.) */
@container lane (max-width: 500px) {
  .cs-grid-2 { grid-template-columns: minmax(0, 1fr); }
  .cs-next { height: auto; max-height: none; min-height: 0; aspect-ratio: auto; }
  .cs-next .cs-hero-words { position: relative; left: auto; top: auto; bottom: auto; width: auto; padding: 32px 28px 0; }
  .cs-next .cs-hero-links { margin-top: 24px; }
  .cs-next .cs-hero-art { position: relative; inset: auto; height: 240px; margin-top: 28px; margin-left: 28px; }
}
@container lane (max-width: 440px) {
  .cs-grid-3 { grid-template-columns: minmax(0, 1fr); }
  /* a colorway to a row, its badge beside its name, its verdict and its
     colour (one over another, each badge stood the width of the phone,
     and the three took three screens) */
  .cs-colorways > .cs-tile { display: grid; grid-template-columns: 96px minmax(0, 1fr); grid-template-rows: auto auto; column-gap: 16px; row-gap: 10px; align-content: center; }
  .cs-colorways > .cs-tile > * { margin-top: 0; }
  .cs-colorways > .cs-tile > .cs-well { grid-column: 1; grid-row: 1 / 3; }
  .cs-colorways > .cs-tile > .cs-idea-head { grid-column: 2; align-self: end; }
  .cs-colorways > .cs-tile > .cs-swatch { grid-column: 2; align-self: start; }
}
/* The story's own pieces, in a narrow lane: every two-column piece goes
   to one column, the words first, and the tiles that lay their work
   beside their words lay it under them instead. */
@container lane (max-width: 500px) {
  /* (the two decision files went on standing side by side, each a
     phone's half, their paths broken over four lines and the pills that
     open them cut off at the tile's edge) */
  .cs-sheets, .cs-decision-docs { grid-template-columns: minmax(0, 1fr); }
  /* (the miniature board needs nothing here: it is drawn in its own
     unit, a 360th of its tile, so on a phone it is shrunk whole with the
     tile rather than squeezed) */
  .cs-mini { margin-top: 24px; }
  .cs-wide { grid-template-columns: minmax(0, 1fr); padding: 28px 0 0 28px; }
  .cs-wide-words { padding: 0 28px 0 0; }
  .cs-wide-words > .cs-pill { margin-top: 20px; }
  .cs-tile > .cs-wide-art { margin-top: 24px; min-height: 0; height: 340px; }
  .cs-components-stage { height: auto; }
  /* the browser's path takes its own line under the chips and reads from
     the left, its dot in the line (set to the right, it broke into a
     ragged block with its dot stranded at the far side) */
  .cs-components .cs-components-path { flex-basis: 100%; text-align: left; }
  .cs-components .cs-components-path a { display: block; }
  .cs-components .cs-components-path a svg { display: inline-block; vertical-align: -0.2em; }
  .cs-rollout-merch .cs-photo { height: 300px; }
  .cs-madrid { height: 400px; }
}
/* a number and its sentence to a row, in a narrow lane */
@container lane (max-width: 460px) {
  .cs-stats { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .cs { --gap: 16px; --pad: var(--hang); --cs-top: calc(var(--top) + var(--menu-size) + 24px); }
  .cs-head { margin-top: calc((var(--menu-size) - var(--title-h)) / 2); gap: 6px; }
  .cs-next, .cs-tile, .cs-stat { border-radius: 26px; }
  .cs-next .cs-hero-art { height: 300px; margin-left: 20px; }
}

/* ======================================================================
   The living pieces
   What the three case studies are told with once the work can run on the
   page instead of only being pictured on it: the app itself, the board
   itself, the brand itself. Everything here still speaks the draft's
   language (the reading sizes, the lit tiles, the frosted pills, the
   springs);
   what a piece shows inside itself (an app's own fonts, a board's own
   cards) is drawn at that thing's own sizes, since it is a picture of the
   work and not the page.
   ====================================================================== */

/* ---- reading: the back button's ring fills as the story does ----
   A hairline of the case's deep colour runs round the round back button,
   from twelve o'clock, as far as the page has been read (js/case.js
   writes --read, 0 to 1). It is the one thing on the masthead that
   moves with the scroll, and it says how much story is left without a
   bar laid across the window. */
.cs-back { position: relative; }
.cs-back::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(color-mix(in oklab, var(--deep) 62%, var(--tint)) calc(var(--read, 0) * 360deg), transparent 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3 * var(--u)), #000 calc(100% - 2.5 * var(--u)));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3 * var(--u)), #000 calc(100% - 2.5 * var(--u)));
  pointer-events: none;
}

/* ---- the demo: the app itself, on a phone ----
   The phone is the chapter, standing on the page on its own under the
   chapter's opener (its sticker, "Live app!", the rule, the caption, as
   every chapter opens), with "Start over" under its foot. PantryPal is on
   its home screen, opens from its icon and runs as the App Store build
   does (assets/case/pantrypal/app), drawn at the app's points inside so it
   can stand at any size here. Opener, phone and button stand together in
   one window: a link to the chapter lands with the opener 24 under the
   window's top, the masthead's buttons clear at the sides, and the phone
   as tall as the window leaves under it, never wider than 440. (Until
   November 2026 the phone stood in the app's butter under its awning, a
   card of its own; for a while before that under the chapter's title and
   a line about it, which put its foot under the fold; before that beside a
   card of the flow it walked, and a shelf of stickers.) */
#try.cs-phonesec { scroll-margin-top: calc(24 * var(--u) - var(--sec-pad)); }
.cs-phonesec-head { margin-bottom: calc(20 * var(--u)); }
.cs-phonestage {
  --phone-w: min(calc(440 * var(--u)), 100cqw - 40 * var(--u), (100svh - 190 * var(--u)) * 0.489);
  display: grid;
  justify-items: center;
  gap: calc(12 * var(--u));
}
.cs-demo-phone {
  position: relative;
  width: var(--phone-w);
  filter:
    drop-shadow(0 calc(2 * var(--u)) calc(3 * var(--u)) color-mix(in oklab, var(--deep) 16%, transparent))
    drop-shadow(0 calc(28 * var(--u)) calc(36 * var(--u)) color-mix(in oklab, var(--deep) 30%, transparent));
}
/* until the app has painted, the phone is its frame on a dark screen */
.cs-demo-phone:not(.pp-device) {
  aspect-ratio: 900 / 1840;
  background:
    url(../assets/case/pantrypal/app/frame.webp) 0 0 / 100% 100% no-repeat,
    radial-gradient(60% 40% at 30% 25%, #4a5466, #262c37 70%) 5.4% 2.5% / 89.2% 94.9% no-repeat;
}
.cs-demo-phone.pp-device { background: none; }
/* a word to press, in the app's ink ring */
.cs-preset {
  display: inline-block;
  padding: 0 calc(7 * var(--u));
  border-radius: calc(8 * var(--u));
  background: #fff;
  box-shadow: inset 0 0 0 calc(1.5 * var(--u)) var(--mark);
  font: inherit;
  line-height: 1.5;
  color: var(--mark);
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.2s ease, scale var(--t-pop) var(--spring-pop);
}
@media (hover: hover) { .cs-preset:hover { background: #fff1c9; } }
.cs-preset:active { scale: 0.95; transition-duration: 90ms; }
.cs-preset:focus-visible { outline: 2px solid var(--deep); outline-offset: 2px; }
.cs-phonestage-restart { padding: calc(4 * var(--u)) calc(12 * var(--u)); border-radius: calc(10 * var(--u)); font-size: var(--t-small); }

.cs-type-display {
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  letter-spacing: 0;
  color: #fff;
  --o: calc(3 * var(--u));
  --d: calc(2.12 * var(--u));
  text-shadow:
    var(--o) 0 0 #000, var(--d) var(--d) 0 #000, 0 var(--o) 0 #000, calc(-1 * var(--d)) var(--d) 0 #000,
    calc(-1 * var(--o)) 0 0 #000, calc(-1 * var(--d)) calc(-1 * var(--d)) 0 #000, 0 calc(-1 * var(--o)) 0 #000, var(--d) calc(-1 * var(--d)) 0 #000;
}
.cs-type-prose {
  font-family: 'PP Faustina', Georgia, serif;
  font-weight: 500;
  letter-spacing: 0;
}

/* ---- PantryPal: the hub, in the dark ----
   The old first screen with the lights off but for what it asked you to
   tap: fourteen windows onto the same screen, in the three kinds they come
   in (the foods in the brand's red, the shelf tabs in honey, the buttons in
   the app's own green). Seen at once, they are the finding; nothing has to
   point at them. Beside the screen, the one number that says it, as large
   as the tile will carry, over a row of fourteen bulbs, a bulb a window.
   As the tile rises the screen goes dark and the windows light one after
   another, each with a ping; with each one the number counts on by one
   (01 to 14) and its bulb comes on, so the count is the lights, not a
   number rolled up beside them.
   (It was a screenshot with fourteen numbered markers baked over it, which
   covered half the tabs' names, beside three findings with a paragraph
   each and lines drawn from them to the screen: three columns of words
   for one picture. The next try kept two smaller counts beside the screen,
   three taps to a recipe and two meanings for one plus, and they only
   took the eye off the fourteen.)
   Each window is a piece of the screen itself, the same picture laid at
   the same place over the dark (the figure is a container, so one of the
   picture's pixels is 100cqw / 459), so the dark never has to have holes
   cut in it. Places and sizes are in the picture's own pixels, and the
   two buttons' outer bottom corners (--bl, --br) follow the screen's own
   curve, or their windows would light a corner of the bezel. */
.cs-hub {
  --phone: calc(232 * var(--u));
  --t: min(var(--u), (100cqw - var(--phone) - 200 * var(--u)) / 340);
  display: grid;
  grid-template-columns: auto var(--phone);
  justify-content: space-evenly;
  column-gap: calc(40 * var(--u));
  align-items: center;
  padding: calc(44 * var(--u));
}
.cs-tile.cs-hub > * { margin-top: 0; }
.cs-hub .is-food { --kind: #ff4b4b; }
.cs-hub .is-tab { --kind: #e8a33d; }
.cs-hub .is-button { --kind: #45b441; }
/* one window, its bulb and its count all keep the same time */
.cs-hub [style*='--k'] { --at: calc(0.7s + var(--k, 0) * 0.085s); }

.cs-hub-phone { position: relative; justify-self: center; width: var(--phone); container-type: inline-size; --px: calc(100cqw / 459); }
.cs-hub-phone img { width: 100%; }
.cs-hub-dark, .cs-hub-lights { position: absolute; pointer-events: none; }
.cs-hub-dark {
  left: calc(33 * var(--px));
  top: calc(37 * var(--px));
  width: calc(387 * var(--px));
  height: calc(836 * var(--px));
  border-radius: calc(46 * var(--px));
  background: rgb(24 14 10 / 0.7);
  -webkit-backdrop-filter: saturate(0.45);
  backdrop-filter: saturate(0.45);
  transition: opacity 0.6s ease 0.2s;
}
.cs-hub-lights { inset: 0; }
.cs-hub-lights i {
  position: absolute;
  left: calc(var(--x) * var(--px));
  top: calc(var(--y) * var(--px));
  width: calc(var(--w) * var(--px));
  height: calc(var(--h) * var(--px));
  border-radius: calc(12 * var(--px)) calc(12 * var(--px)) calc(var(--br, 12) * var(--px)) calc(var(--bl, 12) * var(--px));
  background: url(../assets/case/pantrypal/figma/figma-2.webp) calc(var(--x) * var(--px) * -1) calc(var(--y) * var(--px) * -1) / 100cqw auto no-repeat;
  box-shadow:
    0 0 0 calc(1.5 * var(--u)) var(--kind),
    0 0 calc(14 * var(--u)) color-mix(in oklab, var(--kind) 55%, transparent);
  transition: opacity 0.25s ease;
}
/* the ping each window gives as it lights: its ring thrown out and gone */
.cs-hub-lights i::after { content: ''; position: absolute; inset: 0; border-radius: inherit; opacity: 0; }
html.rises .cs-hub:not(.is-risen) .cs-hub-dark,
html.rises .cs-hub:not(.is-risen) .cs-hub-lights i { opacity: 0; }
.cs-hub.is-risen .cs-hub-lights i { animation: cs-hub-light 0.4s ease-out var(--at) backwards; }
.cs-hub.is-risen .cs-hub-lights i::after { animation: cs-hub-ping 0.9s cubic-bezier(0.2, 0.7, 0.3, 1) var(--at); }
@keyframes cs-hub-light { from { opacity: 0; } }
@keyframes cs-hub-ping {
  from { opacity: 1; box-shadow: 0 0 0 0 var(--kind); }
  to { opacity: 0; box-shadow: 0 0 0 calc(14 * var(--u)) var(--kind); }
}
/* a kind pointed at under the count leaves only its own windows lit */
.cs-hub:has(.cs-hub-tally .is-food:hover) .cs-hub-lights i:not(.is-food),
.cs-hub:has(.cs-hub-tally .is-tab:hover) .cs-hub-lights i:not(.is-tab),
.cs-hub:has(.cs-hub-tally .is-button:hover) .cs-hub-lights i:not(.is-button) { opacity: 0; }
.cs-hub-tally:has(li:hover) li:not(:hover) { opacity: 0.35; }

/* The count, and the screen beside it, stand as one pair in the middle of
   the tile, the same air either side of them and between. Everything in
   the count is measured in --t, a unit that is the page's --u until the
   tile is too narrow to hold the screen and 340 of them (the count's
   width) side by side, so the number and the bulbs under it shrink
   together and keep one width. The bulbs are spread to the number's own
   ends, and the number is drawn in by the 1's side bearing, so its ink
   stands on the words' left edge. Its two digits are a counter (it
   counts on with the windows: a registered integer, so it can be
   animated, stepping once a window), always two digits wide, so the
   column never jumps as it goes from 09 to 10; the real 14 is beside it
   for a reader, and is what shows without script or under reduced motion. */
@property --hub-n { syntax: '<integer>'; inherits: false; initial-value: 14; }
.cs-hub-sum { display: grid; }
.cs-hub-count { display: grid; justify-items: start; }
.cs-hub-count b { font-weight: inherit; }
.cs-hub-n {
  display: block;
  margin-left: -0.126em;
  font-size: calc(308 * var(--t));
  line-height: 0.8;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--pastel-ink);
  counter-reset: hub var(--hub-n, 14);
}
.cs-hub-n::before { content: counter(hub, decimal-leading-zero); }
html.rises .cs-hub:not(.is-risen) .cs-hub-n { --hub-n: 0; }
/* a beat behind each window's own start, so it counts the window once it shows */
.cs-hub.is-risen .cs-hub-n { animation: cs-hub-count calc(14 * 0.085s) steps(14, jump-start) 0.82s backwards; }
@keyframes cs-hub-count { from { --hub-n: 0; } to { --hub-n: 14; } }
.cs-hub-count > span { margin-top: calc(22 * var(--t)); font-size: max(16px, calc(23 * var(--t))); line-height: 1.25; letter-spacing: -0.014em; color: var(--pastel-ink); }

/* the tally: a bulb a window, unlit rings until each window lights, its
   kind under each run of them */
.cs-hub-tally { display: flex; justify-content: space-between; gap: calc(20 * var(--t)); margin-top: calc(36 * var(--t)); padding-top: calc(22 * var(--t)); border-top: 1px solid color-mix(in oklab, var(--deep) 16%, transparent); list-style: none; }
.cs-hub-tally li { display: grid; gap: calc(12 * var(--t)); font-size: max(12px, calc(15 * var(--t))); line-height: 1.2; color: var(--tile-ink); white-space: nowrap; cursor: default; transition: opacity 0.25s ease; }
.cs-hub-bulbs { display: flex; gap: calc(6 * var(--t)); }
.cs-hub-bulbs i {
  position: relative;
  flex: none;
  width: calc(12 * var(--t));
  aspect-ratio: 1;
  border-radius: 50%;
  box-shadow: inset 0 0 0 max(1px, calc(1.5 * var(--t))) color-mix(in oklab, var(--kind) 45%, transparent);
}
.cs-hub-bulbs i::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--kind);
  box-shadow:
    0 0 0 calc(3 * var(--t)) color-mix(in oklab, var(--kind) 18%, transparent),
    0 0 calc(12 * var(--t)) color-mix(in oklab, var(--kind) 50%, transparent);
}
html.rises .cs-hub:not(.is-risen) .cs-hub-bulbs i::after { scale: 0; }
.cs-hub.is-risen .cs-hub-bulbs i::after { animation: cs-hub-bulb var(--t-pop) var(--spring-pop) var(--at) backwards; }
@keyframes cs-hub-bulb { from { scale: 0; } }

/* The verdict, as one of the case's stickers (the app's white button,
   ringed and set down on its ink, as the chapters' words are): a brain in
   the app's coral throwing off sparks, and what it is, slapped on the
   card's top edge once the count has come to fourteen, at its right,
   under the words it is the verdict on, and over the screen's column
   but clear of the screen, so it labels the finding without lying over
   the design. (At the left it sat under the chapter's deck, which ends
   lower than its words do, and crowded it.) The card lets it hang over
   its edge. */
.cs-tile.cs-hub { overflow: visible; }
.cs-tile.cs-hub > .cs-hub-flag {
  position: absolute;
  z-index: 3;
  top: 0;
  right: calc(44 * var(--u));
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--u));
  height: calc(48 * var(--u));
  margin: 0;
  padding: 0 calc(22 * var(--u)) 0 calc(13 * var(--u));
  border-radius: 999px;
  background: #fff;
  box-shadow: inset 0 0 0 calc(2.5 * var(--u)) var(--mark), 0 calc(4 * var(--u)) 0 var(--mark);
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-size: max(15px, calc(21 * var(--u)));
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: var(--mark);
  translate: 0 -55%;
  rotate: 2.5deg;
}
.cs-hub-flag svg { flex: none; width: calc(32 * var(--u)); height: auto; overflow: visible; }
.cs-hub-flag .is-brain { fill: #ff7e7d; stroke: var(--mark); stroke-width: 2; }
.cs-hub-flag .is-fold { stroke: var(--mark); stroke-width: 1.6; }
.cs-hub-flag .is-spark { stroke: var(--mark); stroke-width: 2.2; }
html.rises .cs-hub:not(.is-risen) .cs-hub-flag { opacity: 0; }
.cs-hub.is-risen .cs-hub-flag { animation: cs-hub-slap 0.55s var(--spring-pop) 2.05s backwards; }
@keyframes cs-hub-slap { from { opacity: 0; scale: 1.8; rotate: 12deg; } }

/* a phone's: the count over the screen, both centred */
@container lane (max-width: 560px) {
  .cs-hub { --phone: min(230px, 64cqw); --t: min(var(--u), (100cqw - 44px) / 340); grid-template-columns: auto; justify-content: center; row-gap: 34px; padding: 40px 22px 34px; }
  .cs-tile.cs-hub > .cs-hub-flag { right: 16px; }
}

/* ---- the store page: the listing's own panels, as the store lays them ---- */
.cs-store {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: calc(14 * var(--u));
  padding: calc(36 * var(--u));
  list-style: none;
}
.cs-tile.cs-store > * { margin-top: 0; }
.cs-store img {
  width: 100%;
  height: auto;
  border-radius: calc(18 * var(--u));
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent),
    0 calc(18 * var(--u)) calc(34 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 50%, transparent);
  transition: translate 0.7s var(--ease-rise);
}
@media (hover: hover) {
  .cs-store:hover li img { translate: 0 calc(-6 * var(--u)); }
  .cs-store:hover li + li img { transition-delay: 40ms; }
  .cs-store:hover li + li + li img { transition-delay: 80ms; }
  .cs-store:hover li + li + li + li img { transition-delay: 120ms; }
  .cs-store:hover li + li + li + li + li img { transition-delay: 160ms; }
}

/* ---- a wide picture that is the whole point: montages, sweeps ---- */
.cs-sweep { padding-bottom: calc(36 * var(--u)); }
.cs-sweep .cs-idea-head { margin-bottom: calc(24 * var(--u)); }
.cs-sweep .cs-stage img { width: 100%; height: auto; border-radius: calc(16 * var(--u)); }
.cs-sweep-labels {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: calc(10 * var(--u)) !important;
  font-size: var(--t-small);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--tile-ink-2);
  text-align: center;
}

/* ---- a document that is the real page, running (js/case.js) ----
   The window keeps its still as the poster, and the page itself is laid
   over it once it is near, drawn at its own width and scaled down whole,
   as the board is. A long one reads itself: it scrolls slowly while in
   view and holds still under the pointer, and a press opens the real file
   (the link it sits in). One that is meant to be used (data-live-use)
   takes the pointer instead, and its way out to the real file is the path
   in its tile's head, which says it is live. */
.cs-live-doc { isolation: isolate; }
.cs-live-doc > iframe {
  position: absolute;
  z-index: 1;
  left: 0;
  top: 0;
  border: 0;
  transform-origin: 0 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}
.cs-live-doc > iframe.is-ready { opacity: 1; }
.cs-live-doc[data-live-use] > iframe { pointer-events: auto; }
.cs-live-doc .cs-doc-open { z-index: 3; }

/* the mark of a window that is the real thing, in its caption: a small
   green dot that breathes, beside the file's own path */
.cs-live-dot {
  display: inline-block;
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  margin: 0 calc(8 * var(--u)) calc(1 * var(--u)) calc(1 * var(--u));
  border-radius: 50%;
  vertical-align: middle;
  background: #43ba51;
  box-shadow: 0 0 0 calc(3 * var(--u)) rgb(67 186 81 / 0.2);
  animation: cs-live 2s ease-in-out infinite;
}
.cs-components-path a { display: inline-flex; align-items: center; justify-content: flex-end; gap: calc(2 * var(--u)); color: var(--tile-ink); }
.cs-components-path a svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); transition: translate var(--t-snap) var(--spring-snap); }
@media (hover: hover) {
  .cs-components-path a:hover { color: var(--pastel-ink); }
  .cs-components-path a:hover svg { translate: calc(1.5 * var(--u)) calc(-1.5 * var(--u)); }
}
@keyframes cs-live { 50% { box-shadow: 0 0 0 calc(5 * var(--u)) rgb(67 186 81 / 0.08); } }

/* ---- a site, top to bottom ----
   The whole page as it is live (captured at a desktop's 1100), sliding up
   under its own sticky header, slowly, once the tile has come into view:
   down at a reader's pace, a rest at the foot, and back up. Pointed at,
   it holds; pressed, it opens the site itself. The page slides by its own
   height less the window's, which the window, a size container, knows. */
.cs-site { aspect-ratio: 1100 / 820; }
.cs-site-page { position: absolute; inset: 0; overflow: hidden; container-type: size; }
/* The page opens on its headline, just under the bar, and reads down
   from there: the capture's own top is the site's switch between its two
   audiences and then a blank band the height of a window over the
   headline, so the window opened on a page that looked empty. (6.67% of
   the capture's height lands the headline 50 of its pixels under the
   bar.) */
.cs-site-page img { display: block; width: 100%; height: auto; translate: 0 -6.67%; }
.cs-site-bar { position: absolute; z-index: 1; left: 0; top: 0; width: 100%; height: auto; box-shadow: 0 1px 0 rgb(15 23 42 / 0.06); }
.is-risen .cs-site-page img, .cs-site.is-risen .cs-site-page img { animation: cs-site-read 64s var(--ease-draw) 1.2s infinite; }
@media (hover: hover) { .cs-site:hover .cs-site-page img { animation-play-state: paused; } }
@keyframes cs-site-read {
  0%, 4% { translate: 0 -6.67%; }
  84%, 91% { translate: 0 calc(-100% + 100cqh); }
  100% { translate: 0 -6.67%; }
}

/* ---- the hero's run: the board's own Run, pressed from the page ---- */
.cs-pill[data-run] { cursor: pointer; }
.cs-pill[data-run] svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); }
.cs-pill[data-run].is-running { pointer-events: none; }
/* a play triangle at rest; while the board runs, a turning arc */
.cs-pill[data-run] .cs-run-busy { display: none; }
.cs-pill[data-run].is-running .cs-run-go { display: none; }
.cs-pill[data-run].is-running .cs-run-busy { display: block; animation: cs-spin 0.9s linear infinite; }
@keyframes cs-spin { to { rotate: 1turn; } }

/* ---- Vicino: two ways to build, played out ----
   When the pair comes into view (.is-playing, js/case.js), each side
   builds the same board its own way, in about six seconds. On the left
   the agent is asked, thinks, ticks off its working a line at a time,
   lays out its plan, and the plan is added to the board. On the right a
   pointer drags the prompt in, pulls its wire to the still, runs the
   still, pulls the still's wire round to the video and runs that, and
   the clip rolls (js/case.js starts it once its card has filled). The
   end state is the resting one, so without script or motion it simply
   stands there, finished. */
.cs-ways .cs-typing { display: none; }
.cs-ways.is-playing .cs-copilot-ask { animation: cs-pop-in 0.5s var(--spring-pop) 0.1s both; }
.cs-ways.is-playing .cs-copilot-think .cs-typing { display: inline-flex; justify-self: start; animation: cs-typing-life 0.95s linear 0.45s both; }
.cs-ways.is-playing .cs-copilot-trace li { animation: cs-pop-in 0.4s var(--spring-pop) calc(1.4s + var(--k) * 0.38s) both; }
.cs-ways.is-playing .cs-copilot-trace li > i::before { animation: cs-swap-in 0.3s var(--spring-pop) calc(1.72s + var(--k) * 0.38s) both; }
.cs-ways.is-playing .cs-copilot-trace li > i::after { animation: cs-spin 0.7s linear infinite, cs-shown 0.32s linear calc(1.4s + var(--k) * 0.38s); }
.cs-ways.is-playing .cs-copilot-state > span:first-child { animation: cs-shown 2.55s linear; }
.cs-ways.is-playing .cs-copilot-state > span:first-child::before { animation: cs-breathe 0.9s ease-in-out infinite; }
.cs-ways.is-playing .cs-copilot-state > span:last-child { animation: cs-swap-in 0.3s var(--spring-pop) 2.55s both; }
.cs-ways.is-playing .cs-copilot-plan { animation: cs-pop-in 0.5s var(--spring-pop) 2.55s both; }
.cs-ways.is-playing .cs-copilot-nodes li { animation: cs-pop-in 0.45s var(--spring-pop) calc(2.75s + var(--k) * 0.14s) both; }
.cs-ways.is-playing .cs-copilot-nodes::before { animation: cs-grow 0.5s var(--ease-draw) 2.95s both; }
.cs-ways.is-playing .cs-copilot-cost { animation: cs-pop-in 0.4s var(--spring-pop) 3.2s both; }
.cs-ways.is-playing .cs-copilot-add { animation: cs-add 1.2s linear 3.3s both; }
.cs-ways.is-playing .cs-copilot-added { animation: cs-swap-in 0.35s var(--spring-pop) 4.45s both; }
@keyframes cs-pop-in { from { opacity: 0; translate: 0 calc(10 * var(--u)); scale: 0.96; } }
@keyframes cs-typing-life { 0% { opacity: 0; scale: 0.9; } 10%, 88% { opacity: 1; scale: 1; } 100% { opacity: 0; scale: 0.96; visibility: hidden; } }
/* shown only for as long as it runs (no fill: before and after, the
   resting state, which hides it) */
@keyframes cs-shown { from, to { visibility: visible; opacity: 1; } }
@keyframes cs-swap-in { from { opacity: 0; scale: 0.8; } }
@keyframes cs-grow { from { scale: 1 0; } }
@keyframes cs-breathe { 50% { opacity: 0.35; } }
/* the button: up, pressed, and gone into what it did */
@keyframes cs-add {
  0% { visibility: visible; opacity: 0; scale: 0.94; }
  12% { visibility: visible; opacity: 1; scale: 1; }
  70% { visibility: visible; opacity: 1; scale: 1; }
  78% { visibility: visible; opacity: 1; scale: 0.92; }
  88% { visibility: visible; opacity: 1; scale: 1; }
  100% { visibility: visible; opacity: 0; scale: 1; }
}
/* the answer being written: three dots, one after another */
.cs-typing {
  justify-self: start;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(var(--lh) * 1em + 25 * var(--u));
  padding: 0 calc(22 * var(--u));
}
.cs-typing i { width: calc(9 * var(--u)); height: calc(9 * var(--u)); border-radius: 50%; background: currentColor; opacity: 0.35; animation: cs-dot 1.1s ease-in-out infinite; }
.cs-typing i:nth-child(2) { animation-delay: 0.15s; }
.cs-typing i:nth-child(3) { animation-delay: 0.3s; }
@keyframes cs-dot { 30% { opacity: 1; translate: 0 calc(-3 * var(--u)); } 60% { opacity: 0.35; translate: 0 0; } }

/* the board, by hand: the prompt dragged in under the pointer, the still
   dropped beside it, and each wire drawn as the pointer pulls it; each
   card's run shows play, then the dot of a run while its bar paints under
   the well, then the check, and the picture fills */
.cs-mini-wires path { stroke-dasharray: 1; stroke-dashoffset: 0; }
.cs-ways.is-playing .cs-mini-text { animation: cs-hand-drag 0.65s cubic-bezier(0.33, 0, 0.2, 1) 0.1s both, cs-appear 0.12s linear 0.1s both, cs-hand-drop 0.3s var(--spring-pop) 0.75s; }
.cs-ways.is-playing .cs-mini-image { animation: cs-pop-in 0.5s var(--spring-pop) 0.85s both; }
.cs-ways.is-playing .cs-mini-wires path:first-child { animation: cs-draw 0.45s linear 1.4s both; }
.cs-ways.is-playing .cs-mini-image .cs-node-chip svg:first-child { animation: cs-shown 1.51s linear 0.85s; }
.cs-ways.is-playing .cs-mini-image .cs-node-chip i { animation: cs-shown 1.04s linear 2.36s, cs-breathe 0.8s ease-in-out 2.36s infinite; }
.cs-ways.is-playing .cs-mini-image .cs-node-chip svg:last-child { animation: cs-swap-in 0.3s var(--spring-pop) 3.4s both; }
.cs-ways.is-playing .cs-mini-image .cs-node-well::after { animation: cs-run 1.04s linear 2.36s both; }
.cs-ways.is-playing .cs-mini-image .cs-node-well img { animation: cs-fill 0.5s ease 3.4s both; }
.cs-ways.is-playing .cs-mini-video { animation: cs-pop-in 0.5s var(--spring-pop) 2.7s both; }
.cs-ways.is-playing .cs-mini-wires path:last-child { animation: cs-draw 1s linear 3.55s both; }
.cs-ways.is-playing .cs-mini-video .cs-node-chip svg:first-child { animation: cs-shown 2.41s linear 2.7s; }
.cs-ways.is-playing .cs-mini-video .cs-node-chip i { animation: cs-shown 1.24s linear 5.11s, cs-breathe 0.8s ease-in-out 5.11s infinite; }
.cs-ways.is-playing .cs-mini-video .cs-node-chip svg:last-child { animation: cs-swap-in 0.3s var(--spring-pop) 6.35s both; }
.cs-ways.is-playing .cs-mini-video .cs-node-well::after { animation: cs-run 1.24s linear 5.11s both; }
.cs-ways.is-playing .cs-mini-video .cs-node-well video { animation: cs-fill 0.5s ease 6.35s both; }
.cs-ways.is-playing .cs-mini-video :is(.cs-clip-chip, .cs-clip-bar) { animation: cs-appear 0.4s ease 6.45s both; }
.cs-ways.is-playing .cs-mini-hand { animation: cs-hand 6s linear both; }
@keyframes cs-draw { from { stroke-dashoffset: 1; } }
@keyframes cs-fill { from { opacity: 0; scale: 1.04; } }
@keyframes cs-appear { from { opacity: 0; } }
/* the prompt, carried in on the pointer, a card lifted off the board */
@keyframes cs-hand-drag {
  from {
    translate: calc(-34 * var(--bu)) calc(138 * var(--bu));
    rotate: -4deg;
    box-shadow:
      0 0 0 1px rgb(15 23 42 / 0.075),
      0 calc(6 * var(--bu)) calc(14 * var(--bu)) rgb(15 23 42 / 0.12),
      0 calc(28 * var(--bu)) calc(40 * var(--bu)) calc(-14 * var(--bu)) color-mix(in oklab, var(--deep) 55%, transparent);
  }
}
@keyframes cs-hand-drop { 0% { scale: 1.03; } 100% { scale: 1; } }
@keyframes cs-hand {
  0% { translate: calc(26 * var(--bu)) calc(170 * var(--bu)); scale: 0.9; opacity: 0; animation-timing-function: linear; }
  1.67% { translate: calc(26 * var(--bu)) calc(170 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: cubic-bezier(0.33, 0, 0.2, 1); }
  12.5% { translate: calc(60 * var(--bu)) calc(32 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  14.17% { translate: calc(60 * var(--bu)) calc(32 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  15% { translate: calc(60 * var(--bu)) calc(32 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: ease-in-out; }
  21.67% { translate: calc(146 * var(--bu)) calc(60 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  23.33% { translate: calc(146 * var(--bu)) calc(60 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  30.83% { translate: calc(184 * var(--bu)) calc(46 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  32.5% { translate: calc(184 * var(--bu)) calc(46 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: ease-in-out; }
  38.33% { translate: calc(312 * var(--bu)) calc(18 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  39.33% { translate: calc(312 * var(--bu)) calc(18 * var(--bu)); scale: 0.84; opacity: 1; animation-timing-function: linear; }
  40.67% { translate: calc(312 * var(--bu)) calc(18 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: ease-in-out; }
  47.5% { translate: calc(330 * var(--bu)) calc(46 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  57.5% { translate: calc(330 * var(--bu)) calc(46 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  59.17% { translate: calc(330 * var(--bu)) calc(46 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  60.56% { translate: calc(347.9 * var(--bu)) calc(76.2 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  61.94% { translate: calc(347.4 * var(--bu)) calc(113.7 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  63.33% { translate: calc(330.5 * var(--bu)) calc(145.2 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  64.72% { translate: calc(293.1 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  66.11% { translate: calc(255.3 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  67.5% { translate: calc(218.1 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  68.89% { translate: calc(180.3 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  70.28% { translate: calc(143.1 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  71.67% { translate: calc(105.3 * var(--bu)) calc(146 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  73.06% { translate: calc(68.5 * var(--bu)) calc(148.8 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  74.44% { translate: calc(58.7 * var(--bu)) calc(182.9 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  75.83% { translate: calc(84 * var(--bu)) calc(206 * var(--bu)); scale: 0.9; opacity: 1; animation-timing-function: linear; }
  77.5% { translate: calc(84 * var(--bu)) calc(206 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: ease-in-out; }
  84.17% { translate: calc(342 * var(--bu)) calc(178 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  85.17% { translate: calc(342 * var(--bu)) calc(178 * var(--bu)); scale: 0.84; opacity: 1; animation-timing-function: linear; }
  86.5% { translate: calc(342 * var(--bu)) calc(178 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: linear; }
  88.33% { translate: calc(342 * var(--bu)) calc(178 * var(--bu)); scale: 1; opacity: 1; animation-timing-function: ease-in-out; }
  99.17% { translate: calc(372 * var(--bu)) calc(320 * var(--bu)); scale: 1; opacity: 0; animation-timing-function: linear; }
  100% { translate: calc(372 * var(--bu)) calc(320 * var(--bu)); scale: 1; opacity: 0; }
}
/* the run's progress, painted under the work, as on the board */
.cs-node-well::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: calc(3 * var(--bu));
  background: #49e0f5;
  transform-origin: 0 50%;
  scale: 0 1;
  opacity: 0;
}
@keyframes cs-run { 0% { scale: 0 1; opacity: 1; } 85% { scale: 1 1; opacity: 1; } 100% { scale: 1 1; opacity: 0; } }
.cs-replay { grid-column: 1 / -1; justify-self: center; margin-top: calc(4 * var(--u)); background: var(--surface); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; cursor: pointer; }
@media (hover: hover) { .cs-replay:hover { background: var(--tint); } }
.cs-replay svg { transition: rotate var(--t-pop) var(--spring-pop); }
@media (hover: hover) { .cs-replay:hover svg { rotate: -120deg; translate: 0 0 !important; } }

/* ---- Next Level: the interview, answered as the chat answers ----
   Choosing a question puts it up in blue at once; Sebastien's answer
   waits behind three dots for a beat, and then arrives. */
.cs-interview-stage .cs-bubbles { grid-template-areas: 'q' 'a'; }
.cs-interview-stage .is-q { grid-area: q; }
.cs-interview-stage .is-a, .cs-interview-stage .cs-typing { grid-area: a; }
.cs-interview-stage .cs-typing { display: inline-flex; visibility: hidden; }
.cs-interview-stage > [data-on] .is-q { animation: cs-pop-in 0.45s var(--spring-pop) 0.05s both; }
.cs-interview-stage > [data-on] .cs-typing { visibility: visible; animation: cs-typing-life 0.95s linear 0.35s both; }
.cs-interview-stage > [data-on] .is-a { animation: cs-pop-in 0.5s var(--spring-pop) 1.2s both; }
.cs-interview-stage .cs-typing { background: var(--pill); color: var(--bubble-ink); }

/* ---- Next Level: nine versions, as a design tool keeps them ----
   The chosen version stands big on the left; the history runs down the
   right, grouped by direction, with the client's two notes where he left
   them. It walks itself while in view, as the other steppers do. */
.cs-history {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc(320 * var(--u));
  gap: var(--gap);
  padding: var(--gap);
}
.cs-tile.cs-history > * { margin-top: 0; }
.cs-history-stage {
  position: relative;
  min-height: calc(420 * var(--u));
  border-radius: calc(24 * var(--u));
  background: #fff;
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent);
  overflow: hidden;
}
.cs-history-stage > figure {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  justify-items: center;
  padding: calc(28 * var(--u)) calc(32 * var(--u)) calc(22 * var(--u));
}
.cs-history-stage img { align-self: center; width: auto; max-width: 90%; height: auto; max-height: calc(340 * var(--u)); object-fit: contain; }
.cs-history-stage figcaption { display: grid; justify-items: center; gap: calc(6 * var(--u)); text-align: center; }
.cs-history-stage figcaption b { font-weight: inherit; color: var(--pastel-ink); }
.cs-history-stage figcaption span { font-size: var(--t-small); line-height: 1.3; letter-spacing: 0; color: var(--tile-ink); max-width: 26em; text-wrap: balance; }
.cs-history-list { display: grid; align-content: start; gap: calc(2 * var(--u)); list-style: none; }
.cs-history-list .cs-history-group {
  margin: calc(8 * var(--u)) 0 calc(1 * var(--u));
  padding-left: calc(10 * var(--u));
  font-size: calc(15 * var(--u));
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--tile-ink-2);
}
.cs-history-list .cs-history-group:first-child { margin-top: 0; }
.cs-version {
  display: grid;
  grid-template-columns: calc(34 * var(--u)) minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(10 * var(--u));
  width: 100%;
  padding: calc(3 * var(--u)) calc(10 * var(--u)) calc(3 * var(--u)) calc(4 * var(--u));
  border-radius: calc(12 * var(--u));
  text-align: left;
  color: var(--tile-ink);
  transition: background-color 0.25s ease, color 0.25s ease;
}
.cs-version img { width: calc(34 * var(--u)); height: calc(34 * var(--u)); object-fit: contain; border-radius: calc(8 * var(--u)); background: #fff; padding: calc(2 * var(--u)); }
.cs-version > span { font-size: var(--t-small); line-height: 1.25; letter-spacing: 0; min-width: 0; }
.cs-version > i { font-style: normal; font-size: calc(15 * var(--u)); color: var(--tile-ink-2); font-variant-numeric: tabular-nums; }
@media (hover: hover) { .cs-version:not([aria-selected='true']):hover { background: rgb(255 255 255 / 0.4); color: var(--pastel-ink); } }
.cs-version[aria-selected='true'] { background: #fff; color: var(--pastel-ink); box-shadow: 0 calc(8 * var(--u)) calc(18 * var(--u)) calc(-12 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent); }
.cs-version.is-shipped > i { color: #fff; background: var(--deep); padding: calc(3 * var(--u)) calc(8 * var(--u)); border-radius: 99px; }
/* the client's notes, where he left them in the history */
.cs-history-note {
  display: grid;
  grid-template-columns: calc(28 * var(--u)) minmax(0, 1fr);
  gap: calc(8 * var(--u));
  align-items: start;
  margin: calc(4 * var(--u)) 0;
  padding: 0 calc(4 * var(--u));
}
.cs-history-note img { width: calc(28 * var(--u)); height: calc(28 * var(--u)); border-radius: 50%; object-fit: cover; object-position: 50% 20%; background: #fff; }
.cs-history-note p {
  padding: calc(7 * var(--u)) calc(12 * var(--u));
  border-radius: calc(4 * var(--u)) calc(16 * var(--u)) calc(16 * var(--u)) calc(16 * var(--u));
  background: #fff;
  font-size: calc(15.5 * var(--u));
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--bubble-ink);
  text-wrap: pretty;
}

/* each colorway's colour, sampled from its own badge, under it */
.cs-colorway-swatch { grid-auto-flow: column; justify-content: start; align-items: center; gap: calc(10 * var(--u)); }

/* ---- Next Level: why the ninth, at every size ----
   The last character badge beside the badge that shipped, both shrunk
   together by one slider (js/case.js), from a print down to a favicon. */
.cs-scale { display: grid; gap: calc(20 * var(--u)); }
.cs-scale-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); }
.cs-scale-pair figure { display: grid; gap: calc(12 * var(--u)); }
.cs-scale-well { height: calc(300 * var(--u)); }
/* the picture is drawn at the slider's size, capped by its well so a
   phone's narrower well still holds the biggest setting whole */
.cs-scale-well img { width: min(calc(var(--s, 200) * var(--u)), 88%); height: auto; max-width: none; object-fit: contain; }
/* the version over what it is (side by side, each broke in two in a half
   of the column: "v8 · the line / drone" beside "thin lines, lettering
   round / the ring") */
.cs-scale-pair figcaption { display: grid; gap: calc(3 * var(--u)); font-size: var(--t-small); line-height: 1.3; letter-spacing: 0; color: var(--tile-ink); }
.cs-scale-pair figcaption b { font-weight: inherit; color: var(--pastel-ink); }
.cs-scale-control { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: calc(16 * var(--u)); }
.cs-scale-control span { font-size: var(--t-small); line-height: 1; letter-spacing: 0; color: var(--tile-ink-2); font-variant-numeric: tabular-nums; }
.cs-scale-control output { min-width: 4.5em; text-align: right; font-size: var(--t-small); letter-spacing: 0; color: var(--pastel-ink); font-variant-numeric: tabular-nums; }
.cs-scale-control input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: calc(28 * var(--u));
  background: transparent;
  cursor: pointer;
}
.cs-scale-control input[type='range']::-webkit-slider-runnable-track { height: calc(6 * var(--u)); border-radius: 99px; background: linear-gradient(to right, var(--deep) var(--p, 50%), rgb(255 255 255 / 0.7) var(--p, 50%)); }
.cs-scale-control input[type='range']::-moz-range-track { height: calc(6 * var(--u)); border-radius: 99px; background: rgb(255 255 255 / 0.7); }
.cs-scale-control input[type='range']::-moz-range-progress { height: calc(6 * var(--u)); border-radius: 99px; background: var(--deep); }
.cs-scale-control input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  margin-top: calc(-10 * var(--u));
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--deep) 20%, transparent), 0 calc(4 * var(--u)) calc(10 * var(--u)) color-mix(in oklab, var(--deep) 35%, transparent);
}
.cs-scale-control input[type='range']::-moz-range-thumb {
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  border: 0;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--deep) 20%, transparent), 0 calc(4 * var(--u)) calc(10 * var(--u)) color-mix(in oklab, var(--deep) 35%, transparent);
}
.cs-scale-control input[type='range']:focus-visible { outline: 2px solid var(--deep); outline-offset: 4px; border-radius: 99px; }

@media (prefers-reduced-motion: reduce) {
  .cs-ways.is-playing *, .cs-interview-stage > [data-on] *, .cs-spec *, .cs-live-dot, .cs-pill[data-run] svg, .cs-site-page img { animation: none !important; }
  .cs-ways.is-playing .cs-typing, .cs-interview-stage .cs-typing { display: none !important; }
}

/* The living pieces in a narrow lane: side-by-side pieces stack, and rows
   scroll sideways. */
@container lane (max-width: 500px) {
  .cs-store { grid-template-columns: repeat(5, 200px); overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
  .cs-store li { scroll-snap-align: start; }
  .cs-phonestage-restart { padding: 7px 14px; }
  /* on a phone the masthead's buttons stand over the lane, so the phone
     lands under them, as any chapter does, and stands no taller than it is */
  #try.cs-phonesec { scroll-margin-top: calc(var(--cs-top) + 24 * var(--u) - var(--sec-pad)); }
  .cs-history { grid-template-columns: minmax(0, 1fr); padding: 16px; }
  .cs-history-stage { min-height: 360px; }
  /* the two badges stay side by side, to be shrunk and compared at the
     same moment (one over the other, the one being read was always half
     a screen from the other), in shorter wells */
  .cs-scale-well { height: 180px; }
  .cs-sweep-labels { display: none; }
}
@media (max-width: 760px) {
  /* the floors that keep a desktop row of tiles level leave a phone's
     single column full of air: there the words set the height */
  .cs-stat { min-height: 0; gap: 18px; }
}

/* ======================================================================
   The chapters
   What holds a story's parts apart and in order: each chapter's number,
   in its own case's language; the list of them in the lane's left
   margin; and the few pieces every chapter tells its numbers and its
   pictures with.
   ====================================================================== */

/* ---- the chapters' numbers ----
   By default a number stands in a capsule of the case's colour, in its
   deep ink. Each case then draws it in its own product's hand. */
.cs-chapter-num {
  flex: none;
  display: inline-grid;
  place-items: center;
  min-width: calc(44 * var(--u));
  height: calc(44 * var(--u));
  padding: 0 calc(14 * var(--u));
  border-radius: 999px;
  background: var(--tint);
  color: var(--deep);
  font-size: var(--t-name);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* a chapter outside the dated story carries a word, at the small size */
.cs-chapter-num.is-word { font-size: var(--t-small); letter-spacing: 0.01em; }

/* PantryPal: the app's own sticker type. The number is Fugaz One in the
   app's coral, outlined in its ink and set down on a hard ink shadow, a
   little askew, the way the app's own drawings are stuck on; a word is
   one of the app's white buttons, ink-ringed, as "Dinner!" is. */
[data-case='pantrypal'] .cs-chapter-num {
  min-width: 0;
  height: auto;
  padding: 0;
  border-radius: 0;
  background: none;
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  font-size: calc(50 * var(--u));
  line-height: 1;
  letter-spacing: 0.01em;
  color: #ff7e7d;
  -webkit-text-stroke: calc(5 * var(--u)) var(--mark);
  paint-order: stroke fill;
  filter: drop-shadow(0 calc(4 * var(--u)) 0 var(--mark));
  rotate: -5deg;
  translate: 0 calc(-4 * var(--u));
}
[data-case='pantrypal'] .cs-chapter-num.is-word {
  height: calc(42 * var(--u));
  padding: 0 calc(20 * var(--u));
  border-radius: 999px;
  background: #fff;
  box-shadow: inset 0 0 0 calc(2.5 * var(--u)) var(--mark), 0 calc(4 * var(--u)) 0 var(--mark);
  font-size: calc(22 * var(--u));
  color: var(--mark);
  -webkit-text-stroke: 0;
  filter: none;
  rotate: -2deg;
  translate: 0 calc(-2 * var(--u));
}

/* Vicino: a node on the board. The number is a card's header (the
   cargo's colour in its swatch, the number in the board's own weight),
   its output port on the card's right edge, and the hairline is the wire
   that leaves it, carrying a spark to the date at its other end. A short
   wire comes down into the card from the chapter before, so the chapters
   read as one pipeline down the page: the thing, then its language, then
   the machines, then the pen. */
[data-case='vicino'] .cs-chapter-top { position: relative; }
[data-case='vicino'] .cs-chapter-num {
  position: relative;
  gap: calc(9 * var(--u));
  grid-auto-flow: column;
  height: calc(40 * var(--u));
  padding: 0 calc(16 * var(--u)) 0 calc(10 * var(--u));
  border-radius: calc(13 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.08),
    0 calc(12 * var(--u)) calc(26 * var(--u)) calc(-16 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: 0;
  color: #1d1d1f;
}
[data-case='vicino'] .cs-chapter-num::before {
  content: '';
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: calc(7 * var(--u));
  background: color-mix(in oklab, var(--port, #8bd6d9) 30%, #fff);
  box-shadow: inset 0 0 0 calc(5 * var(--u)) var(--port, #8bd6d9);
}
[data-case='vicino'] .cs-chapter-num::after {
  content: '';
  position: absolute;
  right: calc(-4 * var(--u));
  top: 50%;
  width: calc(8 * var(--u));
  height: calc(20 * var(--u));
  translate: 0 -50%;
  border-radius: calc(4 * var(--u));
  background: var(--port, #8bd6d9);
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
}
[data-case='vicino'] .cs-chapter-rule {
  position: relative;
  height: calc(2 * var(--u));
  margin-left: calc(-14 * var(--u));
  border-radius: 99px;
  background: color-mix(in oklab, var(--port, #8bd6d9) 70%, #fff);
}
/* the spark, running the wire once the chapter is in, and again and again */
[data-case='vicino'] .cs-chapter-rule::after {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: calc(9 * var(--u));
  height: calc(9 * var(--u));
  translate: 0 -50%;
  border-radius: 50%;
  background: var(--port, #8bd6d9);
  box-shadow: 0 0 0 calc(4 * var(--u)) color-mix(in oklab, var(--port, #8bd6d9) 25%, transparent);
  opacity: 0;
}
[data-case='vicino'] .cs-chapter.is-risen .cs-chapter-rule::after { animation: cs-wire-spark 3.6s var(--ease-draw) 1.1s infinite; }
@keyframes cs-wire-spark {
  0% { left: 0; opacity: 0; }
  6% { opacity: 1; }
  52% { left: calc(100% - 9 * var(--u)); opacity: 1; }
  60%, 100% { left: calc(100% - 9 * var(--u)); opacity: 0; }
}
/* the date is the input port of the next card along */
[data-case='vicino'] .cs-chapter-when {
  display: inline-flex;
  align-items: center;
  height: calc(30 * var(--u));
  padding: 0 calc(12 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.08);
  color: #5b6472;
}
/* the wire in from the chapter before, falling into the card's top */
[data-case='vicino'] .cs-sec:not(.is-part) .cs-chapter .cs-chapter-num > i {
  position: absolute;
  left: calc(22 * var(--u));
  bottom: 100%;
  width: calc(2 * var(--u));
  height: calc(var(--air-chapter) - 40 * var(--u));
  background: linear-gradient(to bottom, transparent, color-mix(in oklab, var(--port, #8bd6d9) 70%, #fff));
  pointer-events: none;
}
[data-case='vicino'] .cs-sec:not(.is-part) .cs-chapter .cs-chapter-num > i::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: calc(-4 * var(--u));
  width: calc(20 * var(--u));
  height: calc(8 * var(--u));
  translate: -50% 0;
  border-radius: calc(4 * var(--u));
  background: var(--port, #8bd6d9);
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
}

/* Next Level: the badge's ring. The number stands bold in the brand's
   navy inside a hairline circle of its blue, with the badge's second
   ring arcing round its right side, and the hairline is a construction
   line, ticked like a ruler, as the guides in a brand book are. */
[data-case='nextlevel'] .cs-chapter-num {
  position: relative;
  min-width: 0;
  width: calc(48 * var(--u));
  height: calc(48 * var(--u));
  padding: 0;
  border-radius: 50%;
  background: #fff;
  box-shadow: inset 0 0 0 calc(2 * var(--u)) #0495eb;
  font-size: var(--t-name);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: #0d2a4d;
}
[data-case='nextlevel'] .cs-chapter-num::after {
  content: '';
  position: absolute;
  inset: calc(-7 * var(--u));
  border-radius: 50%;
  border: calc(1.5 * var(--u)) solid transparent;
  border-right-color: #0d2a4d;
  border-top-color: color-mix(in oklab, #0d2a4d 0%, transparent);
  rotate: -20deg;
}
[data-case='nextlevel'] .cs-chapter-num.is-word {
  width: auto;
  padding: 0 calc(20 * var(--u));
  border-radius: 999px;
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
[data-case='nextlevel'] .cs-chapter-num.is-word::after { display: none; }
[data-case='nextlevel'] .cs-chapter-rule {
  height: calc(9 * var(--u));
  background:
    linear-gradient(#0495eb, #0495eb) 0 50% / 100% 1px no-repeat,
    repeating-linear-gradient(to right, color-mix(in oklab, #0495eb 55%, transparent) 0 1px, transparent 1px calc(24 * var(--u))) 0 0 / 100% 100% no-repeat;
  -webkit-mask: linear-gradient(to right, #000 70%, transparent);
  mask: linear-gradient(to right, #000 70%, transparent);
  opacity: 0.6;
}
[data-case='nextlevel'] .cs-chapter-when { color: #0b6db0; }

/* ---- the rail: the chapters, down the lane's left margin ----
   Under the back button, in the margin the lane leaves on the left, every
   chapter of the story: the one being read marked, the ones before it
   done, and a runner of the case's own (a hat, a spark, a drone) that
   travels to the one being read; pressed, a chapter goes there. It is the
   page's one sign of where you are, and of how far: its head counts the
   chapters read. It stands in the page right after the opening tile, a
   box no height at all that sticks a little under the masthead, with the
   list hung from it, so it comes up from under the tile's foot as the tile
   scrolls away and then holds still while the story scrolls past beside
   it (js/case.js builds it from the chapters' openers). (It was a plain
   list, its marks the case's deep colour; before that a column of marks at
   the window's very edge that said a chapter's name only when pointed at.)
   A phone has no margin for it: there the reading ring round the back
   button says how far you are. */
.cs-main > .cs-rail {
  /* hung as far under the tile's foot as the overview's first line, so
     it comes up level with the story */
  --rail-drop: calc(112 * var(--u));
  position: sticky;
  top: calc(var(--cs-top) + 8 * var(--u) - var(--rail-drop));
  z-index: 2;
  width: var(--rail-w);
  max-width: none;
  height: 0;
  margin: 0 0 0 calc(var(--gutter-l) - var(--lane-l));
}
.cs-rail-in {
  position: absolute;
  left: 0;
  top: var(--rail-drop);
  width: var(--rail-w);
}
/* the count first, standing over the column of the chapters' marks, and
   the rail's name after it, over their names: so the count is what is
   left when the rail folds (below), in the column it heads */
.cs-rail-head { display: flex; align-items: center; gap: calc(8 * var(--u)); }
.cs-rail-count { order: -1; flex: none; display: flex; align-items: center; justify-content: center; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cs-rail-count b { font-weight: inherit; }
/* one column exactly the panel's width, so a row folds with the panel
   rather than holding out at its names' width */
.cs-rail-list { position: relative; z-index: 1; display: grid; grid-template-columns: minmax(0, 1fr); list-style: none; }
.cs-rail-list a {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  -webkit-tap-highlight-color: transparent;
}
.cs-rail-num { display: grid; place-items: center; font-variant-numeric: tabular-nums; }
.cs-rail-name { overflow: hidden; white-space: nowrap; text-overflow: clip; }
.cs-rail-tick { display: grid; place-items: center; }
.cs-rail-tick svg { fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.cs-rail-list a:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }
/* the runner: where the chapter being read is (--y, its middle), and
   only once a chapter is being read */
.cs-rail-runner {
  position: absolute;
  z-index: 2;
  left: 0;
  top: 0;
  translate: 0 var(--y, 0px);
  opacity: 0;
  pointer-events: none;
  transition: translate var(--t-settle) var(--spring-settle), opacity 0.3s ease;
}
.cs-rail.is-started .cs-rail-runner { opacity: 1; }
.cs-rail-runner i { display: block; width: 100%; height: 100%; }
@media (max-width: 760px) { .cs-rail { display: none; } }

/* ---- the rail, folded ----
   Where a pointer can hover, the rail stands folded to a column as wide
   as the back button over it: the count of chapters read at its head and
   each chapter's mark under it, the one being read marked and the ones
   before it done, each in its case's dress, and the runner still going
   from one to the next. Pointed at, or reached with the keyboard, it
   opens to its full width into the margin kept empty for it (above, "the
   lane"), lifting a little off the page as it does, its names and its
   rail's name coming in once there is room for them; it never reaches the
   story. It waits a moment before it opens, so a pointer only passing
   over it on its way to the back button leaves it be, and a moment longer
   before it folds, so a pointer that slips off its edge does not snap it
   shut. Only its width moves; its rows keep their heights, so the runner
   stays put on its chapter. (It stood open all the time, 184 wide; then
   for a day it opened over the story's first words.) On a touch screen,
   which has no pointer to hover with, it stands open, as it did. */
@media (min-width: 761px) and (hover: hover) {
  .cs-rail-in {
    /* the shadow it lifts off the page with, open; nothing, folded */
    --rail-lift: 0 0 0 0 transparent;
    transition:
      width 0.46s var(--ease-rise) 0.22s,
      box-shadow 0.34s ease 0.22s;
  }
  .cs-rail:is(:hover, :focus-within) .cs-rail-in {
    --rail-lift: 0 calc(22 * var(--u)) calc(40 * var(--u)) calc(-22 * var(--u)) rgb(30 30 30 / 0.2);
    width: var(--rail-open);
    transition-delay: 0.12s, 0.12s;
  }
  /* the words come in once the rail is wide enough for them, and go
     first when it folds, so a name is never seen half cut */
  .cs-rail-title, .cs-rail-name, .cs-rail-tick {
    opacity: 0;
    translate: calc(-6 * var(--u)) 0;
    transition: opacity 0.14s ease, translate 0.3s var(--ease-rise);
  }
  .cs-rail:is(:hover, :focus-within) :is(.cs-rail-title, .cs-rail-name, .cs-rail-tick) {
    opacity: 1;
    translate: 0 0;
    transition: opacity 0.24s ease 0.29s, translate 0.42s var(--ease-rise) 0.25s;
  }
}
@media (min-width: 761px) and (hover: hover) and (prefers-reduced-motion: reduce) {
  .cs-rail-in, .cs-rail:is(:hover, :focus-within) .cs-rail-in { transition-duration: 0.01s; transition-delay: 0s; }
  .cs-rail-title, .cs-rail-name, .cs-rail-tick { translate: 0 0; }
}

/* ---- PantryPal's rail: the recipe ----
   The app's own recipe screen, small: a card ringed in ink on a hard ink
   shadow, "Recipe" outlined in the app's sticker type with the count of
   steps done in the app's own pill (it goes green when the last is), and
   every chapter one of the app's steps. A step to come is plain white; the
   step being read is the app's live step, its head coral and its number
   cell green, lifted onto its shadow; a step done goes the app's steel and
   a step quieter, ticked green. The chef's hat sits in the step being
   read, where its tick will go, and hops into the next. The chapters without a number carry one of
   the app's drawings instead: the tomato thrown away, a live dot for the
   app running on the page, and the cheeseburger, order up. */
[data-case='pantrypal'] .cs-rail-in {
  /* 13 a side: a step's number cell, 30 with its ring, stands in the
     middle of the folded rail's 56, under the back button's middle */
  padding: calc(12 * var(--u)) calc(13 * var(--u)) calc(12 * var(--u));
  border-radius: calc(18 * var(--u));
  background: #fffdf8;
  box-shadow: inset 0 0 0 calc(2 * var(--u)) var(--mark), 0 calc(4 * var(--u)) 0 var(--mark), var(--rail-lift, 0 0 0 0 transparent);
  font-family: 'PP Fugaz One', system-ui, sans-serif;
  letter-spacing: 0.01em;
  color: var(--mark);
}
[data-case='pantrypal'] .cs-rail-head { gap: calc(7 * var(--u)); margin: 0 0 calc(11 * var(--u)); }
[data-case='pantrypal'] .cs-rail-title {
  font-size: calc(21 * var(--u));
  line-height: 1.1;
  color: #fff;
  -webkit-text-stroke: calc(3.4 * var(--u)) var(--mark);
  paint-order: stroke fill;
}
[data-case='pantrypal'] .cs-rail-count {
  /* as wide as a step's cell, over the column of them */
  width: calc(30 * var(--u));
  padding: calc(3 * var(--u)) 0;
  border-radius: 99px;
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--mark);
  font-size: max(10px, calc(11 * var(--u)));
  line-height: 1;
  transition: background-color 0.2s ease;
}
[data-case='pantrypal'] .cs-rail.is-finished .cs-rail-count { background: #b4ff85; }
[data-case='pantrypal'] .cs-rail-list { gap: calc(7 * var(--u)); }
[data-case='pantrypal'] .cs-rail-list a {
  grid-template-columns: calc(27 * var(--u)) minmax(0, 1fr) auto;
  column-gap: calc(8 * var(--u));
  height: calc(30 * var(--u));
  padding-right: calc(7 * var(--u));
  overflow: hidden;
  /* a border, not an inset shadow: the number cell's own paper would
     cover a shadow on its side */
  border: calc(1.5 * var(--u)) solid var(--mark);
  border-radius: calc(9 * var(--u));
  background-color: #fff;
  font-size: max(11.5px, calc(13 * var(--u)));
  line-height: 1;
  color: var(--mark);
  transition: background-color 0.25s ease, box-shadow 0.25s ease, opacity 0.25s ease, translate var(--t-pop) var(--spring-pop);
}
[data-case='pantrypal'] .cs-rail-num {
  align-self: stretch;
  border-right: calc(1.5 * var(--u)) solid var(--mark);
  background-color: #fff;
  background-position: center;
  background-size: 72%;
  background-repeat: no-repeat;
  font-size: max(10.5px, calc(12 * var(--u)));
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.2s ease, background-size 0.2s ease;
}
[data-case='pantrypal'] a[href='#problem'] .cs-rail-num { background-image: url(../assets/case/pantrypal/app/art/tomato.webp); }
[data-case='pantrypal'] a[href='#results'] .cs-rail-num { background-image: url(../assets/case/pantrypal/app/art/cheddar-cheeseburger.webp); background-size: 84%; }
[data-case='pantrypal'] a[href='#try'] .cs-rail-num::before {
  content: '';
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  border-radius: 50%;
  background: #ff4b4b;
  box-shadow: 0 0 0 calc(3 * var(--u)) rgb(255 75 75 / 0.22);
  animation: cs-live 2s ease-in-out infinite;
}
[data-case='pantrypal'] .cs-rail-tick {
  width: calc(16 * var(--u));
  height: calc(16 * var(--u));
  border-radius: 50%;
  border: 1px dashed var(--mark);
  transition: background-color 0.2s ease, border-color 0.2s ease, scale var(--t-pop) var(--spring-pop);
}
[data-case='pantrypal'] .cs-rail-tick svg { width: 72%; height: 72%; stroke-width: 3.4; opacity: 0; transition: opacity 0.2s ease; }
[data-case='pantrypal'] .cs-rail-list a.is-done { background-color: #ececec; opacity: 0.72; }
[data-case='pantrypal'] .cs-rail-list a.is-done .cs-rail-num { background-color: #cdcdcd; }
[data-case='pantrypal'] .cs-rail-list a.is-done .cs-rail-tick { border: calc(1.5 * var(--u)) solid var(--mark); background: #b4ff85; scale: 1.08; }
[data-case='pantrypal'] .cs-rail-list a.is-done .cs-rail-tick svg { opacity: 1; }
[data-case='pantrypal'] .cs-rail-list a[aria-current='step'] {
  background-color: #ff7e7d;
  box-shadow: 0 calc(3 * var(--u)) 0 var(--mark);
  translate: 0 calc(-2 * var(--u));
}
[data-case='pantrypal'] .cs-rail-list a[aria-current='step'] .cs-rail-num { background-color: #b4ff85; }
/* the hat stands where the tick will be */
[data-case='pantrypal'] .cs-rail-list a[aria-current='step'] .cs-rail-tick { opacity: 0; }
@media (hover: hover) {
  [data-case='pantrypal'] .cs-rail-list a:not([aria-current]):hover { background-color: #ffeec4; opacity: 1; }
}
/* the hat, in the step being read, at its far end where the tick will
   go (so it never sits over a neighbour); travelling, it hops. (It sat
   on the step's corner, its brim on the card's top edge, and its crown
   covered the number of the step above.) */
[data-case='pantrypal'] .cs-rail-runner {
  /* centred on the tick's place, at the step's far end: the rail's width
     less its padding, the step's ring and padding, and half the tick */
  left: calc(var(--rail-open) - 43 * var(--u));
  top: calc(-14 * var(--u));
  width: calc(27 * var(--u));
  height: calc(26 * var(--u));
}
/* Folded, the hat stands in the cell of the step being read, a size down,
   in place of its number: the column of steps reads down to the one being
   cooked, and the hat hops on down the column to the next. Opening, it
   slides out along the step to where the tick will go. A cell's own
   divider goes too, so each cell is a whole ringed square. */
@media (min-width: 761px) and (hover: hover) {
  [data-case='pantrypal'] .cs-rail-runner {
    transition:
      translate var(--t-settle) var(--spring-settle),
      opacity 0.3s ease,
      left 0.46s var(--ease-rise) 0.22s,
      top 0.46s var(--ease-rise) 0.22s,
      scale 0.3s var(--ease-rise) 0.22s;
  }
  [data-case='pantrypal'] .cs-rail:is(:hover, :focus-within) .cs-rail-runner { transition-delay: 0s, 0s, 0.12s, 0.12s, 0.12s; }
  [data-case='pantrypal'] .cs-rail:not(:hover, :focus-within) .cs-rail-runner { left: calc(28 * var(--u) - 13.5 * var(--u)); top: calc(-13 * var(--u)); scale: 0.78; }
  [data-case='pantrypal'] .cs-rail:not(:hover, :focus-within) .cs-rail-num { border-right-color: transparent; }
  [data-case='pantrypal'] .cs-rail:not(:hover, :focus-within) .cs-rail-list a[aria-current='step'] .cs-rail-num { color: transparent; background-size: 0; }
  [data-case='pantrypal'] .cs-rail:not(:hover, :focus-within) .cs-rail-list a[aria-current='step'] .cs-rail-num::before { opacity: 0; }
}
[data-case='pantrypal'] .cs-rail-runner i {
  background: url(../assets/case/pantrypal/app/hat.webp) center / contain no-repeat;
  rotate: -10deg;
  filter: drop-shadow(0 calc(2 * var(--u)) 0 rgb(30 30 30 / 0.3));
}
[data-case='pantrypal'] .cs-rail.is-moving .cs-rail-runner i { animation: cs-hat-hop 0.64s var(--ease-rise); }
@keyframes cs-hat-hop {
  0% { translate: 0 0; rotate: -10deg; }
  34% { translate: calc(-6 * var(--u)) calc(-16 * var(--u)); rotate: 14deg; }
  72% { translate: 0 calc(2 * var(--u)); rotate: -20deg; }
  100% { translate: 0 0; rotate: -10deg; }
}

/* ---- Vicino's rail: the story, run as a pipeline ----
   Canvas's own board, small: the dotted stage, the board's run pill at its
   head ("Story run", and how far the run has got), and every chapter a
   node, its swatch in its cargo's colour (the chapters' own, as on their
   openers), wired top to bottom through ports of the same colours. A node
   to come is queued, dashed and quiet; the one being read is running,
   ringed in the case's deep colour with its progress painting under it as
   a run's does on the board; a node done has earned its green check. The
   spark runs down the wire to the node being read. */
[data-case='vicino'] .cs-rail-in {
  /* the wire runs down the folded rail's middle, under the back button's:
     9 of padding, a node's 6, and half its swatch */
  --port-x: calc(28 * var(--u));
  padding: calc(12 * var(--u)) calc(9 * var(--u)) calc(14 * var(--u));
  border-radius: calc(18 * var(--u));
  background:
    radial-gradient(circle, rgb(15 23 42 / 0.1) calc(1 * var(--u)), transparent calc(1.5 * var(--u))) 0 0 / calc(14 * var(--u)) calc(14 * var(--u)),
    #f5f8f8;
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.06), var(--rail-lift, 0 0 0 0 transparent);
}
/* the wire, under the nodes, from the first's port to the last's */
[data-case='vicino'] .cs-rail-in::before {
  content: '';
  position: absolute;
  left: calc(var(--port-x) - 1 * var(--u));
  top: var(--y0, 0px);
  width: calc(2 * var(--u));
  height: calc(var(--y1, 0px) - var(--y0, 0px));
  background: linear-gradient(#8bd6d9, #9b9cf1, #ffb366, #7cc0e8);
}
[data-case='vicino'] .cs-rail-head { margin-bottom: calc(12 * var(--u)); }
[data-case='vicino'] .cs-rail-title {
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(24 * var(--u));
  padding: 0 calc(10 * var(--u)) 0 calc(8 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.08);
  font-size: max(11px, calc(12 * var(--u)));
  font-weight: 600;
  letter-spacing: 0;
  color: #1d1d1f;
}
[data-case='vicino'] .cs-rail-title::before {
  content: '';
  border-left: calc(7 * var(--u)) solid #6366f1;
  border-block: calc(4.5 * var(--u)) solid transparent;
}
[data-case='vicino'] .cs-rail-head { gap: calc(6 * var(--u)); }
/* the count, a chip as wide as a node, over the column of them */
[data-case='vicino'] .cs-rail-count {
  width: calc(38 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.08);
  font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
  font-size: max(10px, calc(11 * var(--u)));
  color: #5b6472;
}
[data-case='vicino'] .cs-rail-list { gap: calc(14 * var(--u)); }
[data-case='vicino'] .cs-rail-list li:nth-child(1) { --port: #8bd6d9; }
[data-case='vicino'] .cs-rail-list li:nth-child(2) { --port: #9b9cf1; }
[data-case='vicino'] .cs-rail-list li:nth-child(3) { --port: #ffb366; }
[data-case='vicino'] .cs-rail-list li:nth-child(4) { --port: #7cc0e8; }
[data-case='vicino'] .cs-rail-list li:nth-child(5) { --port: #8bd6d9; }
[data-case='vicino'] .cs-rail-list a {
  grid-template-columns: calc(26 * var(--u)) minmax(0, 1fr) auto;
  /* (at 8, "The AI guide" was a pixel too wide for its place in a window
     whose frame unit is one, 1280 wide or 700 tall, and came out "The AI
     gui…") */
  column-gap: calc(7 * var(--u));
  min-height: calc(32 * var(--u));
  /* 6 a side, so a folded node is its swatch and a frame of 6 round it */
  padding: calc(6 * var(--u));
  border-radius: calc(10 * var(--u));
  background: #fff no-repeat 0 100% / 0 calc(2.5 * var(--u));
  background-image: linear-gradient(#49e0f5, #49e0f5);
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.08),
    0 calc(8 * var(--u)) calc(18 * var(--u)) calc(-12 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
  font-size: var(--t-small);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0;
  color: #1d1d1f;
  transition: box-shadow 0.25s ease, opacity 0.25s ease, color 0.25s ease;
}
/* its ports, in and out, on the wire */
[data-case='vicino'] .cs-rail-list a::before,
[data-case='vicino'] .cs-rail-list a::after {
  content: '';
  position: absolute;
  left: calc(var(--port-x) - 9 * var(--u) - 7 * var(--u));
  width: calc(14 * var(--u));
  height: calc(5 * var(--u));
  border-radius: calc(3 * var(--u));
  background: var(--port);
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
}
[data-case='vicino'] .cs-rail-list a::before { top: calc(-2.5 * var(--u)); }
[data-case='vicino'] .cs-rail-list a::after { bottom: calc(-2.5 * var(--u)); }
[data-case='vicino'] .cs-rail-list li:first-child a::before,
[data-case='vicino'] .cs-rail-list li:last-child a::after { display: none; }
/* the swatch: the node's type, in its cargo's colour, with its number */
[data-case='vicino'] .cs-rail-num {
  height: calc(18 * var(--u));
  border-radius: calc(5 * var(--u));
  background: color-mix(in oklab, var(--port) 34%, #fff);
  box-shadow: inset 0 0 0 calc(1.5 * var(--u)) var(--port);
  font-size: max(9px, calc(10 * var(--u)));
  font-weight: 700;
  color: #1d1d1f;
}
[data-case='vicino'] .cs-rail-num:empty::before { content: '→'; font-size: max(10px, calc(11 * var(--u))); }
[data-case='vicino'] .cs-rail-tick {
  width: calc(15 * var(--u));
  height: calc(15 * var(--u));
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.16);
  color: #fff;
  transition: background-color 0.25s ease, box-shadow 0.25s ease, scale var(--t-pop) var(--spring-pop);
}
[data-case='vicino'] .cs-rail-tick svg { width: 70%; height: 70%; stroke-width: 3.2; opacity: 0; transition: opacity 0.2s ease; }
/* queued */
[data-case='vicino'] .cs-rail-list a:not(.is-done):not([aria-current]) { color: #5b6472; opacity: 0.78; }
[data-case='vicino'] .cs-rail-list a:not(.is-done):not([aria-current]) .cs-rail-num { background: #fff; }
/* running: ringed, its progress painting under it, its status turning */
[data-case='vicino'] .cs-rail-list a[aria-current='step'] {
  box-shadow:
    0 0 0 calc(1.5 * var(--u)) var(--deep),
    0 calc(10 * var(--u)) calc(22 * var(--u)) calc(-12 * var(--u)) color-mix(in oklab, var(--deep) 55%, transparent);
  animation: cs-node-run 1.3s var(--ease-draw) 0.2s both;
}
@keyframes cs-node-run { from { background-size: 0 calc(2.5 * var(--u)); } to { background-size: 100% calc(2.5 * var(--u)); } }
[data-case='vicino'] .cs-rail-list a[aria-current='step'] .cs-rail-tick {
  box-shadow: none;
  background: conic-gradient(#49e0f5 0 25%, rgb(73 224 245 / 0.18) 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5 * var(--u)), #000 calc(100% - 2 * var(--u)));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.5 * var(--u)), #000 calc(100% - 2 * var(--u)));
  animation: cs-spin 0.9s linear infinite;
}
/* done: the check it earned, and its swatch filled with its cargo's
   colour, so a node that has run is told from one queued even folded,
   where the check is out of sight (queued, its swatch is white; running,
   tinted; run, full) */
[data-case='vicino'] .cs-rail-list a.is-done .cs-rail-num { background: var(--port); }
[data-case='vicino'] .cs-rail-list a.is-done .cs-rail-tick { background: #43ba51; box-shadow: none; scale: 1.06; }
[data-case='vicino'] .cs-rail-list a.is-done .cs-rail-tick svg { opacity: 1; }
@media (hover: hover) {
  [data-case='vicino'] .cs-rail-list a:not([aria-current]):hover { opacity: 1; color: #1d1d1f; }
}
/* the spark, on the wire, at the in-port of the node being read */
[data-case='vicino'] .cs-rail-runner {
  left: calc(var(--port-x) - 5 * var(--u));
  top: calc(-21 * var(--u));
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  transition: translate 0.7s var(--ease-draw), opacity 0.3s ease;
}
[data-case='vicino'] .cs-rail-runner i {
  border-radius: 50%;
  background: #49e0f5;
  box-shadow: 0 0 0 calc(3 * var(--u)) rgb(73 224 245 / 0.28), 0 0 calc(12 * var(--u)) #49e0f5;
  animation: cs-spark-pulse 1.6s ease-in-out infinite;
}
@keyframes cs-spark-pulse { 50% { scale: 1.35; box-shadow: 0 0 0 calc(5 * var(--u)) rgb(73 224 245 / 0.12), 0 0 calc(16 * var(--u)) #49e0f5; } }

/* ---- Next Level's rail: the flight plan ----
   A brand book's plate, small: the badge's blue grid on white, "Flight
   plan" in the wordmark's heavy capitals, and the chapters as waypoints on
   one flight path, each in a ring of the badge's blue with its number. The
   drone from the badge flies the path, hovering at the chapter being read
   and spraying it clean as it goes: the path it has flown is solid and the
   path to come dashed, a waypoint passed fills blue, its name is clean and
   wears a glint, and the one being cleaned has a shine passing across it.
   The last stop, the reflection, is the landing pad. */
[data-case='nextlevel'] .cs-rail-in {
  /* the flight path runs down the folded rail's middle, under the back
     button's (the names start where the drone's spray ends; at a padding
     of 12 on the left and 8 on the right "Five questions" just fitted a
     window 1280 wide, and at 9 and 9 it has two more) */
  --path-x: calc(28 * var(--u));
  padding: calc(13 * var(--u)) calc(9 * var(--u)) calc(14 * var(--u));
  border-radius: calc(18 * var(--u));
  background-color: #fff;
  background-image:
    linear-gradient(rgb(4 149 235 / 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgb(4 149 235 / 0.07) 1px, transparent 1px);
  background-size: calc(12 * var(--u)) calc(12 * var(--u));
  box-shadow: inset 0 0 0 1px rgb(4 149 235 / 0.28), var(--rail-lift, 0 0 0 0 transparent);
}
/* the path: dashed where it is still to be flown, solid where it has */
[data-case='nextlevel'] .cs-rail-in::before,
[data-case='nextlevel'] .cs-rail-in::after {
  content: '';
  position: absolute;
  left: calc(var(--path-x) - 1 * var(--u));
  top: var(--y0, 0px);
  width: calc(2 * var(--u));
}
[data-case='nextlevel'] .cs-rail-in::before {
  height: calc(var(--y1, 0px) - var(--y0, 0px));
  background: repeating-linear-gradient(to bottom, rgb(4 149 235 / 0.55) 0 calc(4 * var(--u)), transparent 0 calc(9 * var(--u)));
}
[data-case='nextlevel'] .cs-rail-in::after {
  height: calc(var(--y, 0px) - var(--y0, 0px));
  background: #0495eb;
  opacity: 0;
  transition: height var(--t-settle) var(--spring-settle), opacity 0.3s ease;
}
[data-case='nextlevel'] .cs-rail.is-started .cs-rail-in::after { opacity: 1; }
[data-case='nextlevel'] .cs-rail-head { gap: calc(10 * var(--u)); margin: 0 0 calc(12 * var(--u)); }
[data-case='nextlevel'] .cs-rail-title { font-size: max(10px, calc(11.5 * var(--u))); font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: #0d2a4d; }
/* the count in a ring of the badge's blue, as wide as the column it heads */
[data-case='nextlevel'] .cs-rail-count {
  width: calc(38 * var(--u));
  height: calc(22 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: inset 0 0 0 calc(1.5 * var(--u)) #0495eb;
  font-size: max(10px, calc(11.5 * var(--u)));
  font-weight: 700;
  color: #0495eb;
}
[data-case='nextlevel'] .cs-rail-list a {
  grid-template-columns: calc(48 * var(--u)) minmax(0, 1fr) auto;
  min-height: calc(34 * var(--u));
  font-size: var(--t-small);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0;
  color: var(--ink-3);
  transition: color 0.25s ease;
}
/* the waypoint: a ring of the badge's blue on the path, its number in it */
[data-case='nextlevel'] .cs-rail-num {
  justify-self: start;
  width: calc(19 * var(--u));
  height: calc(19 * var(--u));
  margin-left: calc(var(--path-x) - 9 * var(--u) - 9.5 * var(--u));
  border-radius: 50%;
  background: #fff;
  box-shadow: inset 0 0 0 calc(1.5 * var(--u)) #0495eb;
  font-size: max(8.5px, calc(9 * var(--u)));
  font-weight: 800;
  color: #0495eb;
  transition: background-color 0.25s ease, color 0.25s ease, opacity 0.2s ease, scale var(--t-pop) var(--spring-pop);
}
[data-case='nextlevel'] .cs-rail-num:empty::before { content: 'H'; }
[data-case='nextlevel'] .cs-rail-tick { width: calc(12 * var(--u)); font-size: max(10px, calc(11 * var(--u))); color: #0495eb; }
[data-case='nextlevel'] .cs-rail-tick svg { display: none; }
[data-case='nextlevel'] .cs-rail-tick::before { content: '✦'; opacity: 0; scale: 0.4; transition: opacity 0.25s ease, scale var(--t-pop) var(--spring-pop); }
/* passed: the waypoint filled, the name clean and glinting */
[data-case='nextlevel'] .cs-rail-list a.is-done { color: #0d2a4d; }
[data-case='nextlevel'] .cs-rail-list a.is-done .cs-rail-num { background: #0495eb; color: #fff; }
[data-case='nextlevel'] .cs-rail-list a.is-done .cs-rail-tick::before { opacity: 1; scale: 1; }
/* being cleaned: under the drone, its name shining as the spray passes
   (at 650 "Five questions" came out two pixels too wide for its place,
   and was cut to "Five questio…" for the whole of its chapter) */
[data-case='nextlevel'] .cs-rail-list a[aria-current='step'] { color: #0d2a4d; font-weight: 600; letter-spacing: -0.006em; }
[data-case='nextlevel'] .cs-rail-list a[aria-current='step'] .cs-rail-num { opacity: 0; scale: 0.6; }
[data-case='nextlevel'] .cs-rail-list a[aria-current='step'] .cs-rail-name {
  background: linear-gradient(100deg, #0d2a4d 38%, #6fd0ff 50%, #0d2a4d 62%) 100% 0 / 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: cs-shine 2.6s ease-in-out 0.3s infinite;
}
@keyframes cs-shine { 0%, 30% { background-position: 100% 0; } 70%, 100% { background-position: 0 0; } }
@media (hover: hover) {
  [data-case='nextlevel'] .cs-rail-list a:not([aria-current]):hover { color: #0d2a4d; }
  [data-case='nextlevel'] .cs-rail-list a:not([aria-current]):hover .cs-rail-num { scale: 1.12; }
}
/* the drone: hovering on the path, spraying the name beside it, and
   diving or climbing as it flies to the next. It is the badge's line
   drone, drawn again here for its size: the badge's own drawing, shrunk to
   sixty pixels, thinned its lines to a grey smudge (which is the badge's
   own lesson, chapter 4.2) */
[data-case='nextlevel'] .cs-rail-runner {
  left: calc(var(--path-x) - 26 * var(--u));
  top: calc(-8.3 * var(--u));
  width: calc(52 * var(--u));
  height: calc(16.6 * var(--u));
}
[data-case='nextlevel'] .cs-rail-runner i {
  position: relative;
  background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 32' fill='none' stroke-linecap='round' stroke-linejoin='round'><g stroke='%230d2a4d' stroke-width='2.4'><path d='M5 5h25M70 5h25'/><path d='M17.5 5v6M82.5 5v6M17.5 11H37M63 11h19.5'/><rect x='37' y='6' width='26' height='14' rx='5' fill='%23fff'/><path d='M42 13h16'/><path d='M50 20v4h8'/><rect x='57' y='21.5' width='7' height='5' rx='1.5' fill='%23fff'/></g><g stroke='%230495eb' stroke-width='2'><path d='M68 21.5l8-3M68 24h10M68 26.5l8 3'/></g><circle cx='17.5' cy='5' r='2.2' fill='%230d2a4d'/><circle cx='82.5' cy='5' r='2.2' fill='%230d2a4d'/></svg>") center / contain no-repeat;
  animation: cs-drone-hover 2.6s ease-in-out infinite;
}
[data-case='nextlevel'] .cs-rail-runner i::after {
  content: '';
  position: absolute;
  left: 80%;
  top: 62%;
  width: calc(14 * var(--u));
  height: calc(6 * var(--u));
  background: repeating-linear-gradient(90deg, #0495eb 0 calc(3 * var(--u)), transparent 0 calc(6 * var(--u))) 0 50% / 200% calc(1.5 * var(--u)) no-repeat;
  -webkit-mask: linear-gradient(90deg, #000 30%, transparent);
  mask: linear-gradient(90deg, #000 30%, transparent);
  animation: cs-spray 0.7s linear infinite;
}
@keyframes cs-drone-hover {
  0%, 100% { translate: 0 0; rotate: -1deg; }
  50% { translate: 0 calc(-2.5 * var(--u)); rotate: 1.2deg; }
}
@keyframes cs-spray { to { background-position: calc(6 * var(--u)) 50%; } }
[data-case='nextlevel'] .cs-rail.is-moving[data-heading='down'] .cs-rail-runner i { animation: cs-drone-hover 2.6s ease-in-out infinite, cs-drone-dive 0.7s var(--ease-rise); }
[data-case='nextlevel'] .cs-rail.is-moving[data-heading='up'] .cs-rail-runner i { animation: cs-drone-hover 2.6s ease-in-out infinite, cs-drone-climb 0.7s var(--ease-rise); }
@keyframes cs-drone-dive { 30% { rotate: 10deg; } }
/* folded, the drone flies the path a size down, inside the column, and
   holds its spray, there being no name beside it to clean */
@media (min-width: 761px) and (hover: hover) {
  [data-case='nextlevel'] .cs-rail-runner { transition: translate var(--t-settle) var(--spring-settle), opacity 0.3s ease, scale 0.3s var(--ease-rise) 0.22s; }
  [data-case='nextlevel'] .cs-rail:is(:hover, :focus-within) .cs-rail-runner { transition-delay: 0s, 0s, 0.12s; }
  [data-case='nextlevel'] .cs-rail:not(:hover, :focus-within) .cs-rail-runner { scale: 0.8; }
  [data-case='nextlevel'] .cs-rail-runner i::after { transition: opacity 0.2s ease; }
  [data-case='nextlevel'] .cs-rail:not(:hover, :focus-within) .cs-rail-runner i::after { opacity: 0; }
}
@keyframes cs-drone-climb { 30% { rotate: -10deg; } }

@media (prefers-reduced-motion: reduce) {
  .cs-rail-runner, [data-case='nextlevel'] .cs-rail-in::after { transition-duration: 0.01s !important; }
  .cs-rail-runner i, .cs-rail-runner i::after, .cs-rail-list a, .cs-rail-list a *, .cs-rail-num::before { animation: none !important; }
  [data-case='vicino'] .cs-rail-list a[aria-current='step'] { background-size: 100% calc(2.5 * var(--u)); }
  [data-case='nextlevel'] .cs-rail-list a[aria-current='step'] .cs-rail-name { background: none; color: #0d2a4d; }
}

/* ---- a number that rolls up to itself, as an odometer does ----
   (js/case.js) Each digit is a column of the ten, twice over, that spins
   once round and settles on its own, the right-hand ones a beat after the
   left. The real number is beside them for a reader, and is what shows
   under reduced motion or without script. */
.cs-odo { display: inline-flex; }
.cs-odo-d {
  display: inline-block;
  height: 1em;
  overflow: hidden;
  line-height: 1;
}
.cs-odo-d > span {
  display: grid;
  translate: 0 0;
  transition: translate 1.7s var(--ease-rise);
  transition-delay: calc(var(--k, 0) * 90ms + 150ms);
}
.cs-odo.is-rolled .cs-odo-d > span { translate: 0 calc(var(--to) * -1em); }

/* ---- a picture, opened out (js/case.js) ----
   A screen, a sketch or a panel can be opened to the size of the window,
   the picture itself growing out of the page into it (a view transition,
   where the browser has them), and put back with a click, a press of
   Escape or the close button. */
[data-zoom] { cursor: zoom-in; }
.cs-zoom {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
  cursor: zoom-out;
}
.cs-zoom[open] { display: grid; place-items: center; }
.cs-zoom::backdrop {
  background: color-mix(in oklab, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  backdrop-filter: blur(18px) saturate(1.2);
}
.cs-zoom img {
  display: block;
  width: auto;
  height: auto;
  max-width: min(92vw, 1600px);
  max-height: 88vh;
  max-height: 88dvh;
  object-fit: contain;
  border-radius: 14px;
  box-shadow: 0 0 0 1px rgb(var(--line) / 0.06), 0 40px 80px -30px rgb(var(--line) / 0.4);
}
.cs-zoom img.is-phone { box-shadow: none; border-radius: 0; filter: drop-shadow(0 30px 40px rgb(var(--line) / 0.3)); }
.cs-zoom-close {
  position: absolute;
  top: max(16px, env(safe-area-inset-top));
  right: max(16px, env(safe-area-inset-right));
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 0 0 1px rgb(var(--line) / 0.06), 0 8px 20px -10px rgb(var(--line) / 0.35);
  color: var(--ink);
}
.cs-zoom-close svg { width: 22px; height: 22px; }
.cs-zoom-cap {
  position: absolute;
  left: 50%;
  bottom: max(18px, env(safe-area-inset-bottom));
  max-width: min(80vw, 720px);
  translate: -50% 0;
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: 0;
  text-align: center;
  color: var(--ink-3);
  text-wrap: balance;
}
::view-transition-group(cs-zoom) { animation-duration: var(--t-settle); animation-timing-function: var(--spring-settle); }
::view-transition-old(cs-zoom), ::view-transition-new(cs-zoom) { animation-duration: 0.2s; height: 100%; object-fit: contain; }

/* ---- the light that follows the pointer ----
   Every lit tile is lit from its top-left corner; pointed at, it is lit
   from where the pointer is too, a soft white bloom that trails the hand
   (js/case.js writes --mx and --my), so a tile answers being looked at
   before it is pressed. */
@media (hover: hover) {
  /* (its own stacking context, so the bloom sits on the tile's colour
     and under everything standing on the tile) */
  .cs-lit { position: relative; isolation: isolate; }
  .cs-lit::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(calc(380 * var(--u)) circle at var(--mx, 50%) var(--my, 0%), rgb(255 255 255 / 0.55), transparent 70%);
    opacity: 0;
    transition: opacity 0.45s ease;
    pointer-events: none;
  }
  .cs-lit:hover::before { opacity: 1; }
}

/* ======================================================================
   The pictures the chapters are told with
   Each is a way to say with the work what the old pages said in a
   paragraph: a number drawn as the thing it counts, a choice stamped on
   the sketch it was made on, a flow the page scrolls through sideways.
   Most are made of the case's own pictures; none of them invents one.
   ====================================================================== */
/* The overview, under the opening tile, opens as every chapter does: a
   word in the case's own hand where a chapter's number stands (Vicino's
   node, PantryPal's white button, Next Level's ring), the hairline drawn
   out from it, and at its far end what follows, the story in so many
   chapters, so the overview reads as the page's first chapter. (It was
   named in small capitals alone, a label over its words, and read as a
   caption to the tile above rather than the start of the story.)
   Under the opener, three things and no more, each a step down from the
   last: the case in one sentence, large; the facts, small, in a line
   between two hairlines, as a film's credits run; and the chapters in
   pictures, which say what the story will tell better than a paragraph
   could. (Two paragraphs stood over the facts, the second listing what
   the chapters' pictures already showed; for a day the whole of it stood
   on a white card, which set it apart from the page more than it held it
   together.) */
.cs-intro {
  --sec-pad: calc(96 * var(--u));
  --intro-rule: color-mix(in oklab, var(--deep) 14%, transparent);
}
/* the sentence, between a part's title and a chapter's in size, quiet but
   for the phrase that carries it, which takes the case's own deep colour */
.cs-intro > :is(.cs-intro-lead, .cs-intro-lede) { margin-top: calc(36 * var(--u)); }
.cs-intro .cs-intro-lead {
  max-width: calc(780 * var(--u));
  font-size: max(29px, calc(44 * var(--u)));
  line-height: 1.12;
  letter-spacing: -0.03em;
  color: var(--ink-3);
  text-wrap: balance;
}
.cs-intro .cs-intro-lead strong { font-weight: inherit; color: var(--accent); }

/* A film of the case, where a case has one (PantryPal's): small, beside
   the sentence where the column is wide and under it where it is narrow,
   looping without its sound as the page's other clips do, with a chip on
   it saying what it is and how long. Pressed, it opens to the theater
   (below). It was shot upright on a phone; here it is cut square, from a
   little above its middle, so the face at the top and the phone in the
   hand both stay in, and the whole frame waits in the theater. (It was cut
   four by five, and stood a good deal taller than the two lines of the
   question beside it, with empty space above and under them.) Its
   corners are a story map picture's, and it is held in a box that clips
   it, since Safari draws a video's own rounded corners square while it
   plays. (It stood across the whole column under the sentence, with its
   controls, and was the biggest thing in the overview.) */
.cs-intro-lede { display: grid; row-gap: calc(28 * var(--u)); justify-items: start; }
.cs-intro-lede > .cs-intro-lead { margin: 0; }
.cs-intro-film {
  position: relative;
  display: block;
  width: min(100%, 200px);
  overflow: hidden;
  isolation: isolate;
  border-radius: calc(20 * var(--u));
  background: var(--tint);
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent),
    0 calc(10 * var(--u)) calc(24 * var(--u)) calc(-16 * var(--u)) color-mix(in oklab, var(--deep) 22%, transparent);
  -webkit-tap-highlight-color: transparent;
  transition: translate var(--t-settle) var(--spring-settle), box-shadow 0.45s ease;
}
.cs-intro-film video { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; object-position: 50% 26%; }
/* the facts come up a little closer under a film's row, which the film's
   height already sets apart from them */
.cs-intro-lede:has(video) + .cs-facts { margin-top: calc(32 * var(--u)); }
/* Vicino's is the board in small, dressed as one of the board's own nodes,
   as the opening tile's Credits is: a white card, its header (a glyph, its
   name, the teal chip a node's model wears, and where a done chip would
   stand, the way in), and in its inset well the workflow alone, the
   prompt, its two pictures, the video and the model, cut from the hero's
   still without the editor's bars around it. It is a link to the working
   replica in a tab of its own. Pointed at, the card lifts, the way in
   fills, and the workflow leans in. (It was the whole of the hero's still,
   toolbars and all, shrunk to a thumbnail: the bars were illegible and the
   workflow was a small thing in its middle. For a day it opened the
   replica in the theater, and wore an input port on its left edge.) */
.cs-intro-film.is-board {
  width: min(100%, 300px);
  padding: 0 calc(9 * var(--u)) calc(9 * var(--u));
  overflow: visible;
  border-radius: calc(18 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(15 23 42 / 0.075),
    inset 0 1px 0 rgb(255 255 255 / 0.88),
    0 calc(10 * var(--u)) calc(24 * var(--u)) calc(-16 * var(--u)) color-mix(in oklab, var(--deep) 24%, transparent);
}
.cs-board-head {
  display: flex;
  align-items: center;
  gap: calc(7 * var(--u));
  height: calc(42 * var(--u));
  padding: 0 0 0 calc(5 * var(--u));
  font-size: max(13px, calc(14.5 * var(--u)));
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #1d1d1f;
}
.cs-board-head > svg { width: calc(17 * var(--u)); height: calc(17 * var(--u)); }
.cs-board-head em {
  padding: calc(3 * var(--u)) calc(7 * var(--u));
  border-radius: 99px;
  background: #e6f6f8;
  font-size: max(10.5px, calc(11 * var(--u)));
  font-style: normal;
  font-weight: 500;
  color: #0d7685;
}
.cs-board-head i {
  display: inline-flex;
  align-items: center;
  gap: calc(3 * var(--u));
  height: calc(26 * var(--u));
  margin-left: auto;
  padding: 0 calc(8 * var(--u)) 0 calc(10 * var(--u));
  border-radius: calc(9 * var(--u));
  background: #f0fdff;
  font-size: max(11px, calc(12 * var(--u)));
  font-style: normal;
  font-weight: 600;
  color: #0d7685;
  transition: background-color 0.25s ease, color 0.25s ease;
}
.cs-board-head i svg { width: calc(13 * var(--u)); height: calc(13 * var(--u)); }
.cs-board-well {
  display: block;
  overflow: hidden;
  border-radius: calc(11 * var(--u));
  background: #eef3f3;
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.05);
}
.cs-intro-film img { display: block; width: 100%; height: auto; aspect-ratio: 1200 / 729; transition: scale 0.7s var(--ease-rise); }
.cs-intro-film-cue {
  position: absolute;
  left: calc(10 * var(--u));
  bottom: calc(10 * var(--u));
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(28 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(9 * var(--u));
  border-radius: 999px;
  background: rgb(255 255 255 / 0.86);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  box-shadow: 0 calc(4 * var(--u)) calc(12 * var(--u)) calc(-6 * var(--u)) rgb(0 0 0 / 0.18);
  font-size: var(--t-micro);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: #1d1d1f;
  transition: scale var(--t-pop) var(--spring-pop);
}
.cs-intro-film-cue svg { width: calc(14 * var(--u)); height: calc(14 * var(--u)); color: var(--deep); }
.cs-intro-film:focus-visible { outline: 2px solid var(--deep); outline-offset: 3px; }
@media (hover: hover) {
  .cs-intro-film:hover {
    translate: 0 calc(-3 * var(--u));
    box-shadow:
      0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent),
      0 calc(16 * var(--u)) calc(32 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 30%, transparent);
  }
  .cs-intro-film:hover .cs-intro-film-cue { scale: 1.06; }
  .cs-intro-film:hover img { scale: 1.05; }
  .cs-intro-film:hover .cs-board-head i { background: #0d7685; color: #fff; }
  .cs-intro-film.is-board:hover {
    box-shadow:
      0 0 0 1px rgb(15 23 42 / 0.075),
      inset 0 1px 0 rgb(255 255 255 / 0.88),
      0 calc(16 * var(--u)) calc(32 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 32%, transparent);
  }
}
@container lane (min-width: 660px) {
  .cs-intro-lede { grid-template-columns: minmax(0, 1fr) auto; column-gap: calc(48 * var(--u)); align-items: center; }
  .cs-intro-film { width: calc(200 * var(--u)); }
  .cs-intro-film.is-board { width: calc(296 * var(--u)); }
  /* beside a preview, the sentence a step smaller, so it keeps a reading
     line in the narrower column rather than running to six short ones */
  .cs-intro-lede > .cs-intro-lead { font-size: calc(40 * var(--u)); }
}

/* the theater: the film opened to the window over the frosted page, as a
   picture opens (above, "a picture, opened out"), whole and upright, with
   its sound and its controls, settling in from a little smaller as it
   fades up. A press outside it, Escape, or the close button puts it
   back. */
.cs-theater { cursor: auto; }
.cs-theater video {
  display: block;
  height: min(86vh, calc(92vw * 16 / 9), 1280px);
  height: min(86dvh, calc(92vw * 16 / 9), 1280px);
  width: auto;
  aspect-ratio: 9 / 16;
  border-radius: 20px;
  background: #000;
  box-shadow: 0 0 0 1px rgb(var(--line) / 0.06), 0 40px 80px -30px rgb(var(--line) / 0.4);
}
@media (prefers-reduced-motion: no-preference) {
  .cs-theater[open] video { animation: cs-theater-in var(--t-settle) var(--spring-settle); }
  .cs-theater[open]::backdrop { animation: cs-theater-fade 0.3s ease; }
}
@keyframes cs-theater-in { from { opacity: 0; scale: 0.94; } }
@keyframes cs-theater-fade { from { opacity: 0; } }

/* the facts: two by two where the column is narrow, labels in the deep
   colour the chapters' dates are set in and values in the small print */
.cs-intro > .cs-facts {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: calc(44 * var(--u));
  border-color: var(--intro-rule);
}
.cs-intro > .cs-facts dt { margin-bottom: calc(6 * var(--u)); color: var(--accent); }
.cs-intro > .cs-facts dd { font-size: var(--t-small); line-height: 1.35; letter-spacing: 0; }
/* Where the column is wide, the four run in one line, each as wide as its
   value and the room left over shared out evenly, parted by hairlines
   that stand the band's whole height. (They stood one under another down
   the left, beside the words, as a book's details stand down its flap;
   read down, they looked like a form.) Each fact past the first stands a
   gap in from its hairline, so its list's dots are cut away by a clip on
   the list itself rather than by the fact's box, which has that gap
   inside it. */
@container lane (min-width: 660px) {
  .cs-intro > .cs-facts { grid-template-columns: repeat(4, auto); gap: 0; padding-block: 0; }
  .cs-intro > .cs-facts > div { padding-block: calc(18 * var(--u)); overflow-x: visible; }
  .cs-intro > .cs-facts > div + div { padding-left: calc(20 * var(--u)); border-left: 1px solid var(--intro-rule); }
  .cs-intro > .cs-facts > div:not(:last-child) { padding-right: calc(20 * var(--u)); }
  .cs-intro > .cs-facts dd.cs-list { clip-path: inset(-0.5em -0.5em -0.5em 0.7em); }
}

/* The story map, the overview's last word and its picture: a shelf of the
   chapters. Each tile is a low plinth in the case's tint, and its drawing
   stands on it, a little larger than the plinth is wide, so the top of it
   rises over the plinth's edge as a thing set on a shelf does (the
   drawings are inked on a clear ground; tools/story-art.sh). On the
   plinth's front edge hangs the chapter's own badge, drawn as the
   chapter's opener draws it further down the page (Vicino's node in the
   chapter's colour, PantryPal's sticker, Next Level's ring), so the map
   reads as the openers to come, in small; under it, the chapter's name
   and its date, the whole width of the plinth. Pointed at, the
   drawing lifts off its plinth a little further. (The drawings sat inside
   their tiles, clipped to them, with "01 · late 2025" over the name; the
   row read as a strip of thumbnails rather than the story's chapters.) */
.cs-intro > .cs-storymap { margin-top: calc(76 * var(--u)); }
.cs-intro .cs-storymap-pic {
  display: block;
  aspect-ratio: 4 / 2.6;
  margin-bottom: calc(30 * var(--u));
  overflow: visible;
}
.cs-intro .cs-storymap-pic img {
  position: absolute;
  left: -6%;
  bottom: -2%;
  width: 112%;
  height: auto;
  object-fit: contain;
  transform-origin: 50% 100%;
  transition: translate 0.7s var(--ease-rise), scale 0.7s var(--ease-rise);
}
/* the badge at about two thirds of its opener's size (zoom, so it is
   drawn and placed at that size), half over the plinth's front edge */
.cs-intro .cs-storymap-pic .cs-chapter-num {
  position: absolute;
  left: calc(20 * var(--u));
  bottom: 0;
  z-index: 1;
  translate: 0 50%;
  zoom: 0.6;
}
[data-case='pantrypal'] .cs-intro .cs-storymap-pic .cs-chapter-num { zoom: 0.5; }
[data-case='vicino'] .cs-intro .cs-storymap-pic .cs-chapter-num { zoom: 0.72; }
.cs-intro .cs-storymap-when { margin: calc(4 * var(--u)) 0 0; }
@media (hover: hover) {
  .cs-intro .cs-storymap a:hover .cs-storymap-pic img { translate: 0 calc(-8 * var(--u)); scale: 1.04; }
}
/* On the way in, the plinths rise a beat apart, left to right, and each
   drawing a beat after its plinth, up out of it from a little smaller.
   (Animations, filling only before they start, so that once in, a drawing
   answers the pointer at once, with no entrance delay left on it.) */
@media (prefers-reduced-motion: no-preference) {
  .cs-intro .cs-storymap li:nth-child(2) { --i: 1; }
  .cs-intro .cs-storymap li:nth-child(3) { --i: 2; }
  .cs-intro .cs-storymap li:nth-child(4) { --i: 3; }
  .cs-intro .cs-storymap li:nth-child(5) { --i: 4; }
  .cs-intro .cs-storymap.is-risen li {
    animation: cs-shelf-in 0.9s var(--ease-rise) backwards;
    animation-delay: calc(var(--i, 0) * 90ms + 80ms);
  }
  .cs-intro .cs-storymap.is-risen .cs-storymap-pic img {
    animation: cs-shelf-pop 0.95s var(--spring-settle) backwards;
    animation-delay: calc(var(--i, 0) * 90ms + 240ms);
  }
}
@keyframes cs-shelf-in { from { opacity: 0; translate: 0 calc(18 * var(--u)); } }
@keyframes cs-shelf-pop { from { opacity: 0; translate: 0 calc(16 * var(--u)); scale: 0.88; } }
/* where the map runs sideways under a finger, it keeps room over the
   plinths for the drawings, which its scroller would otherwise cut */
@container lane (max-width: 500px) {
  .cs-intro > .cs-storymap { margin-top: 20px; padding-top: 44px; }
}
.cs-label { margin-bottom: calc(12 * var(--u)); }

/* ---- the story map: the chapters, each with its own picture ----
   Under the overview, the milestones as a row of small lit tiles, one a
   chapter, each holding an illustration of that chapter drawn in its own
   work's manner, with its number and date over its name; a press goes
   there. They are the page's table of contents, told in pictures rather
   than words. (They were a row of dates on a hairline, each over its
   word, and then each chapter's own artifact: the sketch, the Figma
   screen, the design system's parts.) */
.cs-storymap {
  display: grid;
  grid-template-columns: repeat(var(--n, 5), minmax(0, 1fr));
  /* three rows the whole map shares, its pictures, their dates and their
     names, so that where one date runs to two lines (The mark's "three
     colorways", Vicino's on a phone) every name still stands on one line
     with the others (each tile laid its own rows, and a long date pushed
     its name a line lower than its neighbours') */
  grid-template-rows: repeat(3, auto);
  column-gap: calc(16 * var(--u));
  margin-top: calc(40 * var(--u));
  list-style: none;
}
.cs-storymap li, .cs-storymap a {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  row-gap: 0;
}
.cs-storymap a {
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
}
.cs-storymap-when { margin-bottom: calc(8 * var(--u)); text-wrap: balance; }
.cs-storymap-pic {
  position: relative;
  display: grid;
  /* one cell exactly the tile's size, so that a picture's height in
     shares (a document's 81) is a share of the tile and not of the
     picture's own height: the cell was as tall as its picture, and
     Vicino's documents, which stand unclipped on a wired tile, ran
     35 past its foot and over the date under it */
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  place-items: center;
  /* a little wider than tall: a glimpse of each chapter's picture, enough
     to know it again further down (they stood taller than wide, and the
     row of them was as tall as the words over it) */
  aspect-ratio: 4 / 3.2;
  /* the shape is the tile's, whatever its picture would rather be: where a
     tile does not clip (Vicino's, wired), a picture's own height pushed
     its tile taller, and the shape then widened it past its column */
  min-width: 0;
  min-height: 0;
  margin-bottom: calc(16 * var(--u));
  overflow: hidden;
  border-radius: calc(20 * var(--u));
  background:
    radial-gradient(130% 75% at 0% 0%, color-mix(in oklab, var(--tint), #fff 70%), transparent 72%),
    linear-gradient(to bottom, color-mix(in oklab, var(--tint), #fff 38%), var(--tint) 62%);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent);
  transition: translate var(--t-settle) var(--spring-settle), box-shadow 0.45s ease;
}
/* each picture is an illustration drawn for its tile, at the tile's own
   shape, on a clear ground the tile's light shows through
   (tools/story-art.sh) */
.cs-storymap-pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: translate 0.7s var(--ease-rise);
}
.cs-storymap-when { font-size: var(--t-micro); line-height: 1.2; letter-spacing: 0.08em; text-transform: uppercase; font-variant-numeric: tabular-nums; color: var(--accent); }
.cs-storymap b { font-weight: inherit; font-size: var(--t-name); line-height: 1.15; letter-spacing: -0.014em; text-wrap: balance; }
@media (hover: hover) {
  .cs-storymap a:hover .cs-storymap-pic {
    translate: 0 calc(-4 * var(--u));
    box-shadow:
      inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent),
      0 calc(14 * var(--u)) calc(28 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 26%, transparent);
  }
  .cs-storymap a:hover .cs-storymap-pic img { translate: 0 calc(-6 * var(--u)); }
}

/* ---- a belt: a row of the work's pictures, running past ----
   (js/case.js doubles the row so it runs without a seam.) It eases out
   at both ends, holds still under the pointer, and stands still under
   reduced motion, where the row simply runs off the edge. */
.cs-belt {
  overflow: hidden;
  -webkit-mask: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
  mask: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}
.cs-belt-row {
  --bg: calc(12 * var(--u));
  display: flex;
  gap: var(--bg);
  width: max-content;
  list-style: none;
  animation: cs-belt var(--dur, 70s) linear infinite;
}
.cs-belt-row.is-back { animation-direction: reverse; }
.cs-belt-row > * { flex: none; }
.cs-belt-row img {
  display: block;
  width: var(--bs, calc(72 * var(--u)));
  height: var(--bs, calc(72 * var(--u)));
  object-fit: contain;
  filter: drop-shadow(0 calc(6 * var(--u)) calc(8 * var(--u)) color-mix(in oklab, var(--deep) 22%, transparent));
}
@keyframes cs-belt { to { translate: calc(-50% - var(--bg) / 2) 0; } }
@media (hover: hover) { .cs-belt:hover .cs-belt-row { animation-play-state: paused; } }

/* ---- PantryPal: the problem, in two pictures and a question ----
   Two facts, each a drawing of the same cook beside its words: the food
   thrown away, as the cook tipping a plate of good food into a full bin,
   signed with USDA's own symbol; the recipes written for no one, as the
   cook too tired to scroll a column of strangers' dinners; and the
   question the two leave, set as the chapter's last word. Not on a plate
   or in a bubble: a bubble made the brief a chat. (It was the two
   numbers, the recipes as a greyed belt of dishes running past, and the
   question in a message bubble, "which raises the question" over it; then
   a waffle of a hundred of the app's stickers, the last thirty falling
   out, beside three of its dinners read against a breakfast fridge.) */
/* the two one over the other, each its drawing beside its words, and the
   two always one height, the taller one's (the first's words, with their
   source under them, can stand taller than its drawing) */
.cs-problem { display: grid; grid-template-columns: minmax(0, 1fr); grid-auto-rows: 1fr; gap: var(--gap); align-items: stretch; }

/* The two are one tile twice, mirrored: a drawing in one half and the
   words in the other, the first drawing on the left and the second on the
   right, so the two cooks stand nearest the page's middle. Each drawing
   stands on its tile's foot, which cuts the cook's legs as a floor would,
   so it needs no shadow of its own, and each is drawn on nothing, so the
   tile's light shows through, as the story map's pictures do. Both were
   drawn with Gemini (Nano Banana Pro) after the story map's pictures, the
   bin from the desk's cook, lifted off their white, and set in pictures
   of one size, the cook drawn at nearly one size in each. */
.cs-waste, .cs-endless {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(24 * var(--u)) calc(32 * var(--u));
  align-items: center;
  padding: calc(24 * var(--u)) calc(28 * var(--u));
}
.cs-tile:is(.cs-waste, .cs-endless) > * { margin-top: 0; }
.cs-waste-art, .cs-endless-art { align-self: end; min-width: 0; margin-bottom: calc(-24 * var(--u)); }
.cs-waste-art img, .cs-endless-art img { display: block; width: 100%; height: auto; }

/* the words: an eyebrow, the head, and a sentence that opens on its
   figure. Each tile's words are a container, so its head is set as big as
   its column holds it whatever the lane makes of the tile, and the two
   heads, "Wasted Food" and "Impersonal Recipes", a word a line, at one
   size: the longest word, "Impersonal", is four of its own ems wide. */
.cs-waste-words, .cs-endless-words { container-type: inline-size; }
.cs-waste-words .cs-eyebrow, .cs-endless-words .cs-eyebrow { color: var(--tile-ink); }
.cs-waste-num, .cs-endless-num {
  margin: calc(10 * var(--u)) 0 calc(14 * var(--u));
  font-size: min(calc(76 * var(--u)), 24cqw);
  white-space: nowrap;
  line-height: 0.92;
  letter-spacing: -0.05em;
  color: var(--pastel-ink);
}
.cs-waste-num span, .cs-endless-num span { display: block; }
.cs-waste-words .cs-tile-meta, .cs-endless-words .cs-tile-meta { max-width: 24em; }
.cs-endless-words { display: grid; align-content: start; }
/* The source, signed at the words' foot: the words stand the drawing's
   height, the figure in the middle of it and the signature at its
   bottom. The symbol is USDA's own file, in
   its own blue and green and nothing of the case's over it, as Apple's
   badge is drawn; beside it a hairline, and the Department's name over
   the page the range is from, as a report credits a source. */
.cs-waste-words { display: flex; flex-direction: column; align-self: stretch; }
.cs-waste-words > :first-child { margin-top: auto; }
.cs-waste-source { display: flex; margin-top: auto; padding-top: calc(20 * var(--u)); }
.cs-waste-source a {
  display: inline-flex;
  align-items: center;
  gap: calc(12 * var(--u));
  color: var(--tile-ink-2);
  text-decoration: none;
  border-radius: calc(4 * var(--u));
  -webkit-tap-highlight-color: transparent;
}
.cs-waste-source img { display: block; flex: none; width: auto; height: calc(30 * var(--u)); }
.cs-waste-source-words {
  display: grid;
  gap: calc(1 * var(--u));
  padding-left: calc(12 * var(--u));
  border-left: 1px solid color-mix(in oklab, var(--deep) 22%, transparent);
  font-size: var(--t-micro);
  line-height: 1.3;
  letter-spacing: 0.01em;
}
.cs-waste-source-words b { font-weight: 500; color: var(--tile-ink); }
.cs-waste-source svg { display: inline-block; width: 1.05em; height: 1.05em; margin-left: calc(2 * var(--u)); vertical-align: -0.2em; transition: translate var(--t-pop) var(--spring-pop); }
.cs-waste-source a:focus-visible { outline: 2px solid var(--deep); outline-offset: 4px; }
@media (hover: hover) {
  .cs-waste-source a:hover { color: var(--deep); }
  .cs-waste-source a:hover svg { translate: calc(1.5 * var(--u)) calc(-1.5 * var(--u)); }
}

/* The two facts as two alerts: on each tile's top right corner a badge, as
   a phone badges an app with what is waiting for it, a warning and its
   number in ink on the system's own yellow, as a road sign sets one (the
   warning's mark is cut out of it, so it is the badge's own yellow
   whatever that is). It stands on the corner's
   curve, its middle on the curve's middle (0.29 of the radius in from each
   edge), ringed in the page's own colour, so it is cut out of the tile's
   edge rather than laid over it, on every wash and on ink. It sits in its
   tile's row of the pair and not in the tile, which clips what overhangs
   it. Once its tile has risen it pops on, a beat after, and is still. */
.cs-problem > .cs-waste, .cs-alert.is-waste { grid-area: 1 / 1; }
.cs-problem > .cs-endless, .cs-alert.is-endless { grid-area: 2 / 1; }
.cs-alert {
  position: relative;
  z-index: 2;
  justify-self: end;
  align-self: start;
  display: inline-flex;
  align-items: center;
  gap: calc(4 * var(--u));
  height: max(26px, calc(30 * var(--u)));
  padding: 0 calc(11 * var(--u)) 0 calc(8 * var(--u));
  border-radius: 999px;
  background: #ffcc00;
  color: #2b2200;
  font-size: max(13px, calc(15 * var(--u)));
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  box-shadow:
    0 0 0 max(2.5px, calc(3 * var(--u))) var(--bg),
    0 calc(8 * var(--u)) calc(18 * var(--u)) calc(-6 * var(--u)) rgb(176 128 0 / 0.5);
  translate: calc(50% - var(--r-tile) * 0.29) calc(-50% + var(--r-tile) * 0.29);
  pointer-events: none;
}
.cs-alert svg { display: block; flex: none; width: 1.1em; height: 1.1em; margin-top: -0.08em; }
html.rises .cs-alert { opacity: 0; scale: 0.4; }
html.rises :is(.cs-waste.is-risen ~ .cs-alert.is-waste, .cs-endless.is-risen ~ .cs-alert.is-endless) {
  opacity: 1;
  scale: 1;
  transition: scale var(--t-pop) var(--spring-pop) var(--wait), opacity 0.18s ease var(--wait);
}
.cs-alert.is-waste { --wait: 640ms; }
.cs-alert.is-endless { --wait: 760ms; }
@media (prefers-reduced-motion: reduce) {
  html.rises .cs-alert { scale: 1; transition: opacity 0.2s ease !important; }
}

/* The question the two leave: the chapter's last word, at a part's size,
   its last words marked in the app's butter as a pen marks a page, the
   mark drawn on as it rises, and under it who it was asked for. */
.cs-hmw { display: grid; justify-items: start; gap: calc(10 * var(--u)); }
/* In a phone's lane each tile stands its words over its drawing */
@container lane (max-width: 560px) {
  .cs-waste, .cs-endless { grid-template-columns: minmax(0, 1fr); gap: 22px; padding: 22px; }
  .cs-waste-words, .cs-endless-words { order: -1; }
  .cs-waste-art, .cs-endless-art { margin-bottom: -22px; }
}
.cs-hmw-q {
  max-width: 19em;
  font-size: var(--t-title);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-wrap: balance;
}
.cs-hmw-q mark {
  padding: 0 0.08em;
  margin: 0 -0.04em;
  color: inherit;
  background: linear-gradient(#ffd67e, #ffd67e) 0 86% / 100% 0.44em no-repeat;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition: background-size 0.9s var(--ease-rise) 0.45s;
}
html.rises .cs-hmw:not(.is-risen) .cs-hmw-q mark { background-size: 0% 0.44em; }
.cs-hmw-for { display: flex; flex-wrap: wrap; align-items: center; gap: calc(8 * var(--u)) calc(14 * var(--u)); margin-top: calc(6 * var(--u)); }
.cs-hmw-for .cs-small { color: var(--ink-3); }

/* ---- PantryPal: the three sheets, marked up, and the hub they became ----
   The wireframes as the graph paper they were drawn on, taped to the
   case's board (below, "ideas on paper"), in a row of their own, centred
   on the board, each named in a word. They are judged the way a designer
   judges their own sheets, in pen by the names and never on the drawings:
   a red cross beside each of the two set aside, one and then the other
   as the board rises, and the third ringed in green marker. The ring's
   ink runs on into the arrow, down to the hub the kept one
   became in the first Figma build, standing under them in the middle a
   little taller than a sheet, so the verdict and what came of it are one
   stroke of the same pen. (The three stood askew on the page in white
   cards; then, each with a sentence under it, beside the shelf that
   shipped at the end of their row; but none of these screens shipped, and
   the screen the third became was this hub. Then rubber stamps came down
   across the middle of each drawing, "set aside" and "kept!", and sat on
   the very sketches they judged; then the two names were struck through
   in blue pencil and the third ringed in red, but a struck name reads as
   a word taken back, not an idea weighed, and red on the keep read as a
   warning.) */
.cs-pinboard-papers {
  --sheet-gap: calc(40 * var(--u));
  /* a sheet is 180 wide, or a third of a column too narrow for that, or
     as wide as lets the row and the hub under it stand in one window
     together: the board is about 3.6 sheets and 160 tall, so at 196 it
     stood 70px taller than a window of 1440×900, and at 180 still 24px
     taller than one of 1910×960 */
  --sheet: min(calc(180 * var(--u)), (100cqw - 56 * var(--u) - 2 * var(--sheet-gap)) / 3, (100svh - 160 * var(--u)) / 3.6);
  /* the hub a hair taller than a sheet, and never so narrow that its
     screen can't be read, which on a phone makes it the larger of them */
  --hub: max(var(--sheet) * 0.92, 124px);
  --hub-gap: calc(26 * var(--u));
  /* a unit the size of a sheet, so the tape is torn in proportion to
     the paper it holds */
  --su: calc(var(--sheet) / 176);
  /* the two pens: red for a cut, green for a keep, both fixed, since the
     board keeps its own light paper in the ink theme. The green is a
     shade brighter than it looks, since the marks are multiplied into
     the peach board (at 30 152 82 the ring dried to an olive) */
  --cut-ink: rgb(214 58 42);
  --keep-ink: rgb(22 170 88);
}
.cs-pins.is-papers { grid-template-columns: repeat(3, var(--sheet)); justify-content: center; column-gap: var(--sheet-gap); }
.cs-pins.is-papers .cs-pin-paper { margin-bottom: calc(12 * var(--u)); }
/* and the tape in proportion to its sheet too, or on a phone a strip
   for a page's sheet crossed most of a sheet a third as wide */
.cs-pins.is-papers .cs-pin-paper::before { top: calc(-10 * var(--su)); width: max(36px, 62 * var(--su)); height: max(12px, 20 * var(--su)); }
.cs-pin-name {
  font-size: var(--t-small);
  line-height: 1.2;
  text-align: center;
  color: var(--tile-ink);
}
.cs-pinboard-papers > .cs-pin-hub { position: relative; width: var(--hub); margin: var(--hub-gap) auto 0; }
.cs-pin-hub .cs-phone { width: 100%; margin-bottom: calc(12 * var(--u)); }
/* the three sketches in one frame, the third's: the first is a little
   wider and the second a little taller, and filled to it neither loses
   its phone */
.cs-pins.is-papers .cs-pin-paper img { aspect-ratio: 474 / 838; object-fit: cover; }
/* the marks, drawn by the name they judge and sized in its em, so a
   cross and a ring fit their word at every size of type. The cross
   hangs just past the end of its name, out of the line, so the name
   stays centred under its sheet; it is two quick strokes, the second
   a beat after the first, each overshooting a little as a hand's does.
   The ring is loose and overshoots where it began, as a marker's ring
   does when it is drawn quickly */
.cs-pin-word { position: relative; display: inline-block; }
.cs-pin-mark { position: absolute; overflow: visible; pointer-events: none; mix-blend-mode: multiply; }
.is-crossed .cs-pin-mark { left: calc(100% + 0.4em); top: 0.27em; width: 0.7em; height: 0.7em; color: var(--cut-ink); stroke-width: 3.4; }
.is-ringed .cs-pin-mark { left: -0.74em; top: -0.52em; width: calc(100% + 1.48em); height: 2.24em; color: var(--keep-ink); stroke-width: 3.4; }
.cs-pin-mark path { stroke-dasharray: 1; stroke-dashoffset: 0; }
html.rises .cs-pinboard:not(.is-risen) .cs-pin-mark path { stroke-dashoffset: 1; }
.cs-pinboard.is-risen .is-crossed .cs-pin-mark path { transition: stroke-dashoffset 0.18s var(--ease-draw) calc(0.6s + var(--k, 0) * 0.34s); }
.cs-pinboard.is-risen .is-crossed .cs-pin-mark path + path { transition-delay: calc(0.82s + var(--k, 0) * 0.34s); }
.cs-pinboard.is-risen .is-ringed .cs-pin-mark path { transition: stroke-dashoffset 0.62s var(--ease-draw) 1.25s; }
/* and as the ring is drawn the kept sheet comes up off the board, a
   little nearer and its shadow a little longer, picked from the three
   without a mark on its drawing. (The lift is a transform, so it adds
   to the hover's translate, and the hover keeps its own quick timing.) */
.cs-pins.is-papers .cs-pin.is-kept .cs-pin-paper {
  transform: translateY(calc(-7 * var(--u)));
  box-shadow:
    0 0 0 1px rgb(30 30 30 / 0.05),
    0 calc(2 * var(--u)) calc(3 * var(--u)) rgb(30 30 30 / 0.07),
    0 calc(30 * var(--u)) calc(36 * var(--u)) calc(-18 * var(--u)) color-mix(in oklab, var(--deep) 58%, transparent);
}
html.rises .cs-pinboard:not(.is-risen) .cs-pin.is-kept .cs-pin-paper {
  transform: none;
  box-shadow:
    0 0 0 1px rgb(30 30 30 / 0.05),
    0 calc(1.5 * var(--u)) calc(2 * var(--u)) rgb(30 30 30 / 0.06),
    0 calc(22 * var(--u)) calc(30 * var(--u)) calc(-20 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
}
.cs-pinboard.is-risen .cs-pin.is-kept .cs-pin-paper {
  transition:
    translate var(--t-settle) var(--spring-settle),
    transform 0.7s var(--spring-settle) 1.3s,
    box-shadow 0.7s ease 1.3s;
}
/* the arrow from the ring down to the hub: its tail starts at the foot
   of the ring, a sheet and a gap right of the board's middle, and its
   head (at 14 of its 160) lands just past the phone's right edge, so
   the arrow is as wide as the distance between the two, and the
   drawing's proportions keep its height. It is drawn in the ring's green
   and starts as the ring closes, so the pen never seems to lift */
.cs-pin-arrow {
  --arrow: calc((var(--sheet) + var(--sheet-gap) - var(--hub) / 2 - 4 * var(--u)) * 160 / 136);
  position: absolute;
  z-index: 4;
  top: calc(-1 * var(--hub-gap) + 1 * var(--u));
  left: calc(100% + 4 * var(--u) - var(--arrow) * 14 / 160);
  width: var(--arrow);
  height: calc(var(--arrow) * 150 / 160);
  color: var(--keep-ink);
  stroke-width: 2.6;
  pointer-events: none;
}
.cs-pin-arrow path { stroke-dasharray: 1; stroke-dashoffset: 0; }
html.rises .cs-pinboard:not(.is-risen) .cs-pin-arrow path { stroke-dashoffset: 1; }
.cs-pinboard.is-risen .cs-pin-arrow path { transition: stroke-dashoffset 0.7s var(--ease-draw) 1.84s; }
.cs-pinboard.is-risen .cs-pin-arrow path + path { transition-delay: 2.5s; transition-duration: 0.26s; }
/* a narrow lane: the three still in one row, each a third of it, with
   the gaps between them closed up */
@container lane (max-width: 640px) {
  .cs-pinboard-papers { --sheet-gap: 14px; --hub-gap: 24px; }
}

/* ---- a reel: a flow of screens the page scrolls through sideways ----
   On a wide window the reel stands still in the window while the page
   scrolls on, and the screens pass across it, left as you go down,
   right as you go back, with a bar filling under them (js/case.js; the
   page itself still scrolls the browser's own way, only the reel's
   picture moves with it). Elsewhere, and under reduced motion, it is a
   row that scrolls sideways under a finger, a screen at a time. */
.cs-reel { position: relative; }
.cs-reel-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.cs-reel-scroll::-webkit-scrollbar { display: none; }
/* the screens fade out at the column's two edges as they run past, rather
   than being cut off by them: the reel is the one piece that runs past
   its column, and a hard edge read as a mistake (the fade sits inside the
   track's own padding, so a screen at rest is never in it) */
.cs-reel-scroll {
  -webkit-mask: linear-gradient(to right, transparent, #000 calc(20 * var(--u)), #000 calc(100% - 20 * var(--u)), transparent);
  mask: linear-gradient(to right, transparent, #000 calc(20 * var(--u)), #000 calc(100% - 20 * var(--u)), transparent);
}
.cs-reel-track {
  display: flex;
  gap: calc(44 * var(--u));
  width: max-content;
  padding: calc(16 * var(--u)) calc(40 * var(--u)) calc(8 * var(--u));
  list-style: none;
}
.cs-reel-track li {
  flex: none;
  display: grid;
  justify-items: center;
  gap: calc(18 * var(--u));
  scroll-snap-align: center;
}
.cs-reel-track .cs-phone {
  width: min(calc(268 * var(--u)), (100svh - var(--cs-top) - 220 * var(--u)) * 0.5);
  height: auto;
}
.cs-reel-track span {
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--u));
  font-size: var(--t-small);
  line-height: 1;
  color: var(--ink-3);
}
.cs-reel-track span i {
  display: grid;
  place-items: center;
  min-width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 99px;
  background: var(--tint);
  font-style: normal;
  font-size: var(--t-micro);
  font-variant-numeric: tabular-nums;
  color: var(--tile-ink);
}
.cs-reel-foot {
  display: flex;
  align-items: center;
  gap: calc(16 * var(--u));
  margin: calc(28 * var(--u)) auto 0;
  max-width: var(--col);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.cs-reel-bar { position: relative; flex: 1; height: calc(2 * var(--u)); border-radius: 99px; background: rgb(var(--line) / 0.1); overflow: hidden; }
.cs-reel-bar b { position: absolute; inset: 0; border-radius: inherit; background: var(--deep); transform-origin: 0 50%; scale: var(--p, 0) 1; }
/* the run is a spacer in the reel's own content box, the length of the
   pan: a sticky view can only travel its containing block's content box,
   so a padding there would leave it behind */
.cs-reel.is-pinned::after { content: ''; display: block; height: var(--pan, 0px); }
.cs-reel.is-pinned .cs-reel-view { position: sticky; top: calc(var(--cs-top) + 8 * var(--u)); }
.cs-reel.is-pinned .cs-reel-scroll { overflow: hidden; scroll-snap-type: none; }
.cs-reel.is-pinned .cs-reel-track { will-change: translate; }

/* ---- the app's two faces, each shown in itself ---- */
.cs-type-aa {
  font-size: calc(92 * var(--u));
  line-height: 1;
  letter-spacing: 0;
}
.cs-type-aa.cs-type-display {
  color: #ff7e7d;
  text-shadow: none;
  -webkit-text-stroke: calc(6 * var(--u)) var(--mark);
  paint-order: stroke fill;
  filter: drop-shadow(0 calc(5 * var(--u)) 0 var(--mark));
}
.cs-type-aa.cs-type-prose { font-weight: 500; color: var(--mark); }

/* ---- a sheet: the work's own white paper, for a diagram ---- */
.cs-tile.cs-sheet {
  background: var(--surface);
  box-shadow:
    inset 0 0 0 1px rgb(var(--line) / 0.07),
    0 calc(34 * var(--u)) calc(60 * var(--u)) calc(-44 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
}

/* ---- pipelines: how one thing becomes the next ----
   Four stages a row, each a card with its own small drawing, joined by
   a wire that a spark runs along, behind the cards, so it shows only in
   the gaps between them, as a run moves along a board. */
.cs-pipes { display: grid; gap: calc(28 * var(--u)); padding: calc(28 * var(--u)); }
.cs-tile.cs-pipes > * + * { margin-top: 0; }
.cs-pipe-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(8 * var(--u)); margin-bottom: calc(14 * var(--u)); }
.cs-pipe-head .cs-verdict { background: var(--tint); color: var(--tile-ink); }
.cs-pipe-steps {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: calc(16 * var(--u));
  list-style: none;
}
.cs-pipe-steps::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: calc(20 * var(--u));
  right: calc(20 * var(--u));
  top: calc(30 * var(--u));
  height: calc(2 * var(--u));
  background: repeating-linear-gradient(to right, color-mix(in oklab, var(--deep) 35%, transparent) 0 calc(6 * var(--u)), transparent 0 calc(11 * var(--u)));
}
.cs-pipe-steps::after {
  content: '';
  position: absolute;
  z-index: -1;
  left: 0;
  top: calc(26 * var(--u));
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-radius: 50%;
  background: var(--deep);
  box-shadow: 0 0 0 calc(5 * var(--u)) color-mix(in oklab, var(--deep) 16%, transparent);
  opacity: 0;
}
.is-risen .cs-pipe-steps::after { animation: cs-pipe-run 4.2s var(--ease-draw) 0.6s infinite; }
.cs-pipe + .cs-pipe .cs-pipe-steps::after { animation-delay: 2.7s; }
@keyframes cs-pipe-run {
  0% { left: 0; opacity: 0; }
  6% { opacity: 1; }
  70% { left: calc(100% - 10 * var(--u)); opacity: 1; }
  78%, 100% { left: calc(100% - 10 * var(--u)); opacity: 0; }
}
.cs-pipe-steps li {
  /* its drawing beside its name, and what it does under both (the drawing
     stood over the name, a line to itself) */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-content: start;
  align-items: center;
  gap: calc(8 * var(--u)) calc(10 * var(--u));
  min-width: 0;
  padding: calc(14 * var(--u)) calc(14 * var(--u)) calc(16 * var(--u));
  border-radius: calc(20 * var(--u));
  background:
    radial-gradient(130% 75% at 0% 0%, color-mix(in oklab, var(--tint), #fff 70%), transparent 72%),
    linear-gradient(to bottom, color-mix(in oklab, var(--tint), #fff 50%), color-mix(in oklab, var(--tint), #fff 20%));
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 8%, transparent);
}
.cs-pipe-ico {
  display: grid;
  place-items: center;
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  border-radius: calc(11 * var(--u));
  background: #fff;
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent), 0 calc(6 * var(--u)) calc(12 * var(--u)) calc(-6 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
  color: var(--deep);
}
.cs-pipe-ico svg { width: calc(19 * var(--u)); height: calc(19 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.cs-pipe-steps b { font-weight: inherit; font-size: var(--t-name); line-height: 1.2; letter-spacing: -0.014em; color: var(--pastel-ink); }
.cs-pipe-steps li > span:last-child { grid-column: 1 / -1; font-size: var(--t-small); line-height: 1.42; color: var(--tile-ink); text-wrap: pretty; }

/* ---- PantryPal: every drawing, on three belts ----
   The forty-nine drawings the page carries, dealt onto three belts that
   run against each other, over the three numbers of the run that drew
   them. The list they are dealt from stays for a reader, unseen. */
.cs-belts { display: grid; gap: calc(36 * var(--u)); padding: calc(36 * var(--u)) 0 calc(40 * var(--u)); }
.cs-tile.cs-belts > * + * { margin-top: 0; }
.cs-belt-src { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.cs-belt-rows { display: grid; gap: calc(14 * var(--u)); }
.cs-belt-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gap);
  padding: 0 calc(40 * var(--u));
}
.cs-belt-stats div { display: grid; align-content: start; gap: calc(8 * var(--u)); padding-top: calc(16 * var(--u)); border-top: 1px solid color-mix(in oklab, var(--deep) 16%, transparent); }
.cs-belt-stats dd { order: -1; font-size: calc(60 * var(--u)); line-height: 1; letter-spacing: -0.045em; font-variant-numeric: tabular-nums; color: var(--pastel-ink); }
.cs-belt-stats dt { font-size: var(--t-small); line-height: 1.42; color: var(--tile-ink); text-wrap: pretty; }

.cs-note.is-static { cursor: default; }
.cs-note-more.is-open { grid-template-rows: 1fr; opacity: 1; }

/* ---- PantryPal: ideas on paper ----
   The sketch's three sheets were ideas before they were screens, so they
   stand as the graph paper they were drawn on: upright and one size, each
   taped flat to the case's own board, and under each its name and what
   became of it. (They stood askew on the page in cards of their own. The
   rethink's four ways out stood on a board like it, as ink sketches; the
   story now goes from the rethink straight to the app that shipped.) */
.cs-pinboard { padding: calc(34 * var(--u)) calc(28 * var(--u)) calc(28 * var(--u)); }
.cs-pins {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  column-gap: calc(24 * var(--u));
  row-gap: calc(34 * var(--u));
  list-style: none;
}
.cs-pin { position: relative; display: grid; align-content: start; min-width: 0; }
/* the paper: a white margin round the drawing, lifting a little off the
   board, and a strip of tape across its head at its own small angle */
.cs-pin-paper {
  position: relative;
  display: block;
  margin-bottom: calc(16 * var(--u));
  padding: calc(5 * var(--u));
  border-radius: calc(3 * var(--u));
  background: #fff;
  box-shadow:
    0 0 0 1px rgb(30 30 30 / 0.05),
    0 calc(1.5 * var(--u)) calc(2 * var(--u)) rgb(30 30 30 / 0.06),
    0 calc(22 * var(--u)) calc(30 * var(--u)) calc(-20 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  transition: translate var(--t-settle) var(--spring-settle);
}
.cs-pin-paper img { display: block; width: 100%; height: auto; border-radius: calc(2 * var(--u)); }
.cs-pin-paper::before {
  content: '';
  position: absolute;
  z-index: 3;
  top: calc(-10 * var(--u));
  left: 50%;
  width: calc(62 * var(--u));
  height: calc(20 * var(--u));
  translate: -50% 0;
  rotate: var(--tape, -2deg);
  background: linear-gradient(rgb(255 252 242 / 0.82), rgb(248 238 214 / 0.74));
  box-shadow: 0 calc(1 * var(--u)) calc(2 * var(--u)) rgb(60 40 20 / 0.14);
  /* its two ends torn, as tape is */
  clip-path: polygon(3% 6%, 7% 0, 94% 0, 98% 14%, 100% 48%, 97% 86%, 100% 100%, 5% 100%, 0 84%, 3% 50%, 0 16%);
  pointer-events: none;
}
@media (hover: hover) { .cs-pin:hover .cs-pin-paper { translate: 0 calc(-5 * var(--u)); } }


/* ---- PantryPal: the app as it shipped, in one card ----
   Every screen of the shipped app in the order a new chef meets them, on
   one card of the case's colour that pans across as the page scrolls, as
   the prototype's reel does (the same reel, js/case.js, a little faster,
   since thirteen screens at the page's own pace ran three windows long):
   in at the front door, the tour, "Hey, chef!", the scan's four steps,
   Type it in!, the chef writing, dinner, its recipe, the shelf, and last
   Settings, behind the chef. Each screen is drawn by the page's own phone
   (tools/pantry-screens.mjs), so the reel wears what the live app wears,
   and stands over its number and the name of its step, the bar under the
   row filling as it goes. Two arrows in the card's top corners, either
   side of the switch, step it a screen at a time, or glide while held,
   for a reader who would rather not scroll the page to move it.
   The switch at the card's head turns the row to before: the Figma
   prototype's six screens alone, in the prototype's own order (log in,
   pick, scan, check out, choose, cook), each in the place of the screen
   it became, under its name then. The row fades out, turns, and comes
   back a screen at a time. (The chapter stood five screens on a stage,
   each over the chapter it carried on, with the scan in a card of its
   own; earlier, seven screens turned over one by one, a 3D flip that hid
   half the row's change from view. Before showed an empty place where
   the prototype had no step, eight of fourteen, more empty than not.) */
.cs-ship-reel .cs-reel-view { padding: calc(26 * var(--u)) 0 calc(28 * var(--u)); }
.cs-tile.cs-reel-view > * + * { margin-top: 0; }
/* (room under the row for the phones' shadows to fade out in: the row is
   a scroller, which cuts whatever runs past it, and a shadow stopped at its
   foot drew a hard line across the card) */
.cs-ship-reel .cs-reel-track { --reel-gap: calc(40 * var(--u)); gap: var(--reel-gap); padding: calc(6 * var(--u)) calc(56 * var(--u)) calc(40 * var(--u)); }
/* inside a card the screens fade out over the card's own margin as they
   leave it, a longer fade than the open page's reel, or they read as
   sliced off at the card's edge; the row's own margin is a little wider
   than the fade, so the first and last screens stand clear of it at rest */
.cs-ship-reel .cs-reel-scroll {
  -webkit-mask: linear-gradient(to right, transparent, #000 calc(48 * var(--u)), #000 calc(100% - 48 * var(--u)), transparent);
  mask: linear-gradient(to right, transparent, #000 calc(48 * var(--u)), #000 calc(100% - 48 * var(--u)), transparent);
}
/* a screen's place: as tall as the window lets the whole card stand in
   it, and never so wide that fewer than three stand in the card at once.
   Its two faces stand in it one over the other */
.cs-ship-card {
  position: relative;
  width: min(calc(228 * var(--u)), (100svh - var(--cs-top) - 330 * var(--u)) * 0.489, (100cqw - 112 * var(--u) - 2 * var(--reel-gap)) / 3);
  aspect-ratio: 800 / 1636;
}
.cs-ship-reel .cs-ship-card > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
/* each prototype render drawn so its phone is the app's phone's size, at
   its place: the renders frame their phones in margins of their own, so
   held to the card's height they stood a size smaller; the places come
   from each render's measured phone (pantrypal.html, --l --t --w --h) */
.cs-ship-reel .cs-ship-card > img.is-then { inset: auto; left: var(--l, 0); top: var(--t, 0); width: var(--w, 100%); height: var(--h, 100%); object-fit: fill; }
/* the face turned away is neither seen, pressed nor read */
.cs-ship-reel[data-show='now'] .cs-ship-card > .is-then,
.cs-ship-reel[data-show='then'] .cs-ship-card > .is-now { visibility: hidden; }
/* before: the screens the prototype never had are gone, and the six it
   had stand in its own order */
.cs-ship-reel[data-show='then'] .cs-reel-track li.is-new { display: none; }
.cs-ship-reel[data-show='then'] .cs-reel-track li { order: var(--then, 0); }
/* the step's name and number, as they are and as they were */
.cs-ship-reel .cs-reel-track span { color: var(--tile-ink); }
.cs-ship-reel .cs-reel-track span i { background: rgb(255 255 255 / 0.72); color: var(--pastel-ink); }
.cs-ship-reel .cs-reel-track b { font-weight: inherit; }
.cs-ship-reel[data-show='now'] :is(.cs-reel-track, .cs-reel-foot) :is(b, i).is-then,
.cs-ship-reel[data-show='then'] :is(.cs-reel-track, .cs-reel-foot) :is(b, i).is-now { display: none; }
.cs-ship-reel .cs-reel-foot { max-width: none; margin: calc(-8 * var(--u)) calc(56 * var(--u)) 0; color: var(--tile-ink-2); }
.cs-ship-reel .cs-reel-foot b { font-weight: inherit; }
.cs-ship-reel .cs-reel-bar { background: color-mix(in oklab, var(--deep) 14%, transparent); }
/* as the switch turns the row, each screen comes back up after the one
   before it (js/pantry-story.js deals them, --n their place in the row) */
.cs-ship-reel .cs-reel-track.is-dealt li { animation: cs-ship-deal 0.5s var(--ease-rise) calc(var(--n, 0) * 50ms) backwards; }
@keyframes cs-ship-deal { from { opacity: 0; translate: 0 calc(14 * var(--u)); } }
/* the switch: two words in one white well, the one on show lifted onto
   white, the other in the card's ink */
.cs-ship-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  margin-bottom: calc(22 * var(--u));
  padding-inline: calc(26 * var(--u));
}
.cs-ship-head .cs-ship-switch { justify-self: center; }
.cs-ship-switch {
  display: inline-flex;
  padding: calc(4 * var(--u));
  border-radius: 999px;
  background: rgb(255 255 255 / 0.46);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 10%, transparent);
}
.cs-ship-switch button {
  height: max(34px, calc(36 * var(--u)));
  padding: 0 calc(20 * var(--u));
  border: 0;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: var(--t-small);
  line-height: 1;
  color: var(--tile-ink);
  cursor: pointer;
  transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}
.cs-ship-switch button[aria-checked='true'] {
  background: #fff;
  color: var(--pastel-ink);
  box-shadow: 0 1px 2px rgb(30 30 30 / 0.06), 0 calc(6 * var(--u)) calc(14 * var(--u)) calc(-6 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
}
@media (hover: hover) { .cs-ship-switch button[aria-checked='false']:hover { color: var(--pastel-ink); } }
/* the two arrows, white coins in the card's top corners, as far in from
   its edges as the switch is down from its top, so the three stand on one
   line and the corners are even; the one with nowhere to go is faint.
   (They stood at the card's two sides, level with the phones, over the
   screens fading out at its edges.) */
.cs-reel-step {
  display: grid;
  place-items: center;
  width: max(38px, calc(42 * var(--u)));
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #fff;
  color: var(--pastel-ink);
  box-shadow:
    0 0 0 1px color-mix(in oklab, var(--deep) 8%, transparent),
    0 calc(8 * var(--u)) calc(18 * var(--u)) calc(-8 * var(--u)) color-mix(in oklab, var(--deep) 45%, transparent);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  transition: opacity 0.25s ease, scale 0.2s var(--ease-rise);
}
.cs-reel-step svg { width: 48%; height: auto; }
.cs-reel-step:disabled { opacity: 0.35; cursor: default; }
@media (hover: hover) { .cs-reel-step:not(:disabled):hover { scale: 1.06; } }
.cs-reel-step:not(:disabled):active { scale: 0.94; }
/* a phone's lane: two and a bit to a view, so the next one says there
   are more; the arrows stay, a finger's other way to move them */
@container lane (max-width: 560px) {
  .cs-ship-reel .cs-reel-view { padding: 20px 0 22px; }
  .cs-ship-head { margin-bottom: 16px; padding-inline: 16px; }
  .cs-ship-reel .cs-reel-track { --reel-gap: 18px; padding: 4px 30px 30px; }
  .cs-ship-reel .cs-reel-scroll {
    -webkit-mask: linear-gradient(to right, transparent, #000 24px, #000 calc(100% - 24px), transparent);
    mask: linear-gradient(to right, transparent, #000 24px, #000 calc(100% - 24px), transparent);
  }
  .cs-ship-card { width: min(176px, 46cqw); }
  .cs-ship-reel .cs-reel-foot { margin: -6px 22px 0; white-space: nowrap; }
  /* (the bar and the count alone: beside them the flow's name broke over
     two lines, and the count over two more) */
  .cs-ship-reel .cs-reel-foot > span:first-child { display: none; }
}

/* ---- the store's panels, fanned a little, lifting in turn ---- */
.cs-store li { transition: translate 0.7s var(--ease-rise); }

/* ---- results: each number with a picture of itself ---- */
/* four across, each number over its picture and what it counts: read as
   one line of results, as a report's are, where the column is wide
   enough; two by two in the column (below, "in a narrower lane") */
.cs-stats.cs-results { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cs-results .cs-stat { min-height: 0; grid-template-rows: auto minmax(0, 1fr) auto; align-content: stretch; gap: calc(16 * var(--u)); padding: calc(24 * var(--u)); }
/* the unit under the number, not beside it: a quarter of the column is
   too narrow for "3" and "colorways" on one line */
.cs-results .cs-stat b { font-size: calc(60 * var(--u)); }
.cs-results .cs-stat b small { display: block; flex-basis: 100%; margin: calc(6 * var(--u)) 0 0; font-size: var(--t-small); }
/* (Next Level's "9 → 1" keeps its arrow between its two numbers) */
.cs-results .cs-stat b small:not(:last-child) { flex-basis: auto; margin: 0 0.2em; font-size: 0.5em; }
.cs-results .cs-stat > span:last-child { align-self: end; }

/* ---- PantryPal's results: the store's own count ----
   The store's own two screens side by side, each as it really is: the
   listing as a phone shows it, and App Store Connect's dashboard in a
   browser's window, its bar drawn as Safari draws one, so the numbers read
   as the dashboard they are rather than a picture made of them. Each opens
   to the window. The phone stands small enough that the dashboard, the
   wider screen and the one with the small print, gets the room, and the
   two stand on one line, so their captions read across as a pair. (Four
   tiles of the build's own counts stood here; then, for a day, the
   dashboard's numbers set as an order ticket in the app's hand, the real
   dashboard a thumbnail under it, and a green ring round the listing's
   ratings. Tigo wanted the dashboard itself, as it is, beside the phone,
   and the ring gone.) */
.cs-listed {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: end;
  column-gap: calc(36 * var(--u));
  padding: calc(34 * var(--u)) calc(40 * var(--u)) calc(28 * var(--u));
}
.cs-tile.cs-listed > * + * { margin-top: 0; }
.cs-listed figure { display: grid; justify-items: center; min-width: 0; }
.cs-listed-phone { width: calc(164 * var(--u)); }
.cs-listed-phone .cs-phone { width: 100%; }
.cs-listed .cs-cap { margin-top: calc(14 * var(--u)); text-align: center; }
/* the window, a little rounder than a screen's, with the browser's bar
   over the dashboard: its three lights, and the address in its field */
.cs-browser { width: 100%; border-radius: calc(12 * var(--u)); }
.cs-browser-bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(7 * var(--u));
  height: calc(32 * var(--u));
  padding: 0 calc(13 * var(--u));
  background: linear-gradient(#f8f8f9, #efeff1);
  box-shadow: inset 0 -1px 0 rgb(0 0 0 / 0.08);
}
.cs-browser-bar i {
  width: calc(11 * var(--u));
  height: calc(11 * var(--u));
  border-radius: 50%;
  background: #ff5f57;
  box-shadow: inset 0 0 0 0.5px rgb(0 0 0 / 0.14);
}
.cs-browser-bar i:nth-child(2) { background: #febc2e; }
.cs-browser-bar i:nth-child(3) { background: #28c840; }
.cs-browser-bar span {
  position: absolute;
  left: 50%;
  translate: -50% 0;
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  height: calc(20 * var(--u));
  padding: 0 calc(16 * var(--u));
  border-radius: calc(6 * var(--u));
  background: rgb(0 0 0 / 0.05);
  font-size: max(10px, calc(11.5 * var(--u)));
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  color: #6e6e73;
}
.cs-browser-bar svg { width: calc(10 * var(--u)); height: calc(10 * var(--u)); }

/* ---- PantryPal: what I learned, as the loop it is ----
   The four stops every chapter went round, a drawing to each in the story
   map's hand on the map's own plinth, its number on the plinth's foot as
   the map's are; an arrow in each gutter on to the next stop, and from the
   last a line back under the row to the first: and round again. Under the
   loop, what every lap leaves behind, the system, a tile of its own with
   its drawing beside its words. (Four lessons stood here as sentences on
   hairlines, each lesson and its reason at the one size.) */
.cs-loop {
  --loop-gap: calc(28 * var(--u));
  --loop-ink: color-mix(in oklab, var(--accent) 60%, transparent);
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: repeat(3, auto);
  column-gap: var(--loop-gap);
  padding-bottom: calc(50 * var(--u));
  list-style: none;
}
/* the stops share three rows, so every name and every reason starts
   level with its neighbours' */
.cs-loop li { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; align-content: start; }
.cs-loop-pic {
  position: relative;
  aspect-ratio: 4 / 3.2;
  margin-bottom: calc(24 * var(--u));
  border-radius: calc(20 * var(--u));
  background:
    radial-gradient(130% 75% at 0% 0%, color-mix(in oklab, var(--tint), #fff 70%), transparent 72%),
    linear-gradient(to bottom, color-mix(in oklab, var(--tint), #fff 38%), var(--tint) 62%);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent);
}
.cs-loop-pic img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.cs-loop-pic .cs-chapter-num { position: absolute; z-index: 1; left: calc(16 * var(--u)); bottom: 0; translate: 0 50%; zoom: 0.5; }
/* on to the next: a white button's arrow in the app's ink, across the
   gutter between two plinths */
.cs-loop li:not(:last-child) .cs-loop-pic::after {
  content: '';
  position: absolute;
  z-index: 2;
  top: 50%;
  right: calc(-0.5 * var(--loop-gap));
  width: calc(32 * var(--u));
  height: calc(32 * var(--u));
  translate: 50% -50%;
  border-radius: 50%;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231e1e1e' stroke-width='2.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13'/%3E%3Cpath d='m12.5 6 6 6-6 6'/%3E%3C/svg%3E") center / 58% no-repeat;
  box-shadow: 0 0 0 2px #1e1e1e, 0 calc(4 * var(--u)) calc(8 * var(--u)) color-mix(in oklab, var(--deep) 22%, transparent);
}
.cs-loop b { margin-bottom: calc(6 * var(--u)); font-weight: inherit; font-size: var(--t-name); line-height: 1.2; letter-spacing: -0.014em; color: var(--ink); text-wrap: balance; }
.cs-loop li > span:last-child { font-size: var(--t-small); line-height: 1.5; color: var(--ink-3); text-wrap: pretty; }
/* and round again: a line from under the last stop back under the row
   to the first, where it turns up into an arrowhead, its words on it */
.cs-loop::before {
  content: '';
  position: absolute;
  left: calc((100% - 3 * var(--loop-gap)) / 8);
  right: calc((100% - 3 * var(--loop-gap)) / 8);
  bottom: calc(14 * var(--u));
  height: calc(26 * var(--u));
  border: 2px solid var(--loop-ink);
  border-top: 0;
  border-radius: 0 0 calc(16 * var(--u)) calc(16 * var(--u));
}
.cs-loop > li:first-child::after {
  content: '';
  position: absolute;
  left: calc((100% - 3 * var(--loop-gap)) / 8 + 1px);
  bottom: calc(36 * var(--u));
  width: calc(11 * var(--u));
  height: calc(11 * var(--u));
  translate: -50% 0;
  rotate: 45deg;
  border-top: 2px solid var(--loop-ink);
  border-left: 2px solid var(--loop-ink);
}
.cs-loop::after {
  content: 'and round again';
  position: absolute;
  left: 50%;
  bottom: calc(14 * var(--u));
  translate: -50% 50%;
  padding: 0 calc(12 * var(--u));
  background: var(--bg);
  font-size: var(--t-micro);
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--accent);
}
/* What every lap leaves behind: the cookbook and its robot beside the
   lesson the loop adds up to, at a tile's name size, and why */
.cs-keep {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  align-items: center;
  column-gap: calc(32 * var(--u));
  margin-top: calc(30 * var(--u));
  padding: calc(14 * var(--u)) calc(44 * var(--u)) calc(14 * var(--u)) calc(14 * var(--u));
}
.cs-tile.cs-keep > * + * { margin-top: 0; }
/* the drawing without the air over and under it, which its own canvas
   keeps for the story map's taller plinth */
.cs-keep-pic img { display: block; width: 100%; height: auto; aspect-ratio: 800 / 500; object-fit: cover; object-position: 50% 62%; }
.cs-keep-words { display: grid; justify-items: start; gap: calc(10 * var(--u)); }
.cs-keep .cs-eyebrow { color: var(--tile-ink); }
.cs-keep-name { font-size: calc(26 * var(--u)); line-height: 1.12; letter-spacing: -0.024em; color: var(--pastel-ink); text-wrap: balance; }
.cs-keep .cs-tile-meta strong { font-weight: inherit; color: var(--pastel-ink); }
/* Where the dashboard beside the phone would come down too small to read,
   the phone over it, and the dashboard the column's whole width, its
   address after the lights rather than centred over them (centred, it ran
   into them in a phone's column) */
@container lane (max-width: 640px) {
  .cs-listed { grid-template-columns: minmax(0, 1fr); row-gap: 30px; padding: 28px 20px 22px; }
  .cs-listed-phone { width: min(210px, 60%); }
  .cs-browser-bar span { position: static; translate: none; min-width: 0; margin-left: 8px; padding: 0 10px; overflow: hidden; text-overflow: ellipsis; }
}
/* The loop down the column, a stop to a row, its drawing beside its words
   and each arrow pointing down to the next, with the way round again said
   at its foot (four across, each stop's words ran a word or two to a
   line), and the system's drawing over its words */
@container lane (max-width: 680px) {
  .cs-loop { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; row-gap: 30px; padding-bottom: 34px; }
  .cs-loop li { grid-row: auto; grid-template-rows: auto 1fr; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); column-gap: 18px; align-items: start; }
  .cs-loop-pic { grid-row: span 2; align-self: center; margin-bottom: 0; }
  .cs-loop b { align-self: end; }
  .cs-loop li:not(:last-child) .cs-loop-pic::after { top: auto; right: auto; left: 50%; bottom: -15px; width: 28px; height: 28px; translate: -50% 50%; rotate: 90deg; }
  .cs-loop::before, .cs-loop > li:first-child::after { display: none; }
  .cs-loop::after { content: '\21BA  and round again'; left: 0; bottom: 0; translate: 0; padding: 0; background: none; font-size: 12px; }
  .cs-keep { grid-template-columns: minmax(0, 1fr); row-gap: 4px; padding: 10px 22px 24px; }
  .cs-keep-pic { justify-self: center; width: min(100%, 360px); }
}

/* ---- the story map, wired ----
   Vicino's four are wired one into the next, as nodes are. */
.cs-storymap.is-wired .cs-storymap-pic { overflow: visible; }
/* the wire out of each picture's right edge, across the gap to the next,
   and the output port it leaves from */
.cs-storymap.is-wired li:not(:last-child) .cs-storymap-pic::before {
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  width: calc(16 * var(--u));
  height: calc(2 * var(--u));
  translate: 0 -50%;
  background: #9b9cf1;
}
.cs-storymap.is-wired li:not(:last-child) .cs-storymap-pic::after {
  content: '';
  position: absolute;
  right: calc(-3 * var(--u));
  top: 50%;
  width: calc(6 * var(--u));
  height: calc(16 * var(--u));
  translate: 0 -50%;
  border-radius: calc(3 * var(--u));
  background: #9b9cf1;
  box-shadow: 0 0 0 calc(2 * var(--u)) #fff;
}

/* ---- Vicino: everything a node can be ----
   The board's own palette of node types, each with its drawing, on the
   work's white paper, with the wires' four colours keyed in the head.
   Each type is a chip, its drawing before its name, the way the board's
   own add menu lists them, so the fourteen take three short rows. (Each
   was a tile with its drawing over its name, seven to a row, and the
   palette stood as tall as the sketchbook over it.) */
.cs-palette { padding: calc(26 * var(--u)) calc(28 * var(--u)) calc(28 * var(--u)); }
.cs-tile.cs-palette > * + * { margin-top: 0; }
.cs-palette-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: calc(12 * var(--u)) calc(24 * var(--u)); margin-bottom: calc(18 * var(--u)); }
.cs-wires { display: flex; flex-wrap: wrap; gap: calc(6 * var(--u)) calc(16 * var(--u)); font-size: var(--t-small); line-height: 1; color: var(--ink-3); }
.cs-wires span { display: inline-flex; align-items: center; gap: calc(8 * var(--u)); }
.cs-wires i { width: calc(24 * var(--u)); height: calc(3 * var(--u)); border-radius: 99px; background: var(--dot); }
/* every node the same width, as many to a row as the widest of them,
   "Sketch to Image", lets stand whole, so they stand in columns as the
   board's add menu lists them (they ran in a ragged cloud, a row of six
   over a row of five over three) */
.cs-palette-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(calc(178 * var(--u)), 1fr)); gap: calc(8 * var(--u)); list-style: none; }
.cs-palette-grid li {
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--u));
  min-width: 0;
  padding: calc(5 * var(--u)) calc(14 * var(--u)) calc(5 * var(--u)) calc(5 * var(--u));
  border-radius: calc(14 * var(--u));
  background: #f6f8f8;
  box-shadow: inset 0 0 0 1px rgb(15 23 42 / 0.05);
  font-size: var(--t-small);
  line-height: 1.2;
  letter-spacing: 0;
  white-space: nowrap;
  color: #1d1d1f;
}
.cs-palette-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  border-radius: calc(10 * var(--u));
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.07), 0 calc(6 * var(--u)) calc(12 * var(--u)) calc(-6 * var(--u)) color-mix(in oklab, var(--deep) 40%, transparent);
  color: var(--deep);
}
.cs-palette-ico svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
html.rises .cs-palette:not(.is-risen) .cs-palette-grid li { opacity: 0; scale: 0.9; }
.cs-palette.is-risen .cs-palette-grid li { transition: opacity 0.3s ease, scale var(--t-pop) var(--spring-pop); transition-delay: calc(var(--i) * 35ms + 150ms); }

/* the two ways' heads: which hand, then what it does */
.cs-way .cs-eyebrow { color: var(--tile-ink); }
.cs-tile.cs-way > .cs-tile-name { margin-top: calc(4 * var(--u)); }
/* the board and the agent's panel each stand clear of the line over
   them, however little room the tile has to spare (at its own size, in a
   wide column, the board stood touching the words); 16, not 20, so the
   pair and its replay still end inside a 1910 by 960 window */
.cs-tile.cs-way > .cs-tile-name { margin-bottom: calc(16 * var(--u)); }

/* ---- Vicino: the system's four principles, and its palette as a ramp ----
   Both two to a row, beside the brand book: each principle a frosted chip
   with its number before it, and the ten colours of the ramp in two runs
   of five. (They stood four and ten across the whole column, over the
   book, when the tile's words stood over its work.) */
.cs-principles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(6 * var(--u));
  margin-top: calc(18 * var(--u)) !important;
  list-style: none;
}
.cs-principles li {
  display: flex;
  align-items: baseline;
  gap: calc(10 * var(--u));
  padding: calc(10 * var(--u)) calc(12 * var(--u));
  border-radius: calc(12 * var(--u));
  background: rgb(255 255 255 / 0.62);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.7);
  font-size: var(--t-small);
  line-height: 1.3;
  color: var(--pastel-ink);
  text-wrap: balance;
}
.cs-principles b { font-weight: inherit; font-size: var(--t-micro); letter-spacing: 0.06em; font-variant-numeric: tabular-nums; color: var(--accent); }
.cs-system-label { margin-top: calc(22 * var(--u)) !important; margin-bottom: calc(10 * var(--u)); color: var(--tile-ink-2); }
.cs-ramp {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: calc(12 * var(--u)) calc(3 * var(--u));
  list-style: none;
}
.cs-ramp li { display: grid; gap: calc(3 * var(--u)); min-width: 0; font-size: max(10px, calc(11.5 * var(--u))); line-height: 1.25; font-variant-numeric: tabular-nums; color: var(--tile-ink-2); }
.cs-ramp i {
  display: block;
  height: calc(36 * var(--u));
  margin-bottom: calc(6 * var(--u));
  background: var(--c);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.06);
  transform-origin: 50% 100%;
}
/* each run of five is rounded at its own two ends */
.cs-ramp li:nth-child(5n + 1) i { border-radius: calc(12 * var(--u)) 0 0 calc(12 * var(--u)); }
.cs-ramp li:nth-child(5n) i { border-radius: 0 calc(12 * var(--u)) calc(12 * var(--u)) 0; }
.cs-ramp b { font-weight: inherit; color: var(--pastel-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
html.rises .cs-system:not(.is-risen) .cs-ramp i { scale: 1 0; }
.cs-system.is-risen .cs-ramp i { transition: scale 0.7s var(--ease-rise); }
.cs-ramp li:nth-child(2) i { transition-delay: 40ms; } .cs-ramp li:nth-child(3) i { transition-delay: 80ms; }
.cs-ramp li:nth-child(4) i { transition-delay: 120ms; } .cs-ramp li:nth-child(5) i { transition-delay: 160ms; }
.cs-ramp li:nth-child(6) i { transition-delay: 200ms; } .cs-ramp li:nth-child(7) i { transition-delay: 240ms; }
.cs-ramp li:nth-child(8) i { transition-delay: 280ms; } .cs-ramp li:nth-child(9) i { transition-delay: 320ms; }
.cs-ramp li:nth-child(10) i { transition-delay: 360ms; }

/* the accent study's four candidates, the winner ringed */
.cs-accents { display: inline-flex; gap: calc(6 * var(--u)); }
.cs-accents i { width: calc(18 * var(--u)); height: calc(18 * var(--u)); border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08); }
.cs-accents i.is-won { box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08), 0 0 0 calc(2.5 * var(--u)) #fff, 0 0 0 calc(4.5 * var(--u)) var(--deep); }

/* ---- Vicino: the guide, and the list of what it must never do ----
   The guide runs beside its never list, which is set as a check the
   machine runs against itself: a dark editor's panel in the system's own
   ink-800, every rule a red cross with its name and its reason, and the
   conditions that fail the output at its foot, ticking in one by one as
   the panel rises. */
.cs-guide-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap);
  align-items: stretch;
}
.cs-guide-pair .cs-guide-doc { display: flex; flex-direction: column; }
.cs-guide-pair .cs-guide-doc .cs-window { flex: 1; aspect-ratio: auto; min-height: calc(320 * var(--u)); }
.cs-tile.cs-lint {
  padding: 0;
  background: #1d1d1f;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06), 0 calc(40 * var(--u)) calc(60 * var(--u)) calc(-40 * var(--u)) rgb(0 0 0 / 0.55);
  color: #e8eaed;
}
.cs-tile.cs-lint > * + * { margin-top: 0; }
.cs-lint-head {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  padding: calc(14 * var(--u)) calc(18 * var(--u));
  border-bottom: 1px solid rgb(255 255 255 / 0.08);
  font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;
  font-size: var(--t-micro);
  letter-spacing: 0;
  color: #9aa3ad;
}
.cs-lint-head b { margin-left: auto; font-weight: 400; letter-spacing: 0.12em; text-transform: uppercase; color: #ffb366; }
.cs-lint-lights { display: inline-flex; gap: calc(6 * var(--u)); }
.cs-lint-lights i { width: calc(10 * var(--u)); height: calc(10 * var(--u)); border-radius: 50%; background: #3a3d43; }
.cs-lint-lights i:first-child { background: #ff5f57; } .cs-lint-lights i:nth-child(2) { background: #febc2e; } .cs-lint-lights i:last-child { background: #28c840; }
.cs-lint-list { padding: calc(4 * var(--u)) 0; list-style: none; }
.cs-lint-list li {
  display: grid;
  grid-template-columns: calc(26 * var(--u)) minmax(0, 1fr);
  column-gap: calc(6 * var(--u));
  padding: calc(7 * var(--u)) calc(18 * var(--u));
}
.cs-lint-list li:nth-child(odd) { background: rgb(255 255 255 / 0.02); }
.cs-lint-x { grid-row: 1 / 3; padding-top: calc(2 * var(--u)); font-size: var(--t-small); line-height: 1.2; color: #ff6b6b; }
.cs-lint-list b { font-weight: 500; font-size: var(--t-small); line-height: 1.3; letter-spacing: 0; color: #f4f5f6; }
.cs-lint-list span:last-child { font-size: var(--t-micro); line-height: 1.5; letter-spacing: 0.005em; color: #9aa3ad; text-wrap: pretty; }
.cs-lint-fail {
  padding: calc(12 * var(--u)) calc(18 * var(--u)) calc(14 * var(--u));
  border-top: 1px dashed rgb(255 255 255 / 0.12);
  font-size: var(--t-micro);
  line-height: 1.55;
  color: #9aa3ad;
  text-wrap: pretty;
}
.cs-lint-fail b { font-weight: 400; color: #ffb366; }
html.rises .cs-lint:not(.is-risen) .cs-lint-list li { opacity: 0; translate: calc(-8 * var(--u)) 0; }
.cs-lint.is-risen .cs-lint-list li { transition: opacity 0.3s ease, translate 0.5s var(--ease-rise); transition-delay: calc(var(--i) * 110ms + 250ms); }

/* ---- Vicino: ninety findings, on the severity ladder ----
   One bar, cut by severity in the system's own colours (its red for a
   blocker, amber for friction, cyan for polish), each part as wide as
   its share of the ninety; the counts stand under their own part. They
   stand in the review's own tile, beside the review they were written
   up in. (They were a tile of their own over it, and the chapter took a
   window and a half.) */
.cs-severity { display: grid; gap: calc(14 * var(--u)); }
.cs-wide-words > .cs-severity { margin-top: calc(24 * var(--u)); }
.cs-severity-total { display: flex; align-items: center; gap: calc(6 * var(--u)) calc(18 * var(--u)); }
.cs-severity-total b { flex: none; font-weight: inherit; font-size: calc(80 * var(--u)); line-height: 0.9; letter-spacing: -0.05em; font-variant-numeric: tabular-nums; color: var(--pastel-ink); }
.cs-severity-total > span { max-width: 20em; font-size: var(--t-small); line-height: 1.42; color: var(--tile-ink); }
/* the bar is cut in proportion, and the counts under it stand evenly:
   in the review's half of the tile, eleven-ninetieths is too narrow to
   hold its own word */
.cs-severity-bar, .cs-severity-key { display: grid; grid-template-columns: 11fr 47fr 32fr; gap: calc(4 * var(--u)); }
.cs-severity-key { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cs-severity-bar i { height: calc(30 * var(--u)); border-radius: calc(8 * var(--u)); transform-origin: 0 50%; }
.cs-severity .is-block { --s: #ef4444; }
.cs-severity .is-friction { --s: #f19a08; }
.cs-severity .is-polish { --s: #49e0f5; }
.cs-severity-bar i { background: var(--s); }
html.rises [data-rise]:not(.is-risen) .cs-severity-bar i { scale: 0 1; }
.is-risen .cs-severity-bar i { transition: scale 0.9s var(--ease-rise) 0.3s; }
.is-risen .cs-severity-bar i + i { transition-delay: 0.45s; }
.is-risen .cs-severity-bar i + i + i { transition-delay: 0.6s; }
.cs-severity-key div { display: grid; align-content: start; gap: calc(4 * var(--u)); min-width: 0; }
.cs-severity-key dd { order: -1; font-size: calc(28 * var(--u)); line-height: 1; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; color: var(--pastel-ink); }
.cs-severity-key dt { display: flex; align-items: center; gap: calc(6 * var(--u)); font-size: var(--t-micro); letter-spacing: 0.04em; color: var(--tile-ink); white-space: nowrap; }
.cs-severity-key dt::before { content: ''; width: calc(8 * var(--u)); height: calc(8 * var(--u)); border-radius: 50%; background: var(--s); }

/* ---- five numbers, read across like a results line ----
   each number over what it counts: in one row where the column is wide
   enough, three over two in the column (below, "in a narrower lane"),
   each tile short (they stood 210 tall, and took more room than the
   chapters they summed up) */
.cs-stats.is-five { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.cs-stats.is-five > :last-child { grid-column: auto; }
.cs-stats.is-five .cs-stat { min-height: 0; align-content: start; gap: calc(16 * var(--u)); padding: calc(24 * var(--u)); }
.cs-stats.is-five .cs-stat b { font-size: calc(56 * var(--u)); }
.cs-stats.is-five .cs-stat b small { display: block; flex-basis: 100%; margin: calc(6 * var(--u)) 0 0; font-size: var(--t-small); }

/* ---- lessons, as a chain: one into the next, as Vicino's chapters run ---- */
.cs-lessons.is-chain { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cs-lessons.is-chain li { position: relative; border-top-color: transparent; }
.cs-lessons.is-chain li::after {
  content: '';
  position: absolute;
  left: 0;
  right: calc(-1 * var(--gap));
  top: -1px;
  height: calc(2 * var(--u));
  background: color-mix(in oklab, #9b9cf1 70%, #fff);
}
.cs-lessons.is-chain li:last-child::after { right: 0; }
/* the number is a node on the wire, so it stands over it: the wire is
   placed, and painted after anything that is not, so without a layer of
   its own the number's white card was drawn under the wire, which struck
   each number through */
.cs-lessons.is-chain li::before {
  position: relative;
  z-index: 1;
  width: max-content;
  padding: calc(4 * var(--u)) calc(9 * var(--u));
  border-radius: calc(8 * var(--u));
  background: #fff;
  box-shadow: 0 0 0 1px rgb(15 23 42 / 0.08);
  color: #1d1d1f;
  translate: 0 calc(-34 * var(--u));
  margin-bottom: calc(-14 * var(--u));
}
.cs-lessons.is-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* ---- Next Level: his answers in three words, and the question ----
   The three words, each its icon over the word, and beside them, as the
   chat would put it, the question they raised: what the interview came
   to, in one row. (The words were three tiles across the column, and the
   question stood alone under them, a row of its own.) */
.cs-distilled { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: calc(32 * var(--u)); align-items: end; }
.cs-distilled .cs-bubble.is-q { max-width: 100%; }
.cs-pillars-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(12 * var(--u)); list-style: none; }
.cs-pillars-row li {
  display: grid;
  gap: calc(16 * var(--u));
  padding: calc(18 * var(--u)) calc(18 * var(--u)) calc(20 * var(--u));
  border-radius: var(--r-tile);
  background:
    radial-gradient(130% 75% at 0% 0%, color-mix(in oklab, var(--tint), #fff 70%), transparent 72%),
    linear-gradient(to bottom, color-mix(in oklab, var(--tint), #fff 38%), var(--tint) 62%);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--deep) 9%, transparent);
}
/* each tile is a container, so its word can be set as big as the tile
   holds it: "dependability" at 40 is wider than a third of a narrow lane */
.cs-pillars-row li { container-type: inline-size; }
.cs-pillar-ico { display: grid; place-items: center; width: calc(38 * var(--u)); height: calc(38 * var(--u)); border-radius: 50%; background: #fff; box-shadow: inset 0 0 0 calc(1.5 * var(--u)) #0495eb; color: #0495eb; }
.cs-pillar-ico svg { width: calc(22 * var(--u)); height: calc(22 * var(--u)); fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.cs-pillars-row b { font-weight: inherit; font-size: min(calc(28 * var(--u)), 15cqw); line-height: 1; letter-spacing: -0.035em; color: var(--pastel-ink); }
html.rises .cs-pillars:not(.is-risen) .cs-pillars-row li { opacity: 0; translate: 0 calc(14 * var(--u)); }
.cs-pillars.is-risen .cs-pillars-row li { transition: opacity 0.4s ease, translate var(--t-settle) var(--spring-settle); transition-delay: calc(var(--i) * 120ms + 150ms); }

/* ---- Next Level: the mark, on its construction ----
   The badge on a brand book's plate: the guides it is built on drawn
   over it in hairlines of its own blue, one after another as the plate
   rises (the circle, its outer ring, the axis through the drone, then
   the wordmark's cap lines and baselines), each named at its end. The
   numbers are the badge's own, measured off the shipped file: the circle
   centred at 254, 254 with a radius of 226, and the two lines of the name
   standing on 259 and 320. A switch takes the guides away. */
.cs-construct {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: calc(48 * var(--u));
  align-items: center;
  /* the guides are named at their left ends, in the plate's own margin */
  padding: calc(56 * var(--u)) calc(44 * var(--u)) calc(56 * var(--u)) calc(118 * var(--u));
  background-image:
    linear-gradient(rgb(4 149 235 / 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgb(4 149 235 / 0.06) 1px, transparent 1px);
  background-size: calc(24 * var(--u)) calc(24 * var(--u));
}
.cs-tile.cs-construct > * + * { margin-top: 0; }
.cs-construct-plate { position: relative; aspect-ratio: 516 / 518; }
.cs-construct-plate > img { display: block; width: 100%; height: auto; }
.cs-construct-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  stroke: #0495eb;
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}
.cs-construct-lines > * { stroke-dasharray: 1; stroke-dashoffset: 0; vector-effect: non-scaling-stroke; }
.cs-construct-lines .is-faint { stroke-dasharray: 0.006 0.006; opacity: 0.7; }
html.rises .cs-construct:not(.is-risen) .cs-construct-lines > * { stroke-dashoffset: 1; }
html.rises .cs-construct:not(.is-risen) .cs-construct-lines .is-faint { opacity: 0; }
.cs-construct.is-risen .cs-construct-lines > * { transition: stroke-dashoffset 1.1s var(--ease-draw), opacity 0.6s ease; transition-delay: calc(var(--k) * 140ms + 300ms); }
.cs-construct-tag {
  position: absolute;
  left: calc(var(--x) * 1%);
  top: calc(var(--y) * 1%);
  translate: -50% -50%;
  padding: calc(3 * var(--u)) calc(8 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgb(4 149 235 / 0.35);
  font-size: max(10px, calc(11 * var(--u)));
  line-height: 1.2;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: #0b6db0;
  transition: opacity 0.4s ease;
  transition-delay: calc(var(--k) * 140ms + 900ms);
}
.cs-construct-tag.is-side { translate: 0 -50%; }
.cs-construct-tag.is-left { translate: -100% -50%; }
html.rises .cs-construct:not(.is-risen) .cs-construct-tag { opacity: 0; }
.cs-construct.is-bare .cs-construct-lines, .cs-construct.is-bare .cs-construct-tag { opacity: 0 !important; transition: opacity 0.3s ease !important; }
.cs-construct-lines { transition: opacity 0.3s ease; }
.cs-construct-words { display: grid; gap: calc(10 * var(--u)); }
.cs-construct-words .cs-eyebrow { color: #0b6db0; }
.cs-construct-words .cs-tile-name { font-size: calc(30 * var(--u)); line-height: 1.12; letter-spacing: -0.026em; text-wrap: balance; }
.cs-construct-words .cs-tile-meta { color: var(--ink-3); font-size: var(--t-body); line-height: 1.5; }
.cs-construct-words .cs-sketch { margin-top: calc(14 * var(--u)); max-width: none; background: #fff; }
.cs-construct-toggle { justify-self: start; margin-top: calc(6 * var(--u)); background: #fff; box-shadow: inset 0 0 0 1px rgb(4 149 235 / 0.35); -webkit-backdrop-filter: none; backdrop-filter: none; color: #0b6db0; cursor: pointer; }
.cs-construct-toggle::before { content: ''; width: calc(12 * var(--u)); height: calc(12 * var(--u)); border-radius: 50%; box-shadow: inset 0 0 0 calc(1.5 * var(--u)) #0495eb; transition: background-color 0.2s ease; }
.cs-construct-toggle[aria-pressed='true']::before { background: #0495eb; }
.cs-colorways .is-chosen { background: #fff; box-shadow: inset 0 0 0 calc(2 * var(--u)) #0495eb, 0 calc(30 * var(--u)) calc(50 * var(--u)) calc(-34 * var(--u)) color-mix(in oklab, var(--deep) 55%, transparent); }

/* ---- Next Level: the rollout ----
   The site across two thirds of the column, reading itself; the
   quarter-zip beside it; and the three socials fanned out together like
   a hand of phones under them, opening as they are pointed at. */
.cs-rollout { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* the site fills its tile's height, however tall the two beside it make it */
.cs-rollout-web { grid-column: 1 / 3; grid-row: 1 / 3; display: flex; flex-direction: column; }
.cs-rollout-web .cs-site { flex: 1; min-height: calc(340 * var(--u)); aspect-ratio: auto; }
.cs-rollout-merch { grid-column: 3; grid-row: 1; }
.cs-rollout-socials { grid-column: 3; grid-row: 2; display: flex; flex-direction: column; padding-bottom: 0; }
.cs-rollout .cs-eyebrow { color: var(--tile-ink); }
.cs-rollout .cs-tile > .cs-tile-name { margin-top: calc(4 * var(--u)); }
/* the quarter-zip's photo and the fan of socials hold their own heights,
   so the pictures in them do not set the row's (the photo's own height
   made the column, and with it the website beside it, 870 tall) */
.cs-rollout-merch .cs-photo { flex: none; height: calc(200 * var(--u)); min-height: 0; }
.cs-fan { position: relative; flex: none; display: flex; justify-content: center; align-items: flex-end; height: calc(170 * var(--u)); margin-top: calc(10 * var(--u)) !important; overflow: hidden; }
.cs-fan .cs-social {
  width: 40%;
  margin: 0 -8%;
  translate: 0 18%;
  mix-blend-mode: normal;
  filter: drop-shadow(0 calc(14 * var(--u)) calc(18 * var(--u)) color-mix(in oklab, var(--deep) 32%, transparent));
  transition: rotate var(--t-settle) var(--spring-settle), translate var(--t-settle) var(--spring-settle), margin var(--t-settle) var(--spring-settle);
}
.cs-fan .cs-social:nth-child(1) { rotate: -10deg; translate: 0 24%; }
.cs-fan .cs-social:nth-child(2) { z-index: 1; }
.cs-fan .cs-social:nth-child(3) { rotate: 10deg; translate: 0 24%; }
@media (hover: hover) {
  .cs-rollout-socials:hover .cs-social { rotate: 0deg; translate: 0 8%; margin: 0 -2%; }
}

/* ---- Next Level: the reflection's numbers, each with its picture ---- */
/* the eight that led to it share out the tile's width, and the ninth
   stands at twice their size at the end of the row (they were a fixed 30
   each, a row wider than a narrow lane's tile) */
.cs-nine { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)) minmax(0, 2.2fr); align-items: center; gap: calc(4 * var(--u)); max-width: calc(420 * var(--u)); }
.cs-nine img { width: 100%; height: auto; aspect-ratio: 1; object-fit: contain; padding: 10%; border-radius: 26%; background: #fff; opacity: 0.55; filter: grayscale(0.6); }
.cs-nine img.is-one { margin-left: calc(6 * var(--u)); width: calc(100% - 6 * var(--u)); padding: 8%; border-radius: 22%; opacity: 1; filter: none; box-shadow: 0 0 0 calc(2 * var(--u)) #0495eb; }
.cs-asks { display: flex; flex-wrap: wrap; gap: calc(6 * var(--u)); }
.cs-asks i {
  display: inline-flex;
  align-items: center;
  height: calc(30 * var(--u));
  padding: 0 calc(12 * var(--u));
  border-radius: 999px;
  background: var(--bubble);
  font-style: normal;
  font-size: var(--t-small);
  color: var(--bubble-ink);
}
.cs-asks.is-surfaces i { background: #fff; color: var(--pastel-ink); }
/* the three shrink together with their tile, keeping their sizes to
   one another, and the shipped one's ring is kept inside it (on a phone,
   two to a row, the ring ran out past the tile's edge) */
.cs-three { display: flex; align-items: center; gap: calc(10 * var(--u)); padding-right: calc(5 * var(--u)); }
.cs-three i { flex: 0 1 calc(40 * var(--u)); min-width: 0; aspect-ratio: 1; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08); }
.cs-three i.is-one { flex-basis: calc(60 * var(--u)); box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08), 0 0 0 calc(3 * var(--u)) #fff, 0 0 0 calc(5 * var(--u)) #0495eb; }

/* ======================================================================
   The chapters and their pictures, in a narrower lane
   The column is never wider than 800, so what is under 860 is how the
   pieces stand on any desktop: the rows of four and six come down to two
   and three, the rollout's site takes the column's whole width over the
   rest, and the spreads that stood two pieces side by side stand them
   one over the other where each needs the width. Under 500 every
   side-by-side piece stands its parts one over another, the words first;
   under 460, a phone's column, the grids go to one or two; and on a
   phone the reading
   sizes leave --u for plain pixels, as the rest of the page's type does
   there. The pieces ask the column they stand in, not the window (each
   section is a size container named "lane", above, "the page"); only the
   type and the spacing ask the window, because they follow the phone's
   own layout.
   ====================================================================== */
@container lane (max-width: 860px) {
  /* three over two, the two each half the row, so the row under is as
     full as the row over it (three to a row left the fifth a hole) */
  .cs-stats.is-five { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .cs-stats.is-five > * { grid-column: span 2; }
  .cs-stats.is-five > :nth-child(n + 4) { grid-column: span 3; }
  .cs-stats.cs-results { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-rollout { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-rollout-web { grid-column: 1 / -1; grid-row: auto; }
  .cs-rollout-merch, .cs-rollout-socials { grid-column: auto; grid-row: auto; }
  /* the prototype's six screens three to a view, as wide as three fit in
     the column, so the flow is read three steps at a time and the pan
     runs through the other three (at 268 two and a half stood in the
     column, the third cut off at its edge, and the pan took two windows
     of scrolling) */
  .cs-reel-track { --reel-gap: calc(32 * var(--u)); --reel-pad: calc(24 * var(--u)); gap: var(--reel-gap); padding-inline: var(--reel-pad); }
  .cs-reel-track .cs-phone { width: min(calc((100cqw - 2 * var(--reel-pad) - 2 * var(--reel-gap)) / 3), (100svh - var(--cs-top) - 220 * var(--u)) * 0.5); }
  /* the lessons two to a row, as the results over them stand (four to a
     row, each lesson's first line broke after a word or two); a chain's
     wire runs on from the first of a row to the second and ends there */
  .cs-lessons, .cs-lessons.is-chain { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-lessons.is-chain { --lesson-gap: calc(56 * var(--u)); }
  .cs-lessons.is-chain li:nth-child(2n)::after { right: 0; }
  /* how it was built, two steps to a row, each its drawing beside its name
     (four to a row, "PantryPalDS" ran out of its card); the wire that runs
     along a row of four has no row to run along */
  .cs-pipe-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-pipe-steps::before, .cs-pipe-steps::after { display: none; }
  /* Next Level's three words over the question they raised, each word big
     enough to read (beside the question, each was a third of a half) */
  .cs-distilled { grid-template-columns: minmax(0, 1fr); }
}
/* The three sheets in a laptop's column, 860 to 1100 (a window of about
   1230 to 1560): four even columns, the three sheets and what the kept one
   became, the arrow standing over the shipped screen and pointing at it
   from the kept sheet's side, so each sheet's words have a quarter of the
   column rather than a sixth (beside an arrow column of their own, the
   five came out 150 wide at 1280 and set their words a word or two to a
   line). The shipped screen and the arrow over it stand as tall as a
   sheet's picture, so the row's words start level. */
/* the same, in a desktop's column only: under 500 these stand one over
   another as a phone's do */
@container lane (501px <= width <= 860px) {
  /* the nine versions: the list a little narrower, the version on show a
     little bigger beside it */
  .cs-history { grid-template-columns: minmax(0, 1fr) calc(290 * var(--u)); }
  /* the badge on its construction over the words about it, as big as it
     can stand with its guides named in its margin (beside the words it
     came out 260 wide, and the three guides named down its left side
     stood touching) */
  .cs-construct { grid-template-columns: minmax(0, 1fr); gap: calc(36 * var(--u)); padding: calc(48 * var(--u)) calc(40 * var(--u)) calc(40 * var(--u)); }
  .cs-construct-plate { justify-self: center; width: calc(360 * var(--u)); }
  /* the words beside the drawing at the badge's heart, and the switch for
     the guides under it */
  .cs-construct-words { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); column-gap: calc(32 * var(--u)); row-gap: calc(10 * var(--u)); align-items: start; }
  .cs-construct-words > * { grid-column: 1; }
  .cs-construct-words > .cs-sketch { grid-column: 2; grid-row: 1 / span 2; align-self: end; margin-top: 0; }
  .cs-construct-words > .cs-construct-toggle { grid-column: 2; grid-row: 3; margin-top: calc(4 * var(--u)); }
}
@container lane (max-width: 500px) {
  /* the next case's tile, words over work: its words stand in the flow
     (the inset that held them off the tile's foot would only lift them
     out of its top), and its art, a span, needs to be a block to be given
     a height at all once it is no longer laid over the tile */
  .cs-next .cs-hero-words { bottom: auto; }
  .cs-next .cs-hero-art { display: block; }
  /* the story map runs sideways under a finger, a chapter at a time */
  .cs-storymap {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(150px, 1fr);
    padding: 4px 0 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .cs-storymap::-webkit-scrollbar { display: none; }
  .cs-storymap li { scroll-snap-align: start; }
  .cs-pipes { padding: 24px; }
  .cs-belt-stats { grid-template-columns: minmax(0, 1fr); padding: 0 28px; }
  .cs-belts { padding: 28px 0; }
  .cs-lessons.is-three { grid-template-columns: minmax(0, 1fr); }
  .cs-guide-pair { grid-template-columns: minmax(0, 1fr); }
  .cs-stats.is-five { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-stats.is-five > *, .cs-stats.is-five > :nth-child(n + 4) { grid-column: auto; }
  .cs-stats.is-five > :last-child { grid-column: 1 / -1; }
  /* one over another, each its drawing beside its word, so the three
     are three short rows (each stood a tile tall, its word at 32, and the
     three took most of a phone's screen) */
  .cs-pillars-row { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .cs-pillars-row li { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 14px; padding: 14px 18px; }
  .cs-interview { grid-template-columns: minmax(0, 1fr); grid-template-areas: 'ask' 'chat' 'who'; }
  .cs-interview > .cs-chips { flex-direction: row; }
  .cs-construct { grid-template-columns: minmax(0, 1fr); gap: 32px; padding: 40px 28px 32px 92px; }
  .cs-palette { padding: 24px; }
}
/* the grids in a narrow lane, a phone's or a narrow window's */
@container lane (max-width: 460px) {
  /* the results a number to a row, as Vicino's are (two to a row, each
     number's words broke a word or two to a line, and the pictures of
     the fifty dishes and the nine versions came out too small to read) */
  .cs-stats.cs-results { grid-template-columns: minmax(0, 1fr); }
  .cs-stats.is-five { grid-template-columns: minmax(0, 1fr); }
  /* one to a row, a chain's wire ends at each lesson's own edge (it ran
     on past the column by a gap, toward a neighbour that was not there) */
  .cs-lessons, .cs-lessons.is-chain { grid-template-columns: minmax(0, 1fr); --lesson-gap: 40px; }
  .cs-lessons.is-chain li:nth-child(n)::after { right: 0; }
  .cs-pipe-steps { gap: 10px; }
  /* two to a row, a step's drawing stands over its name again: beside it,
     "PantryPalDS" ran out past its tile and "the screens" broke in two */
  .cs-pipe-steps li { grid-template-columns: minmax(0, 1fr); justify-items: start; padding: 14px 12px 16px; }
  .cs-rollout { grid-template-columns: minmax(0, 1fr); }
  .cs-end-head { flex-direction: column; gap: 4px; }
}
@media (max-width: 760px) {
  .cs {
    --t-display: clamp(40px, 11.5vw, 52px);
    --t-title: 28px;
    --t-lead: 20px;
    --t-body: 16.5px;
    --t-name: 17px;
    --t-small: 14px;
    --t-micro: 11px;
    --measure: 100%;
    /* the same steps, a phone's size */
    --air-cap: 10px;
    --air-work: 28px;
    --air-head: 22px;
    --air-part-head: 16px;
    --air-part: 72px;
    --air-chapter: 120px;
  }
  .cs-main { line-height: 1.55; }
  .cs-next .cs-hero-name { font-size: 32px; }
  .cs-chapter-top { margin-bottom: 20px; gap: 12px; }
  .cs-chapter-deck { margin-top: 10px; }
  .cs-part-num { margin-bottom: 10px; }
  [data-case='pantrypal'] .cs-chapter-num { font-size: 40px; -webkit-text-stroke-width: 4px; }
  [data-case='pantrypal'] .cs-chapter-num.is-word { height: 36px; padding: 0 14px; font-size: 17px; }
  .cs-waste-words .cs-waste-num, .cs-endless-words .cs-endless-num { font-size: min(64px, 24cqw); }
  .cs-stat b { font-size: 60px; }
  .cs-stats.is-five .cs-stat b { font-size: 56px; }
  .cs-results .cs-stat { min-height: 0; }
  .cs-severity-total b { font-size: 64px; }
  .cs-type-aa { font-size: 76px; }
  .cs-pillars-row b { font-size: 24px; }
  .cs-construct { padding: 32px 20px 28px 76px; }
  .cs-construct-tag { font-size: 10px; padding: 2px 6px; }
  .cs-severity-key dt { font-size: 10px; letter-spacing: 0; }
  .cs-severity-key dd { font-size: 26px; }
  .cs-belt-stats dd { font-size: 44px; }
  .cs-reel-track .cs-phone { width: 210px; }
  .cs-reel-track { gap: 24px; padding: 8px 24px; }
  .cs-ramp li { font-size: 10px; }
  /* on a phone the story map runs sideways out to the window's edges */
  .cs-storymap { margin-inline: calc(-1 * var(--gutter-l)); padding-inline: var(--gutter-l); scroll-padding-inline: var(--gutter-l); }
}

/* Under reduced motion every picture stands in its finished state: the
   belts are still, the sparks gone, the stamps down, the fan dealt, the
   counts drawn, the guides drawn, and nothing waits on a rise to show. */
@media (prefers-reduced-motion: reduce) {
  .cs-belt-row, .cs-pipe-steps::after, [data-case='vicino'] .cs-chapter-rule::after,
  .cs-hub-lights i, .cs-hub-lights i::after, .cs-hub-n, .cs-hub-bulbs i::after, .cs-hub-flag,
  .cs-ship-reel .cs-reel-track.is-dealt li { animation: none !important; }
  .cs-belt-row { flex-wrap: nowrap; }
  .cs-pipe-steps::after, [data-case='vicino'] .cs-chapter-rule::after { opacity: 0 !important; }
  /* the question's mark is there as the words are */
  .cs-chapter-rule, .cs-pin-mark path, .cs-look-paint li, .cs-kitchen-chef, .cs-kitchen-food li,
  .cs-hmw-q mark, .cs-hub-dark,
  .cs-plate img, .cs-split-bar i, .cs-palette-grid li, .cs-ramp i, .cs-lint-list li, .cs-severity-bar i,
  .cs-construct-lines > *, .cs-construct-tag, .cs-pillars-row li, .cs-pin-arrow path,
  .cs-odo-d > span, .cs-storymap-pic, .cs-storymap-pic img, .cs-pin-paper, .cs-rail, .cs-rail a span {
    transition-duration: 0.01s !important;
    transition-delay: 0s !important;
  }
}

/* ======================================================================
   The case studies in ink
   The colour poured over the site from the dot beside the name on Home
   (js/theme.js) is worn here too. The washes need nothing of their own:
   a wash changes only the paper, and everything on a case study already
   stands on the paper's own colour or on a surface of its own. Ink turns
   the page dark, and a case study is mostly the work, drawn on light
   surfaces, so the page is told apart from the work:
     the page       the reading, the heads, the hairlines, the rail's
                    margin: they take ink's own colours, as Home does, and
                    the few words set in the case's deep colour take its lit
                    one (--accent, at the head of this file)
     the work       the tiles in the case's colour, the white sheets, the
                    kitchen's tickets, the stamped and taped paper, the
                    prints, the rail's card: they stay as they are on the
                    paper, with the paper's inks, as the Work tiles do on
                    Home. They are the work, and the work was drawn light;
                    turned dark, its ink drawings and screenshots would be
                    lost, and they stand on the dark page as pictures stand
                    on a dark wall
     the controls   the capsules and chips that sit on the page take ink's
                    raised grey, as the title pill and the composer do,
                    with words to match
   ====================================================================== */
html[data-theme='ink'] .cs { --accent: var(--deep-lit); }
html[data-theme='ink'] [data-case='nextlevel'] .cs-chapter-when { color: var(--accent); }

/* the work: the paper's own inks, so whatever stands inside reads as it
   does on the paper. The page colour itself (--bg) is left alone, since
   what uses it inside is cut out of the page, not drawn on the work. */
html[data-theme='ink'] :is(.cs-tile, .cs-lit, .cs-hero-tile, .cs-next, .cs-stat, .cs-band,
  .cs-rail-in, .cs-pin-paper, .cs-chapter-num, .cs-intro-film,
  .cs-print, .cs-history-stage) {
  --ink: #444343;
  --ink-2: #8a8989;
  --ink-3: #6f6e6e;
  --ink-4: #b6b5b5;
  --fg: #1e1e1e;
  --surface: #fff;
  --pill: #e9eaeb;
  --line: 30 30 30;
  --bubble: #d0e4fd;
  --bubble-ink: #444343;
  --bubble-select: #a9cbf8;
  --accent: var(--deep);
  --tile-ink: color-mix(in oklab, var(--deep) 55%, var(--ink));
  --tile-ink-2: color-mix(in oklab, var(--deep) 45%, #5c5b5b);
  color-scheme: light;
}
/* and their words, which otherwise come down from the page already worked
   out in ink's light grey. Kept as weak as a rule can be, so a surface
   with a colour of its own (the dark editor's panel, the recipe card)
   keeps it. */
html[data-theme='ink'] :where(.cs-tile, .cs-lit, .cs-hero-tile, .cs-next, .cs-stat, .cs-band,
  .cs-rail-in, .cs-pin-paper, .cs-intro-film, .cs-print, .cs-history-stage) {
  color: var(--ink);
}

/* the controls on the page: the raised grey, with words to match (their
   ink was the pastels', for a white capsule). The one chosen keeps the
   case's tint and its dark words, and pointed at, a capsule fills with the
   tint, as the back button and the contact links do; a chip that
   turned white for it on the paper turns a step lighter grey. */
html[data-theme='ink'] :is(.cs-paper .cs-pill, .cs-paper .cs-chip:not([aria-selected='true']), .cs-replay) { color: var(--ink); }
@media (hover: hover) {
  html[data-theme='ink'] :is(.cs-paper .cs-pill, .cs-replay):hover { color: var(--pastel-ink); }
  html[data-theme='ink'] .cs-paper button.cs-chip:not([aria-selected='true']):hover { background: #3a3a3e; }
}
/* the question's last words stay marked in the app's butter, in the
   butter's own ink */
html[data-theme='ink'] .cs-hmw-q mark { color: var(--pastel-ink); }
