/* Portfolio Studio case-study layouts. Load after portfolio-studio.css, which
   supplies the tokens, base type, .section-heading and .media-caption. */

/* Opening: label, title, lead, compact facts, then the product in use. */
.case-hero { padding-top: 48px; }
.case-hero-label { margin-bottom: 16px; color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-title { font-size: clamp(2rem, calc(1.5rem + 2vw), 2.5rem); font-weight: 800; line-height: 1.15; letter-spacing: -.02em; }
/* Chinese titles keep normal tracking; Latin fragments inside them use .latin-display. */
.case-title:lang(zh) { letter-spacing: normal; }
/* Short English labels use the label face; Chinese labels stay in body Hei. */
.case-hero-label:lang(en), .case-meta dt:lang(en), .case-compare-label:lang(en) { font-family: var(--font-label); letter-spacing: .06em; }
.case-lead { max-width: 30em; margin-top: 16px; font-size: 1.25rem; line-height: 1.65; text-wrap: pretty; }
.case-meta { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.4fr); gap: 24px 32px; margin: 40px 0 0; padding-top: 24px; border-top: 1px solid var(--color-border); }
.case-meta dt { color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-meta dd { margin: 4px 0 0; font-weight: 600; line-height: 1.6; }
/* Marks sit flush left in their 24px box, so a tall mark (Goodwill) lines up with a square one (CMU) and the text column stays put. */
.case-meta-logo { display: inline-block; width: 24px; height: 24px; margin-right: 8px; vertical-align: -6px; object-fit: contain; object-position: left center; }
.case-meta-note { display: block; margin-top: 4px; color: var(--color-muted); font-size: .875rem; font-weight: 400; line-height: 1.5; }
/* Project facts beside a photo (Goodwill team photo, a 640px original kept near native size). */
.case-meta-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 400px); gap: 24px 48px; align-items: start; margin: 40px 0 0; padding-top: 24px; border-top: 1px solid var(--color-border); }
.case-meta-row > .case-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; padding-top: 0; border-top: 0; }
.case-meta-photo { margin: 0; }
@media (max-width: 1023px) {
  .case-meta-row { grid-template-columns: minmax(0, 1fr); }
  .case-meta-photo { max-width: 400px; }
}
@media (max-width: 767px) {
  .case-meta-row { margin-top: 32px; }
  .case-meta-row > .case-meta { grid-template-columns: minmax(0, 1fr); }
}
.case-hero-media { margin-top: 40px; }
.case-video { width: 100%; height: auto; aspect-ratio: 16 / 9; border-radius: var(--radius-lg); background: var(--color-text); }
.case-summary { margin-top: 64px; }

/* A compact persona connects the brief to design decisions. Its portrait is illustrative. */
.case-persona { display: grid; grid-template-columns: 144px minmax(0, 1fr); gap: 12px 24px; align-items: start; margin-top: 48px; padding: 24px; background: var(--color-surface-warm); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); }
.case-persona-portrait { grid-row: 1 / 3; align-self: center; width: 100%; height: auto; }
.case-persona-label { color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-persona-identity h2 { margin-top: 4px; font-family: var(--font-display-zh); font-size: 1.25rem; font-weight: 700; line-height: 1.3; }
.case-persona-needs { grid-column: 2; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; margin: 0; font-size: 1rem; line-height: 1.6; }
.case-persona-needs dt { font-weight: 600; }
.case-persona-needs dd { margin: 4px 0 0; text-wrap: pretty; }

/* Preserve Goodwill's horizontal product design at every viewport width. The hero is the title, one lead
   sentence and this picture with a single caption line (Yusen 2026-11-05: fewer text pieces, so the title leads). */
.case-product-overview { display: grid; gap: 8px; margin-top: 64px; }
/* The POS and the voice strip sit on the page itself, with no white stage around them (Design.md §6, Yusen
   2026-11-04: the stage felt abrupt on the gradient). The strip's bottom edge lines up with the POS's, 2px over,
   so no POS shows under the strip at any width: the padding is the POS's height (its 58% width, at most 568px,
   × 1466/2200) less the strip's (the full width × 334/2136). */
.case-product-overview-visual { position: relative; isolation: isolate; padding-top: calc(min(38.65%, 378.5px) - 15.64% + 2px); }
.case-product-overview-visual img { display: block; width: 100%; height: auto; }
.case-product-context { position: absolute; top: 0; left: 50%; width: min(58%, 568px); transform: translateX(-50%); }
/* Faded by filter rather than opacity (close to the old 30% on white), so the gradient doesn't show through it. */
.case-product-context img { filter: saturate(.25) contrast(.3) brightness(1.75); border-radius: var(--radius-lg); }
.case-product-foreground { position: relative; }
.case-product-expand { display: block; color: var(--color-text); text-decoration: none; cursor: zoom-in; border-radius: var(--radius-md); }
.case-product-expand img { border-radius: clamp(3px, .8vw, 12px); box-shadow: var(--shadow-warm-raised); }
.case-product-expand:focus-visible, .case-product-zoom:focus-visible { outline: 2px solid var(--color-text); outline-offset: 4px; }
/* One caption line: what the picture shows on the left, the two actions together on the right. */
.case-product-overview figcaption { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 24px; }
.case-product-overview .media-caption { margin: 0; }
.case-product-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0 24px; }
.case-product-zoom { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; color: var(--color-text); font-size: .875rem; font-weight: 600; text-underline-offset: 4px; }
.case-product-link { justify-self: start; display: inline-flex; align-items: center; min-height: 44px; font-size: .875rem; font-weight: 600; text-underline-offset: 4px; }

@media (max-width: 959px) {
  /* The POS is 78% wide here, at most 360px. */
  .case-product-overview-visual { padding-top: calc(min(51.98%, 239.9px) - 15.64% + 2px); }
  .case-product-context { width: min(78%, 360px); }
}

/* Optional image inspection preserves the source layout instead of reflowing it. */
html.case-image-viewer-open { overflow: hidden; }
.case-image-viewer { width: min(1200px, calc(100% - 32px)); max-width: none; max-height: calc(100dvh - 32px); margin: auto; padding: 20px; border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-bg); color: var(--color-text); overscroll-behavior: contain; }
.case-image-viewer::backdrop { background: rgb(0 0 0 / .65); }
.case-image-viewer-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.case-image-viewer-head p { font-size: 1rem; font-weight: 600; line-height: 1.5; }
.case-image-viewer-close { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-width: 44px; min-height: 44px; padding: 8px 12px; border: 1px solid var(--color-control-border); border-radius: var(--radius-md); background: var(--color-surface); color: var(--color-text); font: inherit; font-size: .875rem; cursor: pointer; }
.case-image-viewer-close span { font-size: 1.25rem; line-height: 1; }
.case-image-viewer-close:hover { border-color: var(--color-text); }
.case-image-viewer-hint { margin-bottom: 12px; color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-image-viewport { overflow: auto; overscroll-behavior: contain; border-radius: var(--radius-md); background: var(--color-surface); }
.case-image-viewport img { display: block; width: max(100%, 1068px); max-width: none; height: auto; }
.case-image-viewport:focus-visible, .case-image-viewer-close:focus-visible { outline: 2px solid var(--color-text); outline-offset: 3px; }
@media (max-width: 767px) {
  .case-image-viewer { padding: 12px; }
}

/* Interactive prototypes sit at the opening or after the relevant design explanation. */
.case-prototype { margin-top: 32px; }
.case-prototype-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 16px; margin-bottom: 12px; }
/* An h2 in the opening (Flashcard), an h3 inside a chapter (SAV). */
.case-prototype-head :is(h2, h3) { font-family: var(--font-display-zh); font-size: 1rem; font-weight: 700; line-height: 1.5; }
.case-prototype-head p { color: var(--color-muted); font-size: .875rem; line-height: 1.5; text-wrap: pretty; }
.case-prototype relay-prototype { --relay-station-width: 100%; }
/* The Flashcard Dictionary case opens with a simulated iPhone (components/flashcard-prototype.js);
   the phone scales down so its search screen is on the first screen, never below 700px tall
   (about 0.8× — smaller and the app's 17px text stops being comfortable to read). */
