/* ========================================================================
   CASE PAGE TEMPLATE, from the Figma frame "Project case".
   Loaded AFTER css/cases.css and css/case-nav.css, and scoped under
   body.case-page, so the other case pages keep the old layout until they are
   moved over one by one. Markup contract: CLAUDE.md, section "Plantilla de
   caso". Behaviour (fit of the mockups): js/case-page.js.

   Everything sits on the shared grid (css/grid.css): 12 / 8 / 4 columns, 16px
   gutter, 1200px container, and 12 rows stretched to the screen height.
   Nothing here is a fixed pixel position.

   DESKTOP (>= 64em), the first screen is the 12 rows of the viewport:
     row 1        the menu bar; the 8px rule starts on its bottom edge (cols 1-3)
     rows 2-8     the head (cols 1-3, centered) and the hero (cols 4-12)
     rows 9-12    the first pair of text blocks: A on cols 4-6, B on cols 10-12
   After it comes the flow: quotes, figures (cols 4-12) and more pairs.

   TABLET (37.5em to 64em, 8 columns) and PHONE (4 columns) stack the same
   pieces on the columns: rule, head, hero, then the pair side by side on
   tablet (4 + 4 columns) and one under the other on phone.
   ======================================================================== */

/* cases.css hides horizontal overflow on html and body, which turns body into a
   scroll container and kills position: sticky. clip hides it without that. */
html:has(body.case-page),
body.case-page { overflow-x: clip; }