.case-prototype flashcard-prototype { --flashcard-screen-height: clamp(700px, calc(100vh - 220px), 868px); }
/* The Hive Five case opens with a simulated iPhone at the design's 402 × 874 frame
   (components/hivefive-prototype.js); it scales the same way as the Flashcard phone. */
.case-prototype hivefive-prototype { --hivefive-screen-height: clamp(700px, calc(100vh - 220px), 898px); }
/* The 拍拍出 case runs a simulated iPhone after the four steps of its 方案 chapter (components/yipai-prototype.js);
   it scales like the Flashcard phone. */
.case-prototype yipai-prototype { --yipai-screen-height: clamp(700px, calc(100vh - 220px), 868px); }
/* The SAV case shows the moped's dashboard and its physical controls at the start of its Digital dashboard
   chapter (components/sav-prototype.js). The screen keeps the design's 1120 × 667 ratio and narrows on shorter
   viewports so the screen, the controls and the next-step row fit one screen once scrolled to. */
.case-prototype sav-prototype { --sav-screen-width: max(560px, calc((100vh - 300px) * 1.679)); }
.case-prototype + .case-section { margin-top: 80px; }
/* A text link after the description (the Figma file) reads as an ink link, not muted copy. */
.case-prototype-head a { color: var(--color-text); font-weight: 600; }

/* Headings, figures and item titles use the display stack. Every Chinese glyph
   they contain must be in the Noto Sans SC subset (see fonts/README.md), or it
   falls back to PingFang in the middle of a heading. */
.case-title, .case-chapter-name, .case-section h3, .case-section h4, .case-stat-value,
.case-questions li, .case-card-title, .case-steps strong, .case-principles strong,
.case-legend strong, .case-layer strong { font-family: var(--font-display-zh); }
/* "Hero Display" is each case page's inline copy of its title glyphs (fonts/build-subset.py),
   so the title paints in its final face instead of swapping from system Hei seconds later. */
.case-title { font-family: "Hero Display", var(--font-display-zh); }
.case-title .latin-display { font-family: "Hero Display", var(--font-display); }

/* Chapters group the narrative; each section is one argument with its evidence. */
.case-chapter { margin-top: 96px; }
/* Chapter titles (Design.md §6「章节标题」, type scale in §4.2): each chapter's <h2>, 32px bold (26px on phones)
   on the chapter's green band (below), above the 24px section <h3>s. Sizes step down by level, about ×1.25: title 40, chapter 32,
   section 24, sub-section 18, body 16 (Yusen picked "Set 3", 2026-11-05). The chapter's "NN" stays in the markup
   but is visually hidden, so the order is still read out; Yusen found visible numbers technical. "Project
   outcomes" and "Next case study" use the same title. */
.case-chapter > .section-heading, .case-summary > .section-heading, .case-next > .section-heading { justify-content: flex-start; gap: 14px; border-top-color: var(--color-text); margin-bottom: 40px; }
.section-heading .case-chapter-name, .case-summary > .section-heading h2 { font-size: 2rem; font-weight: 700; line-height: 1.25; text-wrap: balance; }
/* Each chapter opens on a band in place of the ink rule (Yusen, 2026-11-05: the title needed more weight). The same
   day the sand band proved hard to tell from the page, so it took the header Contact button's green (--color-accent)
   with the title in cream (--color-surface-warm, 9.3:1), not a new shade. Content width, the warm panels' 8px corners.
   It is padded as a header bar rather than a slab: 24px above and below, the title still 32px in from the edge (16px
   and 20px on phones). The band carries the break, so chapters sit 96px apart instead of 128. "Project outcomes" and
   "Next case study" keep the rule, so the band only ever means a chapter. A jump lands the band's top edge where the
   rule used to land. It prints as shown: a PDF saved without background graphics would leave cream text on white.
   The flat green looked like a template (Yusen, 2026-11-05), so the band carries a still of the homepage's flow
   field in deep greens (Images/case/chapter-band.webp, baked by Portfolio/chapter-band-texture.html; 600 × 150
   lossless, drawn at 1200 × 300, one texel per two CSS pixels like the homepage canvas). The cream title measures
   8.36:1 or more over it (12 pages, 320–1920px). On top sits a light touch of glass: a faint light-to-deep wash
   whose light part fades out within the top 20px, above the title's glyphs, and a 1px highlight along the top edge.
   No hover, shadow or lift, so it still reads as a heading, not a button. The texture keeps one size at every width
   (wider than any band; it only grows for a band wider than 1200px), and each chapter shows a different part of it,
   so a page's bands don't repeat. The solid green stays underneath as the fallback, and is all that shows with
   forced colours, more contrast or reduced transparency. */
.case-chapter > .section-heading { position: relative; margin-bottom: 48px; padding: 24px 32px; border-top: 0; border-radius: var(--radius-lg); color: var(--color-surface-warm); -webkit-print-color-adjust: exact; print-color-adjust: exact;
  background-color: var(--color-accent);
  background-image: linear-gradient(180deg, rgb(255 255 255 / .07), rgb(255 255 255 / 0) 20px, rgb(0 0 0 / 0) 60%, rgb(0 0 0 / .1)), url("../Images/case/chapter-band.webp");
  background-size: auto, max(1200px, 100%) auto;
  background-position: 0 0, var(--band-x, 0%) var(--band-y, 30%);
  background-repeat: no-repeat;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .14); }
.case-chapter:nth-child(5n + 2 of .case-chapter) > .section-heading { --band-x: 70%; --band-y: 85%; }
.case-chapter:nth-child(5n + 3 of .case-chapter) > .section-heading { --band-x: 30%; --band-y: 0%; }
.case-chapter:nth-child(5n + 4 of .case-chapter) > .section-heading { --band-x: 100%; --band-y: 60%; }
.case-chapter:nth-child(5n of .case-chapter) > .section-heading { --band-x: 50%; --band-y: 100%; }
@media (forced-colors: active), (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .case-chapter > .section-heading { background-image: none; box-shadow: none; }
}
.case-chapter > .section-heading .mono { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Chapter index (scripts/chapter-index.js): the homepage's sticky project index (.section-heading--index,
   styles/portfolio-studio.css) listing this page's chapters, placed after the project facts. It has no
   heading of its own, so the chapters start at the bar's text inset, centred on a card kept as tall as the
   homepage's (--bar-height), and the next block keeps its own top margin below it. Once the last chapter
   has scrolled past it lifts away (is-past), unless focus is inside it. */
.case-chapter-index { min-height: var(--bar-height); align-items: center; margin: 48px 0 0; }
/* The first chapter's text starts at the inset too: pull the row back by the list's 8px and the link's 10px. */
.case-chapter-index .work-index:not(.is-compact) { margin-inline-start: -18px; }
/* With no heading beside it, the collapsed button centres its text in its 44px target, and so on the card. */
.case-chapter-index .work-index.is-compact .work-index-toggle { align-items: center; }
.case-chapter-index.is-past:not(:focus-within) { opacity: 0; visibility: hidden; transform: translateY(-12px); }
/* Its card and open list take the warm surface, like the data cards (the homepage's index stays white). */
.case-chapter-index::before, .case-chapter-index .work-index.is-compact.is-open ol { background: var(--color-surface-warm); border-color: var(--color-border-warm); }
/* Its entries echo the chapter titles: names semibold, numbers in the accent green (white on the current
   chapter's block). Every entry keeps the same weight, so the row doesn't shift as the marker moves. */
.case-chapter-index .work-index-label, .case-chapter-index .work-index .mono { font-weight: 600; }
.case-chapter-index .work-index a:not([aria-current]) .mono, .case-chapter-index .work-index-toggle .mono { color: var(--color-accent); }
@media (max-width: 767px) {
  .case-chapter-index { margin-top: 32px; }
  /* The button sits at the start of the bar, so the open list keeps its labels at the start too. */
  .case-chapter-index .work-index.is-compact.is-open ol a { justify-content: flex-start; padding-inline: calc(var(--bar-inset) - 7px); text-align: left; }
}
@media (prefers-reduced-motion: no-preference) {
  .case-chapter-index { transition: transform var(--index-morph), opacity var(--index-morph), visibility 0s; }
  .case-chapter-index.is-past:not(:focus-within) { transition: transform var(--index-morph), opacity var(--index-morph), visibility 0s var(--index-morph); }
}
@media print { .case-chapter-index { display: none; } }
/* Chapter rail (Design.md §6「章节导轨」): from 1280px the chapter index is a quiet column in the left margin, sticky
   beside the page, under a link back to the home page's projects: "Project overview", then the chapter names, at
   16px with no numbers, the current one accent green and semibold, the rest muted. A name that wraps in 200px wraps
   the same in both weights, so no row changes height as the current part moves. The content keeps its right
   edge (in line with the header) and gives up on the left only the width the margin lacks. */
.case-chapter-rail { display: none; }
@media (min-width: 1280px) {
  :root { --rail-width: 200px; --rail-gap: 32px; --rail-edge: 32px;
    --rail-reserve: max(0px, calc(var(--rail-edge) + var(--rail-width) + var(--rail-gap) - (100vw - var(--content-wide)) / 2)); }
  main:has(> .case-chapter-rail) { position: relative; padding-left: var(--rail-reserve); }
  .case-chapter-rail { display: block; position: absolute; top: 0; bottom: 0; left: calc(var(--rail-reserve) - var(--rail-gap) - var(--rail-width)); width: var(--rail-width); padding-top: 40px; }
  /* Sticky inside a column as tall as the page's main, so near the end it scrolls away with the last section and
     never reaches the footer. 96px from the top when stuck, near eye level: it must stay above the rail's
     first-screen place (113px, the 73px header plus the 40px padding), or sticky would push the rail down on load.
     So the rail moves only 17px before it sticks. */
  .case-chapter-rail-inner { position: sticky; top: 96px; }
  .case-chapter-index { display: none; }
}
/* The current entry floats as a chip (Yusen, 2026-11-05: the current name looked almost like the rest): a small warm
   card, cream on the warm hairline with a soft warm shadow and 8px corners, lifted 1.5px, its name 1.125× (16 → 18px)
   in accent green, semibold; the other entries stay flat. The name grows by transform from its first letter, so no
   entry reflows and every name keeps its left edge. Names wrap at 200px ÷ 1.125 (wider ones go to two lines), so the
   enlarged name still fits the column; the chip's 12px padding hangs outside the text on both sides. */
.case-chapter-rail, .case-chapter-index { --chip-scale: 1.125; --chip-lift: -1.5px; --chip-pad-x: 12px; --chip-pad-y: 6px; --chip-shadow: var(--shadow-warm-float); --chip-ease: 220ms ease-out; }
.case-chapter-rail-back { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin-bottom: 20px; color: var(--color-text); font-size: 1rem; font-weight: 600; line-height: 1.45; text-decoration: none; }
.case-chapter-rail ol { position: relative; isolation: isolate; margin: 0; padding: 0; list-style: none; }
.case-chapter-rail ol a { display: block; min-height: 44px; padding: 10px 0; color: var(--color-muted); font-size: 1rem; line-height: 1.45; text-decoration: none; }
/* Each label is its entry's chip box: the padding hangs outside the text, so the text keeps its place.
   scripts/chapter-index.js sizes each one to its name in the semibold weight (a wrapped name to its longest line),
   so the weight can change gradually without moving the chip. */
.case-chapter-rail-label { display: inline-block; max-width: calc(var(--rail-width) / var(--chip-scale) + 2 * var(--chip-pad-x)); margin: calc(-1 * var(--chip-pad-y)) calc(-1 * var(--chip-pad-x)); padding: var(--chip-pad-y) var(--chip-pad-x); border-radius: var(--radius-lg); text-wrap: balance; transform-origin: var(--chip-pad-x) 50%; }
.case-chapter-rail ol a[aria-current], .case-chapter-rail.is-measuring .case-chapter-rail-label { font-weight: 600; }
.case-chapter-rail ol a[aria-current] { color: var(--color-accent); }
.case-chapter-rail ol a[aria-current] .case-chapter-rail-label { transform: translateY(var(--chip-lift)) scale(var(--chip-scale)); }
/* One chip for the whole list, placed under the current name (--chip-x/y/w/h, the name's box before scaling) and
   scaled and lifted the same way, so it slides from entry to entry. */
.case-chapter-rail ol::before { content: ""; position: absolute; top: 0; left: 0; z-index: -1; box-sizing: border-box; width: var(--chip-w, 0px); height: var(--chip-h, 0px); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); background: var(--color-surface-warm); box-shadow: var(--chip-shadow); opacity: 0; pointer-events: none; transform: translate(var(--chip-x, 0px), var(--chip-y, 0px)) translateY(var(--chip-lift)) scale(var(--chip-scale)); transform-origin: var(--chip-pad-x) 50%; }
.case-chapter-rail ol.has-chip::before { opacity: 1; }
.case-chapter-rail a:hover { color: var(--color-text); }
.case-chapter-rail a[aria-current]:hover { color: var(--color-accent); }
.case-chapter-rail a:hover .case-chapter-rail-label, .case-chapter-rail-back:hover span:last-child { text-decoration: underline; text-underline-offset: 4px; }
/* Focus rings go round the chip box (2px ink, 3px clear of it), so on the current entry the ring sits outside the chip. */
.case-chapter-rail-back:focus-visible { outline: 2px solid var(--color-text); outline-offset: 2px; border-radius: var(--radius-md); }
.case-chapter-rail ol a:focus-visible { outline: none; }
.case-chapter-rail ol a:focus-visible .case-chapter-rail-label { outline: 2px solid var(--color-text); outline-offset: 3px; }
/* The open chapter list on phones and tablets marks the current part the same way, in place of the green block, but
   without sliding: the name lifts as a chip, 1.125×, accent green on cream. The list is cream too, so the chip's
   hairline and shadow carry its edge. Every name keeps the chip's padding box, so rows keep their height. */