body.case-page {
  --cp-w: min(var(--g-content), 100% - 2 * var(--g-margin));   /* grid width */
  --cp-col: calc((var(--cp-w) - (var(--g-cols) - 1) * var(--g-gutter)) / var(--g-cols));
  --cp-inset: max(var(--g-margin), calc((100% - var(--g-content)) / 2));
  --cp-gap: var(--v-pitch);              /* vertical air between pieces */
  --cp-nav-h: var(--topnav-h, max(56px, var(--v-row)));
  /* The content grid (2026-11-09). --cp-cols columns between --cp-pad-l and
     --cp-pad-r. Defaults are the shared grid (12 / 8 / 4, centered), which
     /about/ and /media/ keep; the 14 project cases (body.cp-case) switch to
     the content-relative grid below. --cp-at-* are the desktop places of the
     shared modules on whichever grid is active. */
  --cp-cols: var(--g-cols);
  --cp-pad-l: var(--cp-inset);
  --cp-pad-r: var(--cp-inset);
  --cp-at-full: 4 / -1;
  --cp-at-text: 4 / span 4;
  --cp-at-ed: 4 / span 3;
  --cp-at-results: 5 / span 7;
  /* What lies between the right edge of the content and the right edge of the
     viewport, in vw so it works inside a margin (a % there resolves against
     the grid area). A piece that bleeds off the right edge cancels it. */
  --cp-bleed-r: max(var(--g-margin), (100vw - var(--g-content)) / 2);
  margin: 0;
  background: var(--bg, #fffaf6);
  color: var(--black, #1f1f29);
  font-family: var(--font-main);
}

body.case-page .case.cp {
  padding: 0;
  border: 0;
  background: var(--bg, #fffaf6);
  color: var(--black, #1f1f29);
}

body.case-page .cp h1,
body.case-page .cp h2,
body.case-page .cp h3 { letter-spacing: 0; }

/* ---------- The two grid containers: the first screen and the flow ---------- */
body.case-page .cp-stage,
body.case-page .cp-flow {
  display: grid;
  grid-template-columns: repeat(var(--cp-cols), minmax(0, 1fr));
  column-gap: var(--g-gutter);
  padding-left: var(--cp-pad-l);
  padding-right: var(--cp-pad-r);
  box-sizing: border-box;
}

body.case-page .cp-flow {
  row-gap: var(--cp-gap);
  padding-block: var(--cp-gap);
}

body.case-page .cp-stage > *,
body.case-page .cp-flow > * { min-width: 0; }

/* ---------- Side column: rule + head ----------
   Desktop: fixed on columns 1-3 and centred in the viewport (sticky for the
   whole height of the case); only columns 4-12 scroll. Tablet and phone stack
   it on top of the hero, no sticky (see the media queries). ---------- */
body.case-page .cp-head { flex: none; }

body.case-page .cp-crumb {
  margin: 0 0 4px;
  font-size: 8px;
  font-weight: 600;
  line-height: 1.3;
  text-transform: uppercase;
}
body.case-page .cp-crumb a { color: inherit; text-decoration: none; }
body.case-page .cp-crumb a:hover,
body.case-page .cp-crumb a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }

body.case-page .cp-title {
  margin: 0 0 8px;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.2;
  text-wrap: balance;
}

body.case-page .cp-meta {
  margin: 0;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.8px;
  text-transform: uppercase;
}

body.case-page .cp-lede {
  margin: calc(var(--v-gutter) * 1.5) 0 0;
  font-size: 14px;
  font-weight: 400;
  font-style: italic;
  color: #6b6b6b;          /* solid grey, 5.3:1 on white (readable, not faded) */
  line-height: 1.3;
}

/* ---------- Top rule ---------- */
body.case-page .cp-rule {
  align-self: end;
  height: 8px;
  margin-bottom: -8px;     /* starts where row 1 (the menu bar) ends */
  background: var(--black, #1f1f29);
}

/* ---------- Hero and figures: a mockup scaled to fit its block ---------- */
body.case-page .cp-hero,
body.case-page .cp-figure {
  position: relative;
  margin: 0;
  background: none;       /* no placeholder grey: the mockup or image is the block */
}

/* The box fills the block; the caption goes under it, on white, on the left
   column line, with a gutter of air above. */
body.case-page .cp-hero {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
}

/* The box the mockup is fitted into. Its size is what js/case-page.js reads. */
body.case-page .cp-fit {
  position: relative;
  min-height: 0;
  overflow: hidden;
}

body.case-page .cp-figure .cp-fit { aspect-ratio: var(--cp-ar, 820 / 620); }

/* A plain image or video instead of a mockup frame: shown whole (contain) on
   the grey; add .cp-fit--cover on the box to fill it and crop instead. */
body.case-page .cp-fit > img,
body.case-page .cp-fit > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: none;
}
body.case-page .cp-fit--cover > img,
body.case-page .cp-fit--cover > video { object-fit: cover; }

/* js/case-page.js scales the frame uniformly and stretches its layout on the
   other axis, so the white mockup itself fills the box on both sides. */
body.case-page .cp-fit .mockup-frame {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

body.case-page .cp-hero figcaption,
body.case-page .cp-figure figcaption {
  margin: 0;
  font-size: 10px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: normal;
  color: var(--black, #1f1f29);
}
body.case-page .cp-hero figcaption { padding: var(--v-gutter) 0 0; }
body.case-page .cp-figure figcaption { margin-top: var(--v-gutter); }

/* ---------- Pair of text blocks ----------
   Text never runs in two columns side by side (2026-11-09): people scroll down,
   so the blocks of a pair stack in one column, columns 4 to 7 (4 of 12, about
   60 characters a line), with the air of the flow between them. A block that
   continues the text of the one above (.cp-block--cont) follows it like a new
   paragraph. Text beside an image (.cp-ed) is still fine. */
body.case-page .cp-pair {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-content: start;
  align-items: start;
}
body.case-page .cp-pair:not(.cp-ed) { row-gap: var(--cp-gap); }

body.case-page .cp .cp-block {
  grid-column: var(--cp-at-text);
  min-width: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: normal;
}
body.case-page .cp-pair:not(.cp-ed) > .cp-block--cont { margin-top: calc(0.65em - var(--cp-gap)); }

/* Numbered headings: the counter runs over the whole page, so the second pair
   continues at 3 and 4. */
body.case-page .cp { counter-reset: cp; }
body.case-page .cp-block h2 {
  counter-increment: cp;
  margin: 0 0 var(--v-gutter);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}
body.case-page .cp-block h2::before { content: counter(cp) ". "; }

body.case-page .cp-block h3 {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}
body.case-page .cp-block p { margin: 0; font-size: 14px; font-weight: 400; line-height: 1.3; }
body.case-page .cp-block p + p { margin-top: 0.65em; }   /* half a line between paragraphs: the text keeps flowing */
body.case-page .cp-block h3:not(:first-child) { margin-top: 1.3em; }
/* A block that opens with an h3 keeps the same heading band as one that opens
   with a numbered h2, so the two bodies of a pair start on one line. */
body.case-page .cp-block > h3:first-child { margin-bottom: var(--v-gutter); }
/* A block that continues the text of its neighbour has no heading: js/case-page.js
   gives it the same band as a padding, so its first line meets the other body. */
body.case-page .cp-block--cont { padding-top: var(--cp-band, 0px); }

/* ---------- Running text: Geist Medium 14, no tracking ----------
   One rule for every running text of the case (the lede, the paragraphs and
   lists of the pairs, the captions), as in the Figma 'Project case' frame.
   Nothing here comes from css/cases.css: its .case__cell rules do not reach
   the template, and the tracking of 0.02em that made the text look off was
   ours (copied from the small texts of the home). */
body.case-page .cp-lede,
body.case-page .cp-block,
body.case-page .cp-block p,
body.case-page .cp-block li,
body.case-page .cp-hero figcaption,
body.case-page .cp-figure figcaption {
  font-family: var(--font-main);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  max-width: none;
}
/* Every caption is 10 px, on every case. */
body.case-page .cp-hero figcaption,
body.case-page .cp-figure figcaption { font-size: 10px; }
/* The lede is the one running text with air: 1 px of tracking at 12 px. */
body.case-page .cp-lede { letter-spacing: 1px; }

/* ---------- Quote ---------- */
body.case-page .cp-quote {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.2;
  text-wrap: balance;
}
body.case-page .cp-quote em { font-style: normal; font-weight: 400; }

/* ========================== DESKTOP, 12 columns ========================== */
@media (min-width: 64em) {
  body.case-page .cp-stage {
    min-height: 100dvh;
    grid-template-rows: repeat(var(--g-rows), minmax(var(--v-row), auto));
    row-gap: var(--v-gutter);
  }
  /* The article is one column holding the side (sticky, spanning both rows),
     the first screen and the flow. The side stays 100dvh tall at the top of the
     viewport inside its grid area, so it releases by itself when the case ends. */
  body.case-page .cp { display: grid; grid-template-columns: minmax(0, 1fr); }
  body.case-page .cp-side {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: start;
    position: sticky;
    top: 0;
    z-index: 2;
    height: 100dvh;
    box-sizing: border-box;
    width: calc(3 * var(--cp-col) + 2 * var(--g-gutter));      /* columns 1 to 3 */
    margin-left: var(--cp-inset);
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  body.case-page .cp-stage { grid-column: 1; grid-row: 1; }
  body.case-page .cp-flow { grid-column: 1; grid-row: 2; }
  /* The rule starts where row 1 (the menu bar) ends and stays with the head. */
  body.case-page .cp-rule { position: absolute; top: var(--v-row); left: 0; right: 0; margin: 0; }
  body.case-page .cp-hero { grid-column: var(--cp-at-full); grid-row: 2 / span 7; grid-template-columns: subgrid; }
  body.case-page .cp-hero .cp-fit { grid-column: 1 / -1; }
  body.case-page .cp-hero figcaption { grid-column: 1 / span 3; }
  body.case-page .cp-stage > .cp-pair { grid-row: 9 / span 4; }

  body.case-page .cp-quote,
  body.case-page .cp-figure { grid-column: var(--cp-at-full); }
  body.case-page .cp-figure { display: grid; grid-template-columns: subgrid; }
  body.case-page .cp-figure .cp-fit { grid-column: 1 / -1; }
  body.case-page .cp-figure figcaption { grid-column: 1 / span 3; }
}

/* ======================= TABLET and PHONE, stacked ======================= */
@media (max-width: 63.99em) {
  body.case-page .cp-side {
    display: grid;
    grid-template-columns: repeat(var(--g-cols), minmax(0, 1fr));
    column-gap: var(--g-gutter);
    row-gap: var(--cp-gap);
    padding: var(--cp-nav-h) var(--cp-inset) var(--cp-gap);   /* the rule starts under the menu */
    box-sizing: border-box;
  }
  body.case-page .cp-stage {
    row-gap: var(--cp-gap);
    padding-bottom: var(--cp-gap);
  }
  body.case-page .cp-rule { grid-column: 1 / span 2; margin-bottom: calc(var(--cp-gap) - var(--v-gutter)); }
  body.case-page .cp-head { grid-column: 1 / span 6; align-self: start; }
  body.case-page .cp-hero { grid-column: 1 / -1; grid-template-rows: auto auto; }
  body.case-page .cp-hero .cp-fit { aspect-ratio: var(--cp-ar, 820 / 620); }
  body.case-page .cp-quote,
  body.case-page .cp-figure { grid-column: 1 / -1; }
  body.case-page .cp-figure figcaption { max-width: none; }
  body.case-page .cp .cp-block { grid-column: 1 / span 6; }
}

@media (max-width: 37.49em) {
  body.case-page { --cp-gap: calc(var(--v-gutter) * 3); }
  body.case-page .cp-rule { grid-column: 1 / span 1; }
  body.case-page .cp-head { grid-column: 1 / -1; }
  body.case-page .cp .cp-block { grid-column: 1 / -1; }
  body.case-page .cp .cp-block--cont { padding-top: 0; }
}

/* ========================= SECTION RAIL, from Figma ========================
   Fixed, right-aligned on the page gutter, centered on the hero rows (2-8).
   The current section is 12px black, the rest 8px fading out. It needs room
   in the margin (from about 1380px); below that the dial button of
   js/case-nav.js takes over, which fits in the margin down to the desktop
   grid and works on touch. */
body.case-page .case-rail {
  right: var(--g-gutter);
  top: calc((9 * var(--v-pitch) - var(--v-gutter)) / 2);
}
body.case-page .case-rail a {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
  color: var(--black, #1f1f29);
}
body.case-page .case-rail a[data-d="0"] { font-size: 12px; color: var(--black, #1f1f29); }
body.case-page .case-rail a[data-d="1"] { color: rgba(31, 31, 41, 0.5); }
body.case-page .case-rail a[data-d="2"] { color: rgba(31, 31, 41, 0.4); }
body.case-page .case-rail a[data-d="3"] { color: rgba(31, 31, 41, 0.2); }
body.case-page .case-rail a[data-d="4"] { color: rgba(31, 31, 41, 0.12); }
body.case-page .case-rail a[data-d="5"] { color: rgba(31, 31, 41, 0.08); }
body.case-page .case-rail a:hover { color: var(--black, #1f1f29); }

/* The orb is the section index at every width (2026-11-06). The rail stays in
   the markup: js/case-nav.js reads its links and tracks the current section. */
body.case-page .case-rail { display: none; }
body.case-page .case-dial__btn { display: grid; }

/* ---------- Results: an extra, set apart from the text pairs ----------
   Columns 4 to 9 (six of the twelve), split in two stats of three columns each
   (two columns each on a phone), side by side on ONE line. Each stat is a big
   figure, its label, a row of ten person icons drawn to scale (the legend says
   what one icon is worth) and nothing else. The figure follows the width of
   the section (cqw), so the longest one ('3k -> 10k') always fits its columns.
   Tablet takes the last six of the eight columns, phone all four. */
body.case-page .cp-results {
  grid-column: var(--cp-at-results);             /* columns 5 to 11 of the page */
  container-type: inline-size;                   /* the figures follow this width (cqw) */
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));   /* the same seven columns as the page */
  column-gap: var(--g-gutter);
  /* One row each for the figure, the label, the icons and the legend, shared
     by both stats (subgrid below), so the two legends sit on the same baseline
     whatever the height of the icons above. The alert takes the last row. */
  grid-template-rows: repeat(4, auto) auto;
  row-gap: 0;
  align-items: start;
}
/* Two stats of three columns with ONE empty column between them. */
body.case-page .cp-results > .cp-result:nth-of-type(1) { grid-column: 1 / span 3; }
body.case-page .cp-results > .cp-result:nth-of-type(2) { grid-column: 5 / span 3; }
body.case-page .cp .cp-result {
  min-width: 0;
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 4;
  row-gap: 0;
}
body.case-page .cp .cp-result p { margin: 0; }
body.case-page .cp-result__n {
  font-size: 9cqw;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
body.case-page .cp-result__l,
body.case-page .cp-result__scale {
  margin-top: var(--v-gutter);
  font-size: 10px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.8px;
  text-transform: uppercase;
}
body.case-page .cp-result__scale { margin-top: calc(var(--v-gutter) / 2); opacity: 0.5; }
body.case-page .cp-result__icons {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  column-gap: calc(var(--v-gutter) / 4);
  margin-top: var(--v-gutter);
}
body.case-page .cp-icon { display: block; width: 100%; height: auto; aspect-ratio: 24 / 28; color: var(--black, #1f1f29); }
body.case-page .cp-icon.is-gone { color: rgba(31, 31, 41, 0.4); }
/* A fraction of an icon: 0.33 of the person, clipped from the left. */
body.case-page .cp-icon.is-part { clip-path: inset(0 64% 0 0); }
body.case-page .cp-result__icons { row-gap: calc(var(--v-gutter) / 4); }
/* The note under the figures is an inline alert: a box on the six columns, the
   text inset one gutter, a small info mark on the left. */
body.case-page .cp-results__note {
  grid-column: 1 / -1;
  grid-row: 5;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: calc(var(--v-gutter) * 0.75);
  align-items: start;
  margin: calc(var(--v-gutter) * 1.5) 0 0;
  padding: calc(var(--v-gutter) * 0.75) var(--v-gutter);
  border: 1px solid var(--black, #1f1f29);
  max-width: none;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: normal;
}
body.case-page .cp-results__note svg { display: block; width: 14px; height: 18px; }
@media (min-width: 37.5em) and (max-width: 63.99em) {
  body.case-page .cp-results { grid-column: 2 / -1; }       /* columns 2 to 8: seven of eight */
}
@media (max-width: 37.49em) {
  /* Four columns: two stats of two, side by side, no room for the empty one. */
  body.case-page .cp-results { grid-column: 1 / -1; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  body.case-page .cp-results > .cp-result:nth-of-type(1) { grid-column: 1; }
  body.case-page .cp-results > .cp-result:nth-of-type(2) { grid-column: 2; }
  body.case-page .cp-result__n { font-size: 10.3cqw; }
}

/* ---------- Editorial text: no widows, no orphans ----------
   Paragraphs and list items of the blocks are composed by js/typeset.js
   (as justified as its limits allow, loaded by js/sidebars.js), which sets its own text-wrap. For the
   rest, and without JS, text-wrap: pretty avoids a lonely last word; the script
   in js/case-page.js also glues the last two words with a no-break space, which
   works in every browser. Short pieces are balanced. */
body.case-page .cp p,
body.case-page .cp li,
body.case-page .cp figcaption { text-wrap: pretty; orphans: 2; widows: 2; }
body.case-page .cp-head p,
body.case-page .cp-result__l,
body.case-page .cp-result__scale { text-wrap: balance; }

/* ========================= EDITORIAL ROWS (.cp-ed) =========================
   A row of the flow where each piece names its own columns, so text and
   images play between 2, 3, 4 or 5 columns of the nine (4 to 12) depending on
   how much the image matters. Write it as <section class="cp-pair cp-ed"> and
   give each child its place with custom properties:
     --ed      desktop columns, e.g. "8 / span 5"      (default 4 / span 3)
     --ed-row  desktop rows, e.g. "1 / span 2"         (default auto)
     --ed-tab  tablet (8 columns)  (text 1 / span 6, figures 1 / -1)
     --ed-ph   phone (4 columns)   (everything 1 / -1)
     --ed-top  space above a figure (default: the heading band of the text)
   A figure starts on the body line of its neighbour, below the heading band,
   never on the title line. Tablet and phone stack in document order, so write
   the text before the figure. Every edge sits on a column line. */
body.case-page .cp-ed { --ed-band: calc(1.3 * 12px + var(--v-gutter)); }
@media (min-width: 64em) {
  body.case-page .cp .cp-ed.cp-ed > :is(.cp-block, .cp-figure) {
    grid-column: var(--ed, var(--cp-at-ed));
    grid-row: var(--ed-row, auto);
    min-width: 0;
  }
  body.case-page .cp .cp-ed.cp-ed > .cp-figure {
    display: block;
    margin: var(--ed-top, var(--ed-band)) 0 0;
  }
  body.case-page .cp .cp-ed .cp-fit { grid-column: auto; }
  /* Text never side by side: a second block goes under the first, with the air
     of the flow, or half a line when it continues the same text. */
  body.case-page .cp .cp-ed > .cp-block ~ .cp-block { margin-top: var(--cp-gap); }
  body.case-page .cp .cp-ed > .cp-block ~ .cp-block--cont { margin-top: 0.65em; }
}
@media (max-width: 63.99em) {
  body.case-page .cp-ed { row-gap: var(--cp-gap); }
  body.case-page .cp-ed > .cp-block--cont { margin-top: calc(0.65em - var(--cp-gap)); }
  body.case-page .cp .cp-ed.cp-ed > .cp-block { grid-column: var(--ed-tab, 1 / span 6); }
  body.case-page .cp .cp-ed.cp-ed > .cp-figure {
    grid-column: var(--ed-tab, 1 / -1);
    display: block;
    margin: 0;
  }
  body.case-page .cp .cp-ed .cp-fit { grid-column: auto; }
}
@media (max-width: 37.49em) {
  body.case-page .cp .cp-ed.cp-ed > :is(.cp-block, .cp-figure) { grid-column: var(--ed-ph, 1 / -1); }
}

/* Running text: 14px from 2026-11-09. On a phone (below 640px, the breakpoint
   of js/a11y.js) the sheet keeps 12px: the phone scale of 4/3 makes it 16, and
   3/2 makes it 18 in the accessible mode, the same as before. */
@media (max-width: 39.99em) {
  body.case-page .cp-lede,
  body.case-page .cp .cp-block,
  body.case-page .cp-block h2,
  body.case-page .cp-block h3,
  body.case-page .cp-block p,
  body.case-page .cp-block li,
  body.case-page .cp-hero figcaption,
  body.case-page .cp-figure figcaption,
  body.case-page .cp-results__note { font-size: 12px; }
}

/* ================== PROJECT CASES: CONTENT GRID AND ZONES ==================
   2026-11-09, from the grid study "integrate at 1200px". The 14 project cases
   carry body.cp-case; /about/ and /media/ do not, and keep the layout above.

   Every case module is placed on the CONTENT grid, never on the page grid, so
   one position works at every desktop width: "1 / span 4" is the first four
   content columns, "span 3 / -1" the last three, "1 / -1" all of them.

     > 1200px        two zones edge to edge. Left, the editorial zone: the same
                     head (title, meta, lede) on four columns of its own, at
                     least 320px wide. Right, the content: 12 full columns,
                     right-aligned, min(max(1200px, 50%), 100% - 320px) wide.
                     Both measured outside, with --cp-zone-pad inside.
     1024 to 1200    one shared grid: the head on columns 1-3, the content on
                     4-12 (9 content columns).
     below 1024      head on top, content under it on the 8 / 4 columns (the
                     rules above, unchanged).
   The G overlay (js/grid-overlay.js) reads the same tokens, so the guides are
   the tracks of the content. ======================================== */
@media (min-width: 64em) {
  body.cp-case {
    --cp-cols: 9;
    --cp-pad-l: calc(var(--cp-inset) + 3 * (var(--cp-col) + var(--g-gutter)));
    --cp-at-full: 1 / -1;
    --cp-at-text: 1 / span 4;
    --cp-at-ed: 1 / span 3;
    --cp-at-results: 2 / span 7;
  }
}

@media (min-width: 75.0625em) {
  body.cp-case {
    --cp-cols: 12;
    --cp-zone-pad: 24px;
    --cp-rail-min: 320px;
    --cp-zone-cols: 4;
    /* % of the article (the full width of the page) */
    --cp-right: min(max(var(--g-content), 50%), 100% - var(--cp-rail-min));
    --cp-pad-l: var(--cp-zone-pad);
    --cp-pad-r: var(--cp-zone-pad);
    --cp-bleed-r: var(--cp-zone-pad);
  }
  /* The inset of the editorial zone of a case (not /work/), to the left, right
     and bottom of the head: 12% of the zone (the reference), never under the
     24px of the content nor over the 72px margin. % of the zone where read. */
  body.case-page.cp-case { --cp-rail-pad: clamp(var(--cp-zone-pad), 12%, var(--g-margin)); }
  body.cp-case .cp { grid-template-columns: minmax(var(--cp-rail-min), 1fr) var(--cp-right); }
  body.cp-case .cp-stage,
  body.cp-case .cp-flow { grid-column: 2; }
  body.cp-case .cp-side {
    grid-column: 1;
    width: auto;
    margin-left: 0;
    padding-inline: var(--cp-rail-pad);
    padding-bottom: var(--cp-rail-pad);
    justify-content: flex-end;               /* the head sits in the bottom-left corner */
    container: cp-zone / inline-size;
  }
  /* The head and its rule take whole columns of the zone: all four while the
     zone is narrow, three and then two as it grows, so the lede keeps a
     reading width. Long titles wrap. */
  body.cp-case .cp-side > * {
    --cp-zcol: calc((100cqi - (var(--cp-zone-cols) - 1) * var(--g-gutter)) / var(--cp-zone-cols));
    --cp-hspan: 4;
    width: calc(var(--cp-hspan) * var(--cp-zcol) + (var(--cp-hspan) - 1) * var(--g-gutter));
  }
  @container cp-zone (min-width: 560px) { body.cp-case .cp-side > * { --cp-hspan: 3; } }
  @container cp-zone (min-width: 900px) { body.cp-case .cp-side > * { --cp-hspan: 2; } }
  /* The rule stays at the top, on columns 3 and 4 of the zone. */
  body.cp-case .cp-side > .cp-rule {
    width: auto;
    left: calc(var(--cp-rail-pad) + 2 * (var(--cp-zcol) + var(--g-gutter)));
    right: var(--cp-rail-pad);
  }
  body.cp-case .cp-title { overflow-wrap: break-word; }
  /* An editorial row may give its pieces another place on the 12 columns. */
  body.cp-case .cp .cp-ed.cp-ed > :is(.cp-block, .cp-figure) { grid-column: var(--ed-w, var(--ed, var(--cp-at-ed))); }
}

/* ---------- The top menu on the two zones (above 1200px, cases only) ----------
   css/topnav.css lays the bar on the centered 1200px grid. On a case above
   1200px it takes the zones of the page instead, so the name sits on the
   editorial zone (over the head) and the links on the content columns.
   One grid for the whole width, no padding, so every % below is of the
   viewport, like the fixed boxes (the bar, its ::before and the glass):
     track 1        8px   (+ the 16px gutter = the 24px inset of the zone)
     tracks 2-5     the four columns of the editorial zone
     track 6        16px  (gutter + 16 + gutter = the two 24px insets)
     tracks 7-18    the twelve content columns
     track 19       8px
   At rest: the name on the zone, the links on content columns 7 to 12
   (Projects 7, About 9, Media 11, CONTACT closing on 12), as on every page.
   Floating: the bar goes back to the grid of css/topnav.css, so the pill is
   the same as on the home, centered on the viewport (columns 3 to 10 of the
   1200px grid), not shifted right with the content zone (2026-11-09). */
@media (min-width: 75.0625em) {
  html.has-topnav body.cp-case {
    --nv-r: min(max(var(--g-content), 50%), 100% - var(--cp-rail-min));
    --nv-p: var(--cp-zone-pad);
    --nv-zc: calc((100% - var(--nv-r) - 2 * var(--nv-p) - 3 * var(--g-gutter)) / 4);
    --nv-cc: calc((var(--nv-r) - 2 * var(--cp-zone-pad) - 11 * var(--g-gutter)) / 12);
  }
  html.has-topnav body.case-page.cp-case {
    --nv-p: clamp(var(--cp-zone-pad), (100% - var(--nv-r)) * 0.12, var(--g-margin));   /* = --cp-rail-pad */
  }
  html.has-topnav:not(.topnav-float) body.cp-case .hero__side-menu {
    padding: 0;
    grid-template-columns:
      calc(var(--nv-p) - var(--g-gutter))
      repeat(4, var(--nv-zc))
      calc(var(--nv-p) + var(--cp-zone-pad) - 2 * var(--g-gutter))
      repeat(12, var(--nv-cc))
      calc(var(--cp-zone-pad) - var(--g-gutter));
  }
  html.has-topnav:not(.topnav-float) body.cp-case .hero__side-menu .hero__name { grid-column: 2 / span 4; }
  html.has-topnav:not(.topnav-float) body.cp-case .topnav__links { grid-column: 13 / span 6; }
}