.case-chapter-index .work-index.is-compact.is-open ol .work-index-label { max-width: calc(100% / var(--chip-scale)); margin: calc(-1 * var(--chip-pad-y)) calc(-1 * var(--chip-pad-x)); padding: calc(var(--chip-pad-y) - 1px) calc(var(--chip-pad-x) - 1px); border: 1px solid transparent; border-radius: var(--radius-lg); transform-origin: var(--chip-pad-x) 50%; }
.case-chapter-index .work-index.is-compact.is-open ol a[aria-current] { color: var(--color-accent); }
.case-chapter-index .work-index.is-compact.is-open ol a[aria-current]::before { opacity: 0; }
.case-chapter-index .work-index.is-compact.is-open ol a[aria-current] .work-index-label { border-color: var(--color-border-warm); background: var(--color-surface-warm); box-shadow: var(--chip-shadow); transform: translateY(var(--chip-lift)) scale(var(--chip-scale)); }
/* 220ms ease-out whenever the current part changes, by scrolling or by a click. The rail waits until the page has
   loaded (is-ready, set by the script), and placing the chip after a resize or a font swap is instant (is-placing).
   The open list has nothing to wait for: it was hidden while the page loaded. Reduced motion: no transitions. */
@media (prefers-reduced-motion: no-preference) {
  .case-chapter-rail.is-ready ol a { transition: color var(--chip-ease), font-weight var(--chip-ease); }
  .case-chapter-index .work-index.is-compact.is-open ol a { transition: color var(--chip-ease); }
  .case-chapter-rail.is-ready .case-chapter-rail-label { transition: transform var(--chip-ease); }
  .case-chapter-rail.is-ready ol::before { transition: transform var(--chip-ease), width var(--chip-ease), height var(--chip-ease); }
  .case-chapter-rail ol.is-placing::before { transition: none; }
  .case-chapter-index .work-index.is-compact.is-open ol .work-index-label { transition: transform var(--chip-ease), background-color var(--chip-ease), border-color var(--chip-ease), box-shadow var(--chip-ease); }
}
@media print { .case-chapter-rail { display: none; } }
.case-section + .case-section { margin-top: 80px; }
.case-section:not(.case-split) > * + * { margin-top: 40px; }
.case-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 48px; align-items: start; }
.case-section h3 { font-size: clamp(1.3125rem, calc(1rem + .6vw), 1.5rem); font-weight: 700; line-height: 1.3; text-wrap: balance; }
.case-section h4 { margin: 0; font-size: 1.125rem; font-weight: 700; line-height: 1.4; }
.case-section .case-prototype-head h4 { font-size: 1rem; line-height: 1.5; }
.case-prose { max-width: 36em; }
.case-prose > * + * { margin-top: 16px; }
.case-prose ol { padding-left: 1.5em; }
.case-prose li + li { margin-top: 8px; }
.case-prose p, .case-principles p, .case-legend p, .case-card p { text-wrap: pretty; }
.case-prose > .case-button { margin-top: 24px; }
.case-buttons { display: flex; flex-wrap: wrap; gap: 12px; }
.case-prose b { font-weight: 600; }

/* Optional evidence stays next to the decision it supports, without lengthening the main read. */
.case-details { border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); }
.case-details > summary { min-height: 56px; padding: 16px 0; color: var(--color-text); font-weight: 600; line-height: 1.5; cursor: pointer; }
.case-details > summary::marker { color: var(--color-muted); }
.case-details > summary:hover { text-decoration: underline; text-underline-offset: 4px; }
.case-details-content { padding: 8px 0 24px; }
.case-details-content > * + * { margin-top: 24px; }

/* Data cards: value plus its meaning, on the case pages' warm surface (Design.md §6). */
.case-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.case-split .case-stats, .case-stats--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* An outcomes group can lead with its headline result (Design.md §6): Goodwill's five cards (.case-stats--five)
   always do, and any other group opts in with .case-stats--lead (Clickable Category). The first card takes a
   row of its own, its number green at twice the size and its meaning beside it; the others share the rows
   below (Goodwill's four in one row, two by two from 1023px). */
.case-stats--five { grid-template-columns: repeat(4, minmax(0, 1fr)); }
:is(.case-stats--five, .case-stats--lead) > .case-stat:first-child { grid-column: 1 / -1; display: grid; grid-template-columns: auto auto minmax(0, 1fr); align-items: center; column-gap: 20px; padding: 28px 32px; background: linear-gradient(160deg, var(--color-accent-wash), transparent 60%), var(--color-surface-warm); }
:is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-icon { width: 56px; height: 56px; margin: 0; padding: 14px; border-radius: 14px; }
:is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-value { color: var(--color-accent); font-size: 2rem; line-height: 1.05; letter-spacing: -.02em; }
:is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-label { max-width: 28em; margin: 0 0 0 12px; padding-left: 32px; border-left: 1px solid var(--color-border-warm); color: var(--color-text); font-size: 1.125rem; }
/* Beside text, in half a split, the lead stacks (its meaning under the number, which would otherwise get only a
   sliver of the half), and a card left alone in the last row takes the row whole. */
.case-split .case-stats--lead > .case-stat:first-child { grid-template-columns: auto minmax(0, 1fr); row-gap: 12px; column-gap: 16px; }
.case-split .case-stats--lead > .case-stat:first-child .case-stat-label { grid-column: 1 / -1; margin: 0; padding: 0; border: 0; }
.case-split .case-stats--lead > .case-stat:last-child:nth-child(even) { grid-column: 1 / -1; }
@media (max-width: 1023px) {
  .case-stats--five { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.case-stat { padding: 24px; background: var(--color-surface-warm); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); box-shadow: var(--shadow-warm); }
/* Optional line icon left of a stat value (Lucide-style strokes, decorative); it uses the card's width, not its height. */
.case-stat:has(.case-stat-icon) { display: flex; flex-wrap: wrap; align-items: center; align-content: flex-start; gap: 4px 10px; }
/* The value keeps its natural width and never breaks mid-value. scripts/stat-fit.js sizes each group so every value
   fits beside its icon (Design.md §6); without the script a value too wide for the row drops below the icon. */
.case-stat:has(.case-stat-icon) .case-stat-value { flex: 0 0 auto; max-width: 100%; }
/* While stat-fit.js measures, each value shows at its natural width on one line. */
.is-fitting-stats .case-stat:has(.case-stat-icon) .case-stat-value { max-width: none; white-space: nowrap; }
.case-stat:has(.case-stat-icon) .case-stat-label { flex: 0 0 100%; }
/* The icon sits in a pale green well, which echoes the green chapter numbers. The well hangs into the card's
   padding, so the icon lines up with the text below it and the value starts where it did before the wells: no
   value drops below its icon because of them, and no card grows taller. */
.case-stat-icon { box-sizing: border-box; flex: none; width: 36px; height: 36px; margin-inline-start: -6px; padding: 6px; border-radius: 10px; background: var(--color-accent-tint); fill: none; stroke: var(--color-accent); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
/* Values are data, not headings: above the section heading, never above the chapter title (§4.2). */
.case-stat-value { display: block; font-size: 1.75rem; font-weight: 700; line-height: 1.2; }
/* A value never needs more room than its card has. Each card is a size container, and a value is at most 20.5% of
   the card's width per pixel of type, which is what the longest one ("÷ 28 days") needs. In a narrow card every
   value steps down just that far, and the cards of a group, all the same width, stay the same size. */
.case-stat { container-type: inline-size; }
.case-stat .case-stat-value { font-size: min(1.75rem, 20.5cqi); }
.case-stats--large .case-stat .case-stat-value { font-size: min(2rem, 24cqi); }
/* A long unit after the number (万美元, 万+, 万 BVI) is set small, so the number carries the value. Short units
   (天, 小时, 家, days) stay full size. The space before it is the number's size, too wide for a small unit, so the
   unit moves in by .15em. */
.case-stat-unit { margin-inline-start: -.15em; font-size: .55em; font-weight: 600; white-space: nowrap; }
/* pretty keeps a label from ending on one word or one character; it moves words between the last lines only, so no
   card changes height (checked on every page at 1440/1024/390/360). */
.case-stat-label { display: block; margin-top: 8px; color: var(--color-muted); font-size: .875rem; line-height: 1.5; text-wrap: pretty; }
.case-stats--large .case-stat-value { font-size: 2rem; line-height: 1.1; }
.case-stats--large .case-stat-icon { width: 44px; height: 44px; margin-inline-start: -6px; padding: 8px; }
/* Design choices (Design.md §6): standard stat cards in an <ol class="case-choices">, the question as the title and the
   chosen option in <strong>. Not a .case-stats group, so stat-fit.js and the two-column split rule leave them alone;
   in a .case-split prose column they stack beside the figure (Goodwill "How we got there"). */
.case-choices { display: grid; gap: 10px; margin: 20px 0 0; padding: 0; list-style: none; }
.case-prose .case-choices { padding-left: 0; }
.case-prose .case-choices > li + li { margin-top: 0; }
.case-choices > .case-stat { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; column-gap: 14px; padding: 14px 18px; }
.case-choices .case-stat-icon { grid-row: 1 / span 2; margin-inline-start: 0; }
.case-choices .case-stat .case-stat-value { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
.case-choices .case-stat-label { grid-column: 2; margin-top: 2px; }
.case-choices .case-stat-label strong { color: var(--color-accent); font-weight: 700; }
/* Choice cards can also fill the column as a grid (Flashcard's four findings and three principles, 2026-11-05):
   .case-choices--two puts two cards in a row and .case-choices--three three; cards in a row share its height.
   Three stack below 1024px (like .case-cards--three), two below 768px. Titles balance their lines, so none ends
   on one word; descriptions keep .case-stat-label's pretty wrapping (balance splits Chinese words). */
.case-choices--two, .case-choices--three { gap: 16px; }
.case-choices--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.case-choices--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
:is(.case-choices--two, .case-choices--three) .case-stat-value { text-wrap: balance; }
@media (max-width: 1023px) { .case-choices--three { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 767px) { .case-choices--two { grid-template-columns: minmax(0, 1fr); } }

/* Media panels, like every card on the case pages, use the warm surface (Design.md §6). An image with a white
   ground opts in to .case-image-blend, which multiplies it onto the panel so the white takes the panel's colour
   instead of showing as a box; a 2% lift first turns a near-white ground (watch.jpg's #fbfcfa) into white, so it
   doesn't come out a shade darker than the panel. Never apply it to screens inside a dark device frame: multiply
   would darken them. */
.case-media { padding: 24px; background: var(--color-surface-warm); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); }
.case-media:has(.case-image-blend) { isolation: isolate; }
.case-image-blend { filter: brightness(1.02); mix-blend-mode: multiply; }
.case-media img, .case-media video { width: 100%; height: auto; }
/* Supporting photos use a lighter frame while keeping their natural proportions. */
.case-media.case-media--compact { padding: 12px; }
/* Device screenshots sit straight on the paper with hero A's warm shadow and no panel (Yusen 2026-11-05: the panel
   looked out of place behind a screen); photos and diagrams keep the warm panel. A bare screen
   (.case-annotated--screen) is drawn at 899/987 of the width, the size of the screen inside Relay.png's tablet,
   so a before/after pair shows the same UI at the same scale. A framed PNG with transparent margins
   (.case-annotated--tablet, Relay.png) takes the shadow on its tablet body (x 27-965, y 27-705 of 987x731, 32px
   corners), not on its image box, and its caption drops the 2.6% transparent margin under the tablet. */
.case-media.case-media--device { padding: 0; background: none; border: 0; border-radius: 0; }
.case-media--device + .media-caption { margin-top: 16px; }
.case-media--device:has(.case-annotated--tablet) + .media-caption { margin-top: calc(16px - 2.6%); }
.case-annotated--screen { width: min(91.1%, 899px); }
.case-annotated--screen img { border-radius: var(--radius-lg); box-shadow: var(--shadow-warm-raised); }
.case-annotated--tablet::before { content: ""; position: absolute; inset: 3.69% 2.23% 3.56% 2.74%; border-radius: 3.4% / 4.7%; box-shadow: var(--shadow-warm-raised); pointer-events: none; }
/* Screens narrower than the column stay at their own size instead of upscaling. */
.case-media--natural img { width: auto; max-width: 100%; margin-inline: auto; }
.case-stack { display: grid; gap: 24px; }

.case-button { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 10px 20px; border: 1px solid var(--color-control-border); border-radius: var(--radius-md); font-size: .875rem; font-weight: 600; line-height: 1.5; text-decoration: none; }
.case-button:hover { border-color: var(--color-text); text-decoration: underline; text-decoration-thickness: 1px; }

.case-questions, .case-cards, .case-steps, .case-legend, .case-principles { display: grid; margin: 0; padding: 0; list-style: none; }
.case-questions .mono, .case-cards .mono, .case-steps .mono, .case-principles .mono { display: block; color: var(--color-muted); font-weight: 400; }

/* Key statements (questions, principles) sit under an ink rule. */
.case-questions { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }
.case-questions li { padding-top: 16px; border-top: 1px solid var(--color-text); font-size: 1.125rem; font-weight: 600; line-height: 1.6; }
.case-questions .mono { margin-bottom: 12px; }
/* Two statements side by side, e.g. a problem statement and the direction it set.
   Their labels are words, so Chinese pages keep them in body Hei. */
.case-questions--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.case-questions-label { display: block; margin-bottom: 12px; color: var(--color-muted); font-family: var(--font-body); font-size: .875rem; font-weight: 400; line-height: 1.5; }
.case-questions-label:lang(en) { font-family: var(--font-label); letter-spacing: .06em; }
.case-principles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 48px; }
.case-principles li { padding-top: 16px; border-top: 1px solid var(--color-text); }
.case-principles .mono { margin-bottom: 8px; }
.case-principles strong { display: block; font-size: 1.125rem; font-weight: 700; line-height: 1.5; }
.case-principles p { margin-top: 8px; }
.case-principles--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Decision cards: an assumption and what the research showed. */
.case-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.case-cards--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.case-card { padding: 24px; background: var(--color-surface-warm); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); }
.case-card .mono { margin-bottom: 12px; }
.case-card-title { font-size: 1.125rem; font-weight: 700; line-height: 1.5; }
.case-card-assume { margin-top: 12px; color: var(--color-muted); font-size: .875rem; line-height: 1.6; }
.case-card-learn { margin-top: 8px; line-height: 1.6; }
.case-card-learn b { font-weight: 600; }
/* Profile cards (personas): a labelled fact per paragraph. */
.case-card-fact { margin-top: 12px; line-height: 1.6; }
.case-card-fact b { display: block; margin-bottom: 2px; color: var(--color-muted); font-size: .875rem; font-weight: 400; }

.case-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
.case-steps--five { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.case-steps li { padding-top: 16px; border-top: 1px solid var(--color-border); }
.case-steps .mono { margin-bottom: 8px; }
.case-steps strong { display: block; font-size: 1.125rem; font-weight: 700; line-height: 1.5; }
.case-steps p { margin-top: 4px; color: var(--color-muted); font-size: .875rem; line-height: 1.6; }

/* Annotated screen: numbered markers on the image match the legend. */
.case-annotated { position: relative; max-width: 987px; margin-inline: auto; }
.case-annotated img { width: 100%; height: auto; }
.case-marker { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; background: var(--color-text); color: var(--color-surface); font-family: var(--font-label); font-size: .8125rem; line-height: 1; }
.case-pin { position: absolute; left: var(--x); top: var(--y); width: 28px; height: 28px; transform: translate(-50%, -50%); box-shadow: 0 0 0 2px var(--color-surface); pointer-events: none; }
.case-legend { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px 32px; }
.case-legend li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 4px 12px; align-content: start; padding-top: 16px; border-top: 1px solid var(--color-border); }
.case-legend strong { font-weight: 700; line-height: 1.5; }
.case-legend-icon { display: inline-block; width: 20px; height: 20px; margin-right: 8px; vertical-align: -4px; fill: none; stroke: var(--color-accent); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.case-legend p { grid-column: 2; color: var(--color-muted); font-size: .875rem; line-height: 1.6; }
/* A legend in the column beside its figure: one item per row. */
.case-legend--stack { grid-template-columns: minmax(0, 1fr); gap: 16px; }
/* A stacked legend beside a figure spans the figure's image box (not its caption) on desktop, items spread evenly. */
@media (min-width: 1024px) {
  .case-split:has(> figure + .case-legend--stack) { grid-template-rows: auto auto; row-gap: 0; }
  .case-split:has(> figure + .case-legend--stack) > figure { display: grid; grid-row: 1 / span 2; grid-template-rows: subgrid; }
  .case-split:has(> figure + .case-legend--stack) > .case-legend--stack { grid-row: 1; align-self: stretch; grid-auto-rows: 1fr; }
}

/* Floor map (Goodwill): a schematic of the back room drawn as inline SVG in the page's
   language, so its labels stay real text. Numbered pins match the legend beside it;
   the current and the new workflow share one floor plan. */
.case-map { display: block; width: 100%; max-width: 440px; height: auto; margin-inline: auto; font-family: var(--font-body); }
.case-map-floor { fill: var(--color-bg); }
.case-map-wall { fill: none; stroke: var(--color-text); stroke-width: 2.5; }
.case-map-zone { fill: var(--color-surface); stroke: var(--color-control-border); }
.case-map-idle { opacity: .45; }
.case-map-idle .case-map-zone { stroke-dasharray: 4 4; }
.case-map-device { fill: var(--color-surface); stroke: var(--color-text); stroke-width: 1.5; }
.case-map-rack { stroke: var(--color-text); stroke-width: 2; stroke-linecap: round; }
.case-map-hanger, .case-map-bin { fill: none; stroke: var(--color-muted); stroke-width: 1.5; }
.case-map-person { fill: var(--color-muted); }
.case-map-person--focus { fill: var(--color-text); }
.case-map-headset { fill: none; stroke: var(--color-text); stroke-width: 1.5; }
.case-map-route { fill: none; stroke: var(--color-text); stroke-width: 2; stroke-linejoin: round; }
.case-map-route--dashed { stroke-dasharray: 6 5; }
.case-map-arrow { fill: var(--color-text); }
.case-map-label { fill: var(--color-text); font-size: 15px; font-weight: 600; }
.case-map-note { fill: var(--color-muted); font-size: 13px; }
.case-map-pin circle { fill: var(--color-text); stroke: var(--color-surface); stroke-width: 2; }
.case-map-pin text { fill: var(--color-surface); font-family: var(--font-label); font-size: 12px; }

/* A participant's words, attributed by role only. */
.case-quote { margin: 0; padding-left: 20px; border-left: 2px solid var(--color-text); }
.case-prose > .case-quote, .case-prose > .case-quote + * { margin-top: 24px; }
.case-quote p { font-size: 1.25rem; font-weight: 600; line-height: 1.5; text-wrap: pretty; }
.case-quote footer { margin-top: 8px; color: var(--color-muted); font-size: .875rem; line-height: 1.5; }

/* Architecture: the agent drives the existing tagging software. */
.case-layers { display: grid; gap: 8px; }
.case-layer { padding: 20px 24px; background: var(--color-surface-warm); border: 1px solid var(--color-border-warm); border-radius: var(--radius-lg); text-align: center; }
.case-layer strong { display: block; font-weight: 700; }
.case-layer span { display: block; margin-top: 4px; color: var(--color-muted); font-size: .875rem; line-height: 1.6; }
.case-layer--agent { background: var(--color-text); border-color: var(--color-text); color: var(--color-bg); }
.case-layer--agent span { color: var(--color-border); }
.case-layer--base { background: transparent; border-color: var(--color-control-border); }
.case-layer-arrow { color: var(--color-muted); font-size: .875rem; line-height: 1.5; text-align: center; }

/* Before / after: same structure and scale for both states, Before first. */
.case-compare { display: grid; gap: 48px; }
.case-compare-item { display: grid; gap: 16px; padding-top: 16px; border-top: 1px solid var(--color-text); }
.case-compare-label { color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-compare-detail { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px 32px; align-items: center; }
.case-compare-photo { width: auto; max-width: 100%; height: auto; max-height: 240px; border-radius: var(--radius-md); }
.case-compare-detail p { text-wrap: pretty; }

/* Image sets (iterations, steps): equal frames, images contained, never cropped. */
.case-gallery { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.case-gallery figure { display: grid; gap: 8px; align-content: start; min-width: 0; }
.case-gallery .case-media { display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3; padding: 16px; }
.case-gallery .case-media img { width: 100%; height: 100%; object-fit: contain; }
.case-gallery .media-caption { margin-top: 0; }
.case-gallery--options .media-caption strong { display: block; margin-bottom: 4px; color: var(--color-text); font-weight: 600; }
/* Source design exports can be opened at full size, including on small screens. */
.case-image-link { display: block; cursor: zoom-in; }
.case-gallery .case-image-link { width: 100%; height: 100%; }
.case-image-link:focus-visible { outline: 2px solid var(--color-text); outline-offset: 4px; }
/* A note about the whole set (e.g. "all are real screenshots") spans every column. */
.case-gallery > .media-caption { grid-column: 1 / -1; }
/* Three phone screens side by side: tall frames, the phone fills each. */
.case-gallery--phones { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.case-gallery--phones .case-media { aspect-ratio: 3 / 5; padding: 12px; }
/* Phone screenshots sit in a simulated iPhone: the frame of the Flashcard prototype
   (a 12px bezel, 58px outer and 46px screen radius and a Dynamic Island at 414px wide),
   drawn in container units so the hero's three small phones and a full-column gallery
   phone keep the same proportions. Screens are 402×874 exports at 2x; the grey corner
   fill baked into the exports sits inside the screen radius and never shows. */
.case-phone { --case-phone-screen: 402 / 874; --case-phone-outer: 1 / 2.106; container-type: inline-size; flex: none; width: 100%; margin-inline: auto; }
/* The Android export is 412×874 and draws its own camera cutout, so no island. */
.case-phone--android { --case-phone-screen: 412 / 874; --case-phone-outer: 1 / 2.056; }
.case-phone-screen { position: relative; height: 100%; padding: 3%; border-radius: 24px; background: #1c1c1e; }
.case-media .case-phone img { display: block; width: 100%; height: 100%; aspect-ratio: var(--case-phone-screen); object-fit: cover; object-position: top; border-radius: 18px; }
@supports (width: 1cqw) {
  .case-phone-screen { padding: 2.9cqw; border-radius: 14cqw; box-shadow: inset 0 0 0 .25cqw #48484a, inset 0 0 0 .75cqw #0a0a0a; }
  .case-media .case-phone img { border-radius: 11.1cqw; }
  .case-phone-screen::after { content: ""; position: absolute; top: 5.6cqw; left: 50%; width: 29.5cqw; height: 8.7cqw; transform: translateX(-50%); border-radius: 4.4cqw; background: #000; }
  .case-phone--android .case-phone-screen::after { content: none; }
}
/* In the tall gallery frames the phone fills the height; on its own it keeps the export's size. */
.case-gallery--phones .case-phone { width: auto; height: 100%; aspect-ratio: var(--case-phone-outer); }
.case-media--natural .case-phone { max-width: 440px; }
/* A source draft has no device status bar: preserve its complete export and
   annotations inside the existing bezel, without adding a camera over the UI. */
.case-phone--draft { --case-phone-screen: auto; }
.case-phone--draft .case-phone-screen::after { content: none; }
/* Paired phone comparisons keep the same screen width and each source's ratio. */
.case-split.case-compare--phones { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; max-width: 720px; margin-inline: auto; }
.case-compare--phones .case-stack { gap: 12px; }
.case-compare--phones .case-phone { max-width: 280px; }
.case-compare--phones .media-caption { margin-top: 0; }
/* Three phones as the opening image, on the same 16:10 stage as the homepage cover. */
.case-media--phones { display: flex; align-items: center; justify-content: center; gap: 5%; aspect-ratio: 16 / 10; }
.case-media--phones .case-phone { width: auto; height: 90%; aspect-ratio: var(--case-phone-outer); }
/* Two photos per row (e.g. inside a split column); frames stay 4:3. */
.case-gallery--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Three steps of an iteration in order (e.g. Goodwill's proof of concept → separate app → widget). */
.case-gallery--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Dashboard screens exported from the same 420×250 artboard: equal frames in one
   panel, so a sequence or a before/after pair lines up without cropping. */
.case-screens { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.case-screens--three { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.case-screens img { display: block; width: 100%; height: auto; }

/* Task flow: the rider acts on white, the vehicle on ink; the legend names both
   and each step also names its actor for screen readers. */
.case-flow { display: grid; gap: 8px; max-width: 480px; margin-inline: auto; }
.case-flow-legend { display: flex; justify-content: center; gap: 24px; margin: 0 0 8px; padding: 0; list-style: none; color: var(--color-muted); font-size: .875rem; line-height: 1.5; }
.case-flow-legend li { display: flex; align-items: center; gap: 8px; }
.case-flow-legend li::before { content: ""; width: 16px; height: 16px; border: 1px solid var(--color-control-border); border-radius: var(--radius-sm); background: var(--color-surface); }
.case-flow-legend .case-flow-key--system::before { border-color: var(--color-text); background: var(--color-text); }
.case-flow-node { padding: 10px 16px; border: 1px solid var(--color-control-border); border-radius: var(--radius-md); background: var(--color-surface); font-size: .875rem; font-weight: 600; line-height: 1.5; text-align: center; text-wrap: balance; }
/* Chinese steps wrap at punctuation and spaces, so balancing never splits a word
   such as 附近; overflow-wrap still breaks a run too long for a narrow branch. */
.case-flow-node:lang(zh) { word-break: keep-all; overflow-wrap: anywhere; }
.case-flow-node--system { border-color: var(--color-text); background: var(--color-text); color: var(--color-bg); }
.case-flow-node--decision { border: 1px dashed var(--color-text); background: transparent; color: var(--color-text); }
.case-flow-arrow { color: var(--color-muted); font-size: .875rem; line-height: 1.5; text-align: center; }
.case-flow-branches { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.case-flow-branch { display: grid; gap: 8px; align-content: start; }
/* A break note hangs from the step above it (no gap, inset, open top) and marks
   where a concept failed; error red always comes with its text label. */
.case-flow-break { margin: -8px 16px 0; padding: 8px 16px 10px; border: 1px dashed var(--color-error); border-top: 0; border-radius: 0 0 var(--radius-md) var(--radius-md); font-size: .875rem; line-height: 1.5; text-wrap: pretty; }
.case-flow-break strong { display: block; color: var(--color-error); font-weight: 600; }
.case-flow .media-caption { justify-content: center; margin-top: 8px; text-align: center; }

@media (max-width: 1023px) {
  .case-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .case-split { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .case-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .case-steps, .case-steps--five, .case-legend, .case-gallery, .case-principles--three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .case-cards--three { grid-template-columns: minmax(0, 1fr); }
  .case-gallery--phones { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
  .case-gallery--three { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
}
/* Below 360px (an iPhone SE, or Display Zoom on a small iPhone) half-width cards leave under 100px for a value:
   every group stacks, so values keep their phone size. This comes after the phone rules above, which set
   two columns. */
@media (max-width: 359px) {
  .case-stats, .case-split .case-stats, .case-stats--pair, .case-stats--five { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 767px) {
  .case-hero { padding-top: 32px; }
  .case-lead { font-size: 1.125rem; }
  .case-meta { grid-template-columns: minmax(0, 1fr); gap: 12px; margin-top: 32px; }
  .case-meta > div { display: grid; grid-template-columns: 4em minmax(0, 1fr); column-gap: 12px; align-items: baseline; }
  .case-meta dd { margin: 0; }
  /* English labels outgrow the 4em column; they stack above their values. */
  .case-meta:lang(en) { gap: 16px; }
  .case-meta:lang(en) > div { display: block; }
  .case-meta:lang(en) dd { margin-top: 4px; }
  .case-hero-media { margin-top: 32px; }
  .case-summary { margin-top: 48px; }
  .case-persona { grid-template-columns: 80px minmax(0, 1fr); gap: 16px; margin-top: 32px; padding: 16px; }
  .case-persona-portrait { grid-row: auto; }
  .case-persona-needs { grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .case-prototype { margin-top: 24px; }
  .case-product-overview { margin-top: 40px; }
  .case-product-actions { column-gap: 16px; }
  .case-chapter { margin-top: 64px; }
  .case-chapter > .section-heading, .case-summary > .section-heading, .case-next > .section-heading { gap: 10px; margin-bottom: 28px; }
  .case-chapter > .section-heading { margin-bottom: 32px; padding: 16px 20px; }
  .section-heading .case-chapter-name, .case-summary > .section-heading h2 { font-size: 1.625rem; }
  .case-section h4 { font-size: 1.0625rem; }
  .case-persona-identity h2 { font-size: 1.125rem; }
  .case-next-card .project-title { font-size: 1.1875rem; }
  .case-section + .case-section, .case-prototype + .case-section { margin-top: 56px; }
  .case-section:not(.case-split) > * + * { margin-top: 32px; }
  .case-stat { padding: 16px; }
  .case-stat-value { font-size: 1.5rem; }
  .case-stat .case-stat-value { font-size: min(1.5rem, 20.5cqi); }
  .case-stats--large .case-stat .case-stat-value { font-size: min(1.625rem, 24cqi); }
  .case-stat-icon { width: 30px; height: 30px; margin-inline-start: -4px; padding: 5px; border-radius: 8px; }
  .case-stats--large .case-stat-icon { width: 36px; height: 36px; margin-inline-start: 0; padding: 6px; }
  /* The lead card stacks: icon and number, then the meaning. */
  :is(.case-stats--five, .case-stats--lead) > .case-stat:first-child { grid-template-columns: auto minmax(0, 1fr); row-gap: 12px; column-gap: 14px; padding: 20px; }
  :is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-icon { width: 48px; height: 48px; padding: 12px; }
  :is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-value { font-size: 1.625rem; }
  :is(.case-stats--five, .case-stats--lead) > .case-stat:first-child .case-stat-label { grid-column: 1 / -1; margin: 0; padding: 0; border: 0; font-size: 1rem; }
  .case-stats--large .case-stat-value { font-size: 1.625rem; }
  /* Values like "39 → 83" are too wide for two phone columns at this size; stack them instead. */
  .case-stats.case-stats--wide { grid-template-columns: minmax(0, 1fr); }
  .case-media { padding: 16px; }
  .case-questions, .case-cards, .case-steps, .case-steps--five, .case-legend, .case-principles { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .case-gallery--phones { grid-template-columns: minmax(0, 1fr); }
  .case-gallery--three { grid-template-columns: minmax(0, 1fr); }
  /* The floor maps scale to about 0.8×; larger type keeps their labels near 12–13px. */
  .case-map-label { font-size: 17px; }
  .case-map-note { font-size: 15px; }
  .case-map-pin text { font-size: 13px; }
  .case-quote p { font-size: 1.125rem; }
  .case-gallery--phones .case-media { aspect-ratio: auto; }
  .case-gallery--phones .case-media > img { max-height: 520px; }
  .case-gallery--phones .case-phone { width: min(100%, 248px); height: auto; aspect-ratio: auto; }
  .case-card { padding: 16px; }
  .case-pin { width: 20px; height: 20px; font-size: .6875rem; }
  .case-compare { gap: 32px; }
  .case-split.case-compare--phones { grid-template-columns: minmax(0, 1fr); }
  .case-compare--phones .case-phone { max-width: 248px; }
  .case-compare-detail { grid-template-columns: minmax(0, 1fr); }
  .case-gallery { gap: 16px 12px; }
  .case-gallery .case-media { padding: 8px; }
  .case-screens, .case-screens--three { grid-template-columns: minmax(0, 1fr); gap: 12px; }
}

/* Next case study: every case study ends with a card for the project that follows it on the home page (the
   last leads back to the first), headed like a chapter and shaped like the home page's project cards (on the warm
   surface where those are white), 24px corners, text 40px in, the cover on the right. The whole card is one link, named by the project's
   category and title (the cover is decorative). On desktop it rises 4px on --shadow-hover under the pointer,
   like the home cards; the shadow sits on ::after so only its opacity animates. */
.case-next { margin-top: 128px; }
.case-next-card { position: relative; isolation: isolate; display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.3fr); align-items: center; column-gap: 48px; padding: 16px; background: var(--color-surface-warm); border-radius: var(--radius-2xl); color: inherit; text-decoration: none; }
.case-next-card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: var(--shadow-hover); opacity: 0; pointer-events: none; }
.case-next-card:focus-visible { outline: 2px solid var(--color-text); outline-offset: 4px; }
.case-next-text { padding-left: 24px; }
.case-next-card .project-category, .case-next-card .project-title { display: block; }
.case-next-card .project-title { font-size: 1.375rem; }
.case-next-media { display: flex; align-items: center; justify-content: center; aspect-ratio: 16 / 10; padding: 24px; }
/* The covers are the home page's, made for its white cards: multiplied onto this warm card, their white
   ground takes the card's colour instead of showing as a white box, and their colours shift by at most 3%. */
.case-next-media img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }
/* Clickable Category's cover is a phone cropped at its bottom edge; it sits on the bottom of its box and fades out over
   its lowest fifth instead of ending in a hard line with a clipped shadow (as on the homepage card). */
.case-next-media img[src*="clickable-category-poster"] { object-position: 50% 100%; -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent); mask-image: linear-gradient(to bottom, #000 78%, transparent); }
@supports (corner-shape: squircle) {
  .case-next-card, .case-next-card::after { corner-shape: squircle; }
}
@media (hover: hover) and (pointer: fine) {
  .case-next-card:hover::after { opacity: 1; }
}
@media (max-width: 767px) {
  .case-next { margin-top: 88px; }
  .case-next-card { grid-template-columns: minmax(0, 1fr); row-gap: 16px; padding: 20px; }
  .case-next-text { padding-left: 0; }
  .case-next-media { padding: 0; }
}
@media (prefers-reduced-motion: no-preference) {
  .case-next-card { transition: transform 600ms ease-in-out; }
  .case-next-card::after { transition: opacity 200ms ease-out; }
  @media (hover: hover) and (pointer: fine) {
    .case-next-card:hover { transform: translateY(-4px); transition-duration: 200ms; transition-timing-function: ease-out; }
  }
}
