/* ============================================================
   CASE-PROSA.CSS — Manu Farías portfolio
   Prosa rules on the portfolio brand.
   Load order: tokens.css → cases.css → case-prosa.css

   Opt-in per case: add .case--prosa next to .case--v4
     <section class="case case--v4 case--prosa">
   Cases without the class don't change.

   What Prosa brings (structure):
   - Serif for reading, sans for titles, labels, data and tables
   - One vertical rhythm (flow) instead of one margin per component
   - Line length in ch: 65ch text, 20ch h1
   - Separation with 1px lines, no shadows, square corners
   - Small labels: uppercase, tracked, one style everywhere
   - <mark> as a highlight band for the key idea
   What stays from the brand (identity):
   - Colors: --color-dark, --color-paper, --color-primary (orange),
     --color-accent (green), --color-mid, --color-rule, --color-info
   - Fonts: Geist (--font-sans) and Literata (--font-serif)
   - Type and space scales from tokens.css

   Uses native CSS nesting. Every rule sits under one scope:
   .case-content .case.case--v4.case--prosa (specificity 0,4,0), so it
   wins over sections 4–6 of cases.css without !important.

   Sections:
   0. Prosa tokens mapped to the brand
   1. Global — elements inside the case
   2. Flow — one vertical rhythm
   3. Labels — one small-label style
   4. Header and metadata
   5. In brief
   6. Sections and decisions
   7. Stats
   8. Figures, band and live window
   9. Callouts: trade-off and closing notes
   10. Disclosure
   11. Table
   12. Timeline
   13. Responsive and motion

   Surfaces are sampled from the case diagrams (SVG), so a diagram
   sits on the page with no visible box: ground #fbfaf8, cards #ffffff,
   header tint #f6f4f0, lines #e1dfda.

   Contrast (on --p-paper #fbfaf8): ink 16.3:1 · ink-muted 5.5:1 ·
   green 7.4:1 · orange 4.3:1 (underlines and icons only, never text) ·
   white on green badge 7.7:1. White on orange is 4.45:1: no orange
   fills behind text.
   ============================================================ */

/* --p-flow must not inherit: a block that sets it for itself
   would otherwise pass it to its own children. */
@property --p-flow {
  syntax: "*";
  inherits: false;
}

.case-content .case.case--v4.case--prosa {
  /* ─── 0. PROSA TOKENS → BRAND ─────────────────────────────── */
  /* Surfaces: sampled from the diagrams so SVGs blend into the page */
  --p-paper: #fbfaf8; /* page and figure band = diagram ground */
  --p-raised: #ffffff; /* cards: stats, callouts = diagram cards */
  --p-tint: #f6f4f0; /* table header, address bar = diagram table header */
  /* Never pure black: a softened warm ink for text, and a lighter one
     for frames and dividers. --color-dark is softened here too, so the
     base case styles (cases.css) inherit it inside Prosa cases. */
  --color-dark: #3d3935;
  --p-ink: #3d3935; /* text (near the diagrams' ink, #2b2b2b) */
  --p-ink-muted: var(--color-mid); /* labels, captions, meta */
  --p-ink-soft: #57524e; /* disclosure body: quieter than ink, 7.4:1 (AAA) */
  --p-rule: #4a4642; /* frames, callout strip, section dividers */
  --p-rule-soft: #e1dfda; /* row separators, figure frames = diagram lines */
  --p-link: var(--color-primary); /* link underline */
  --p-signal: var(--color-accent); /* status, timeline, focus on green */
  --p-mark: color-mix(in srgb, var(--color-primary) 22%, var(--p-paper));

  --p-font-display: var(--font-sans); /* titles, labels, data */
  --p-font-text: var(--font-serif); /* reading */

  --p-text: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem); /* 19–22.5px */
  --p-leading: 1.55;
  --p-leading-fine: 1.1;
  --p-tracking-title: -0.015em;
  --p-tracking-label: 0.08em;

  --p-stroke: 1px;
  --p-stroke-focus: 3px;
  --p-radius: 0;

  --measure: 65ch; /* overrides the 68ch v4 column */
  container-type: inline-size; /* 100cqi for the hero, outside any section */
  --p-figure-max: 54rem; /* figures: wider than the text, short of the edge */
  --p-screen-max: 66rem; /* screenshots: wider still, so UI text stays legible */
  --p-diagram-max: var(--p-screen-max); /* HTML diagrams: same width as screens, one pattern */
  /* Screen width: up to --p-screen-max, never closer than --space-l to
     the window edge, never narrower than the column (100cqi). */
  --p-screen-w: min(
    var(--p-screen-max),
    max(100cqi, 100vw - 2 * var(--space-l))
  );

  background: var(--p-paper);
  box-shadow: 0 0 0 100vmax var(--p-paper);
  color: var(--p-ink);
  font-family: var(--p-font-text);
  font-size: var(--p-text);
  line-height: var(--p-leading);

  /* ─── 1. GLOBAL ─────────────────────────────────────────── */
  & :is(h1, h2, h3) {
    font-family: var(--p-font-display);
    font-weight: 800;
    line-height: var(--p-leading-fine);
    letter-spacing: var(--p-tracking-title);
    text-wrap: balance;
    color: var(--p-ink);
  }

  & :is(p, li, dd) {
    text-wrap: pretty;
  }

  & a:not([class]) {
    color: currentColor;
    text-decoration-color: var(--p-link);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.2ex;
  }

  & a:not([class]):hover {
    text-decoration-color: currentColor;
  }

  & :is(ul, ol):not([class]) {
    padding-inline-start: 1.75ch;
  }

  & :is(ul, ol):not([class]) > li + li {
    margin-block-start: var(--space-2xs);
  }

  & :is(ul, ol):not([class]) > li::marker {
    color: var(--p-ink-muted);
  }

  /* Highlight band behind the key idea, Prosa's <mark> */
  & mark {
    background: linear-gradient(
      0deg,
      transparent 18%,
      var(--p-mark) 18%,
      var(--p-mark) 84%,
      transparent 84%
    );
    color: inherit;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
  }

  /* Utility: an element as wide as the window, from a centered column */
  & .full-bleed {
    width: 100vw;
    margin-left: calc(50% - 50vw);
  }

  & ::selection {
    background: var(--p-ink);
    color: var(--p-paper);
  }

  & :focus-visible {
    outline: var(--p-stroke-focus) solid var(--p-ink);
    outline-offset: 3px;
  }

  /* ─── 2. FLOW ───────────────────────────────────────────── */
  /* One rule spaces every block. Context changes --p-flow, not margins.
     Defaults: paragraphs space-m, after a title space-s, around big
     blocks (figures, tables, stats, callouts) space-xl. */
  & :is(.case-header, .case-section, .case-decision, .case-details__body)
    > * + * {
    margin-block-start: var(--p-flow, var(--space-m));
  }

  & :is(h2, h3, .case-eyebrow, .case-timeline__title) + * {
    --p-flow: var(--space-s);
  }

  & .case-section > .case-section-label + * {
    --p-flow: var(--space-l);
  }

  & :is(.case-section, .case-decision, .case-details__body)
    > :is(
      .case-figure,
      .case-table-wrap,
      .case-stats,
      .case-timeline,
      .case-tl,
      .case-decision__tradeoff
    ),
  & :is(.case-section, .case-decision, .case-details__body)
    > :is(
      .case-figure,
      .case-table-wrap,
      .case-stats,
      .case-timeline,
      .case-tl,
      .case-decision__tradeoff
    )
    + * {
    --p-flow: var(--space-xl);
  }

  & :is(.case-section, .case-decision) > .case-timeline__title {
    --p-flow: var(--space-xl);
  }

  & .case-timeline__title + .case-timeline {
    --p-flow: var(--space-s);
  }

  & :is(.case-section, .case-decision) > .case-details {
    --p-flow: var(--space-l);
  }

  & .case-details + .case-details {
    --p-flow: 0;
  }

  & .case-section > .case-decision + .case-decision {
    --p-flow: var(--space-2xl);
    padding-block-start: 0;
    border-block-start: 0;
  }

  & .case-section > .case-section-label + .case-decision {
    --p-flow: var(--space-xl);
  }

  /* Text column: 65ch for reading, the rest can be wider */
  & :is(.case-section, .case-decision, .case-details__body) > :is(p, ul, ol) {
    max-width: var(--measure);
  }

  /* ─── 3. LABELS ─────────────────────────────────────────── */
  /* Prosa type-label: uppercase, bold, tracked. Same style for the
     eyebrow, metadata, brief, timeline, table header and section number. */
  &
    :is(
      .case-eyebrow,
      .case-meta dt,
      .case-brief dt,
      .case-timeline__title,
      .case-tl__title,
      .case-timeline__date,
      .case-section-label__num,
      .case-figure__label
    ) {
    max-width: none;
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    font-style: normal;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
    color: var(--p-ink-muted);
  }

  /* ─── 4. HEADER AND METADATA ────────────────────────────── */
  & .case-header {
    padding-block-start: var(--space-xl);
  }

  & .case-header h1 {
    max-width: 20ch;
    font-size: var(--size-display);
    line-height: 1.04;
    letter-spacing: -0.025em;
  }

  /* Metadata row: two solid lines frame it, gap separates the fields */
  & .case-meta {
    gap: var(--space-s) var(--space-m);
    margin-block: var(--space-xl) 0;
    padding-block: var(--space-m);
    border-block: var(--p-stroke) solid var(--p-rule-soft);
    font-family: var(--p-font-display);
  }

  & .case-meta dd {
    margin-block-start: var(--space-2xs);
  }

  & .case-meta__main {
    font-size: var(--size-step-0);
    font-weight: 600;
    line-height: 1.3;
    color: var(--p-ink);
  }

  & .case-meta__sub {
    font-size: var(--size-step--1);
    line-height: 1.45;
    color: var(--p-ink-muted);
  }

  /* Status as a Prosa badge: the word carries the meaning */
  & .case-meta__status {
    gap: var(--space-3xs);
    padding: 0.35em 0.6em;
    background: var(--p-signal);
    color: #fff;
    font-size: var(--size-step--1);
    font-weight: 700;
    line-height: 1;
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
  }

  /* ─── 5. IN BRIEF ───────────────────────────────────────── */
  /* Lines above and below, soft rules between rows. No side bar. */
  & .case-brief {
    max-width: var(--measure);
    margin-block-start: var(--space-xl);
  }

  & h2.case-brief__title {
    font-family: var(--p-font-display);
    font-size: var(--size-step-1);
    font-weight: 800;
    letter-spacing: var(--p-tracking-title);
    text-transform: none;
    color: var(--p-ink);
  }

  & .case-brief__list {
    margin-block-start: var(--space-s);
    padding-inline-start: 0;
    border-inline-start: 0;
    border-block: var(--p-stroke) solid var(--p-rule);
  }

  & .case-brief__row,
  & .case-brief__row:first-child,
  & .case-brief__row:last-child {
    padding-block: var(--space-s);
  }

  & .case-brief__row + .case-brief__row {
    border-block-start-color: var(--p-rule-soft);
  }

  & .case-brief dd {
    font-family: var(--p-font-text);
    font-size: var(--p-text);
    line-height: 1.5;
  }

  & .case-brief__row--outcome dd {
    font-weight: 500;
  }

  /* Quote: a brand-orange rule (a graphic, 4.3:1 passes the 3:1 for
     non-text), the text in the reading face. */
  & .case-quote blockquote {
    border-inline-start: calc(var(--p-stroke) * 2) solid var(--color-primary);
    padding-block: 0.15em;
    font-family: var(--p-font-text);
    font-style: normal; /* Literata's italic is too ornate at this size */
    line-height: 1.4;
  }
  /* Short measure and a bit of weight: it reads as a pull quote. The
     opening curly quote hangs, so the text lines up with the caption */
  & .case-quote blockquote p {
    max-width: 30ch;
    font-weight: 500;
    text-indent: -0.42em;
  }
  & .case-quote figcaption {
    margin-block-start: var(--space-xs);
    /* lines up with the quote's text: its padding plus the rule */
    padding-inline-start: calc(var(--space-s) + var(--p-stroke) * 2);
  }

  /* ─── 6. SECTIONS AND DECISIONS ─────────────────────────── */
  & .case-section {
    margin-block-start: var(--space-2xl-3xl);
    padding-block-start: var(--space-m);
    border-block-start: var(--p-stroke) solid var(--p-rule);
  }

  /* Section title: number as a label, title in the reading serif.
     Prosa sets the h2 inside an article in its accent serif. */
  & h2.case-section-label {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2xs);
    max-width: 28ch;
    font-family: var(--p-font-text);
    font-size: var(--size-step-3);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.01em;
    text-transform: none;
    color: var(--p-ink);
  }

  & .case-section-label__num::after {
    content: none;
  }

  & :is(.case-decision, .case-decision__head) > h3 {
    max-width: 30ch;
    font-size: var(--size-step-2);
    font-weight: 800;
  }

  /* Decision line: reading text, the label in sans */
  & .case-decision__summary {
    max-width: var(--measure);
    font-family: var(--p-font-text);
    font-size: var(--p-text);
    font-weight: 400;
    line-height: var(--p-leading);
  }

  &
    :is(.case-decision__summary, .case-decision__tradeoff, .case-after__line)
    strong {
    font-family: var(--p-font-display);
    font-weight: 700;
    color: var(--p-ink);
  }

  /* ─── 7. STATS ──────────────────────────────────────────── */
  /* Prosa grid: as many columns as fit. Cards framed by a line. */
  /* ul.case-stats: wins over the 65ch rule for lists in section 2 */
  /* Same width as the diagrams */
  & :is(.case-section, .case-decision) > ul.case-stats {
    max-width: var(--p-figure-max);
  }

  & .case-stats {
    grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
    gap: var(--space-s);
    /* Top margin comes from the flow (section 2): --space-xl, like figures.
       Only the bottom is reset here. */
    margin-block-end: 0;
  }

  & .case-stats li {
    margin: 0;
    padding: var(--space-m);
    border: var(--p-stroke) solid var(--p-rule);
    border-radius: var(--p-radius);
    background: var(--p-raised);
  }

  & .case-stats__icon {
    color: var(--p-ink-muted);
  }

  & .case-stats__num {
    font-family: var(--p-font-display);
    font-size: var(--size-step-4);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
  }

  & .case-stats__label {
    margin-block-start: var(--space-xs);
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    line-height: 1.45;
    color: var(--p-ink);
  }

  /* ─── 8. FIGURES, BAND AND LIVE WINDOW ──────────────────── */
  /* Every figure is a framed window, like the live demo in the hero:
     a soft line around the image and a bar at the bottom that holds
     the caption (the browser bar, turned into a footer).
     Width: wider than the 65ch reading column, never to the screen
     edge. --p-figure-max (section 0) resizes every figure at once. */

  & .case-figure--dark,
  & .case-figure--dark.case-figure--hero {
    --band-pad: 0px;
    --hero-pad: 0px;
    grid-template-areas:
      "label"
      "media"
      "caption";
    width: 100%;
    max-width: var(--p-figure-max);
  }

  & .case-figure--dark::before {
    display: none;
  }

  /* Media: image, zoom button or live window. Top and sides of the frame */
  & .case-figure--dark > :not(figcaption, .case-figure__label),
  & .case-figure--dark.case-figure--hero > :not(figcaption, .case-figure__label) {
    grid-area: media;
    width: 100%;
    margin: 0;
    border: var(--p-stroke) solid var(--p-rule-soft);
    border-radius: var(--p-radius);
    background: var(--p-paper);
    box-shadow: none;
  }

  & .case-figure--dark img,
  & .case-window {
    border-radius: var(--p-radius);
    background: var(--p-paper);
    box-shadow: none;
  }

  /* Image inside the zoom button: the button already draws the frame */
  & .case-figure--dark > .case-zoom img {
    border: 0;
  }

  & .case-zoom {
    border-radius: var(--p-radius);
  }

  /* Footer bar: the caption closes the frame, styled like the hero's
     address bar (same ground, same soft line, same sans) */
  & .case-figure--dark > figcaption,
  & .case-figure--dark.case-figure--hero > figcaption {
    grid-area: caption;
    align-self: auto;
    justify-self: stretch;
    max-width: none;
    margin: 0;
    padding: 0.7em var(--space-s);
    border: var(--p-stroke) solid var(--p-rule-soft);
    border-block-start: 0;
    background: var(--p-paper);
    color: var(--p-ink-muted);
  }

  & .case-caption {
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    line-height: 1.45;
    color: var(--p-ink-muted);
  }

  /* Screens are wider than diagrams: a 1600px screenshot shown at
     ~970px drops UI text to 8–9px. At --p-screen-w it stays ~70–75%. */
  /* Centered on the window with the .full-bleed technique (section 1):
     the column is centered, so half the column minus half the screen
     puts the screen in the middle of the window. */
  & .case-figure--dark.case-figure--screen,
  & .case-figure--dark.case-figure--hero {
    width: var(--p-screen-w);
    max-width: none;
    margin-inline-start: calc(50% - var(--p-screen-w) / 2);
  }

  /* The hero screen is the most important one: on any desktop it takes
     the window like on a notebook (a --space-l margin each side), up to
     100rem, where the 2372px capture still stays sharp. */
  & .case-figure--dark.case-figure--hero {
    --p-hero-w: min(100rem, max(100cqi, 100vw - 2 * var(--space-l)));
    width: var(--p-hero-w);
    margin-inline-start: calc(50% - var(--p-hero-w) / 2);
  }

  /* Unbuilt alternatives stay smaller than the built ones */
  & .case-figure--dark.case-figure--unbuilt {
    max-width: min(75%, var(--p-figure-max));
  }

  @media (max-width: 600px) {
    & .case-figure--dark.case-figure--unbuilt {
      max-width: none;
    }
  }

  /* Screens (.case-figure--screen, set in the HTML with a data-url):
     a browser bar on top, built like the hero's window bar. The bar is
     ::before (frame and dots), the address pill is ::after (the text
     comes from data-url). The caption sits below, without the box. */
  & .case-figure--dark.case-figure--screen {
    grid-template-areas:
      "label"
      "bar"
      "media"
      "caption";
  }

  & .case-figure--dark.case-figure--screen::before,
  & .case-figure--dark.case-figure--hero::before {
    content: "";
    display: block;
    grid-area: bar;
    margin: 0; /* the v4 hero band bled to the screen edge */
    border: var(--p-stroke) solid var(--p-rule-soft);
    border-radius: var(--p-radius);
    background:
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent)
        var(--space-xs) 50% / 0.6em 0.6em,
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent)
        calc(var(--space-xs) + 1em) 50% / 0.6em 0.6em,
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent)
        calc(var(--space-xs) + 2em) 50% / 0.6em 0.6em,
      var(--p-paper);
    background-repeat: no-repeat;
    font-size: 0.8rem;
  }

  & .case-figure--dark.case-figure--screen::after,
  & .case-figure--dark.case-figure--hero::after {
    content: attr(data-url);
    grid-area: bar;
    place-self: center;
    max-width: calc(100% - 9em);
    margin-block: 0.6em;
    padding: 0.35em 1.2em;
    overflow: hidden;
    border: var(--p-stroke) solid var(--p-rule-soft);
    background: var(--p-tint);
    font-family: var(--p-font-display);
    font-size: 0.72rem;
    line-height: 1;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--p-ink-muted);
  }

  /* The bar draws the top line of the frame */
  & .case-figure--dark.case-figure--screen
    > :not(figcaption, .case-figure__label) {
    border-block-start: 0;
  }

  /* Caption of a screen: no box, aligned with the screen's left edge */
  & .case-figure--dark.case-figure--screen > figcaption,
  & .case-figure--dark.case-figure--hero > figcaption {
    padding-inline: 0;
    border: 0;
    background: none;
  }

  /* Hero: a static screenshot, framed like every other screen (it also
     carries .case-figure--screen): CSS bar on top at every width */
  & .case-figure--dark.case-figure--hero {
    grid-template-areas:
      "label"
      "bar"
      "media"
      "caption";
  }

  & .case-figure--dark.case-figure--hero > img,
  & .case-figure--dark.case-figure--hero > .case-zoom {
    border-block-start: 0;
  }

  /* Figures inside a disclosure: same left edge and width as every
     other figure. The text keeps its indent and 65ch; only the figure
     steps out to the section edge. 100cqi = width of the section. */
  & .case-section {
    container-type: inline-size;
  }

  & .case-details__body > .case-figure--dark {
    --p-details-indent: calc(var(--details-icon) + var(--details-gap));
    width: min(var(--p-figure-max), 100cqi);
    max-width: none;
    margin-inline-start: calc(-1 * var(--p-details-indent));
  }

  /* Inside a disclosure the body is indented: center on the section */
  & .case-details__body > .case-figure--dark.case-figure--screen {
    width: var(--p-screen-w);
    margin-inline-start: calc(
      (100cqi - var(--p-screen-w)) / 2 - var(--p-details-indent)
    );
  }

  & .case-details__body > .case-figure--dark.case-figure--unbuilt {
    width: calc(min(var(--p-figure-max), 100cqi) * 0.75);
  }

  /* An unbuilt screen stays small and aligned with the text, not centered */
  & .case-details__body > .case-figure--dark.case-figure--screen.case-figure--unbuilt {
    margin-inline-start: calc(-1 * var(--p-details-indent));
  }

  @media (max-width: 600px) {
    & .case-details__body > .case-figure--dark.case-figure--unbuilt {
      width: 100cqi;
    }
  }

  /* Label above the frame ("Explored, not built") */
  & .case-figure--dark > .case-figure__label {
    margin-block-end: var(--space-2xs);
  }

  /* "Explored, not built": outline label, dashed because it wasn't built */
  & .case-figure__label {
    padding: 0.4em 0.6em;
    border: var(--p-stroke) dashed var(--p-ink-muted);
    line-height: 1;
  }

  & .case-window__bar {
    background: var(--p-paper);
    border-block-end: var(--p-stroke) solid var(--p-rule-soft);
    font-family: var(--p-font-display);
  }

  & .case-window__url {
    border: var(--p-stroke) solid var(--p-rule-soft);
    border-radius: var(--p-radius);
    background: var(--p-tint);
  }

  /* Replay as a Prosa ghost button */
  & .case-window__replay {
    border: var(--p-stroke) solid var(--p-ink);
    border-radius: var(--p-radius);
    background: transparent;
    color: var(--p-ink);
    font-weight: 700;
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
  }

  & .case-window__replay:hover {
    border-color: var(--p-ink);
    background: var(--p-ink);
    color: var(--p-paper);
  }

  /* HTML diagrams (diagrams.css): framed, with the caption in the
     footer bar, as wide as screens and centered on the window like them. The diagram keeps
     its aspect ratio, so more width means more height and larger text.
     Width: up to --p-diagram-max, never closer than --space-l to the
     window edge, never narrower than the column. */
  & .case-figure--dark.case-figure--diagram {
    --p-diagram-w: min(
      var(--p-diagram-max),
      max(100cqi, 100vw - 2 * var(--space-l))
    );
    width: var(--p-diagram-w);
    max-width: none;
    margin-inline-start: calc(50% - var(--p-diagram-w) / 2);
  }

  /* Diagram footer: the bar keeps the frame's full width, the text is
     centered in it. Screens keep their caption aligned left. */
  & .case-figure--dark.case-figure--diagram > figcaption {
    text-align: center;
    text-wrap: balance;
  }

  /* Inside a disclosure the body is indented: center on the section */
  & .case-details__body > .case-figure--dark.case-figure--diagram {
    width: var(--p-diagram-w);
    margin-inline-start: calc(
      (100cqi - var(--p-diagram-w)) / 2 - var(--p-details-indent)
    );
  }

  /* Live prototype inside a screen figure (.case-live): the flow loads
     dimmed under an invitation; one click starts it. The screenshot is
     the fallback below 768px, where a live screen is too small to use. */
  & .case-live {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
  }

  & .case-live__screen {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    pointer-events: none;
  }

  & .case-live.is-live .case-live__screen {
    opacity: 1;
    filter: none;
    pointer-events: auto;
  }

  & .case-live__start {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    padding: 0;
    border: 0;
    /* After AlignUI's preview: the top of the screen reads clearly and
       fades toward the bottom, never fully, so the screen stays there */
    background: linear-gradient(
      to bottom,
      rgb(251 250 248 / 0) 0%,
      rgb(251 250 248 / 0.15) 30%,
      rgb(251 250 248 / 0.7) 62%,
      rgb(251 250 248 / 0.88) 100%
    );
    font-family: var(--p-font-display);
  }

  & .case-live.is-live .case-live__start {
    display: none;
  }

  /* The whole preview starts the prototype: the button's hit area is
     stretched over the overlay (the button itself stays unpositioned) */
  & .case-live__cta::before {
    content: "";
    position: absolute;
    inset: 0;
    cursor: pointer;
  }

  /* The call to action, styled as a Prosa dark button */
  & .case-live__cta {
    padding: var(--space-xs) var(--space-m);
    border: var(--p-stroke) solid var(--p-ink);
    background: var(--p-ink);
    font-size: var(--size-step--1);
    font-weight: 700;
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
    font-family: inherit;
    color: var(--p-paper);
    cursor: pointer;
    transition:
      background 150ms ease,
      color 150ms ease;
  }

  /* Hover on the button itself, only with a real pointer: no sticky
     hover on touch */
  @media (hover: hover) and (pointer: fine) {
    & .case-live__cta:hover {
      background: var(--p-paper);
      color: var(--p-ink);
    }
  }

  & .case-live__cta:focus-visible {
    background: var(--p-paper);
    color: var(--p-ink);
    outline: 2px solid var(--p-ink);
    outline-offset: 3px;
  }

  & .case-figure--dark > .case-live ~ :is(img, .case-zoom) {
    display: none;
  }

  @media (max-width: 767px) {
    & .case-figure--dark > .case-live {
      display: none;
    }

    & .case-figure--dark > .case-live ~ :is(img, .case-zoom) {
      display: block;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .case-live__cta {
      transition: none;
    }
  }

  /* ─── 9. CALLOUTS: TRADE-OFF AND CLOSING NOTES ──────────── */
  /* Prosa callout: raised panel, full line around it, label on top.
     On the left, a strip of diagonal hairlines (after Tailwind's gutters,
     in the callout's own black and white): it gives the callout a
     character of its own and breaks the reading rhythm. The strip is a
     pseudo-element inside the full border, so the frame stays whole. */
  & :is(.case-decision__tradeoff, .case-after__change) {
    --callout-strip: 1rem;
    position: relative;
    max-width: var(--measure);
    padding: var(--space-s) var(--space-m);
    padding-inline-start: calc(var(--callout-strip) + var(--space-m));
    border: var(--p-stroke) solid var(--p-rule);
    border-radius: var(--p-radius);
    background: var(--p-raised);
    font-family: var(--p-font-display);
    font-size: var(--size-step-0);
    line-height: 1.5;
  }

  & :is(.case-decision__tradeoff, .case-after__change)::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: var(--callout-strip);
    border-inline-end: var(--p-stroke) solid var(--p-rule);
    background: repeating-linear-gradient(315deg, var(--p-rule) 0 1px, transparent 0 50%) 0 0 / 7px 7px;
    pointer-events: none;
  }

  & :is(.case-decision__tradeoff, .case-after__change) strong {
    font-size: var(--size-step--1);
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
  }

  & .case-decision__tradeoff strong {
    margin-inline-end: 0.4em;
  }

  & .case-after__change strong {
    display: block;
    margin-block-end: var(--space-2xs);
  }

  & .case-after__change ul {
    padding-inline-start: 1.75ch;
  }

  & .case-after__change li + li {
    margin-block-start: var(--space-2xs);
  }

  & .case-after {
    gap: var(--space-s);
    margin-block-start: var(--space-l);
  }

  & .case-after__line {
    font-size: var(--p-text);
  }

  & .case-after__change {
    margin-block-start: var(--space-xs);
  }

  /* ─── 10. DISCLOSURE ────────────────────────────────────── */
  /* Prosa disclosure: lines above and below, label in sans, "+" that
     turns into "×". The icon keeps its meaning (bulb = why,
     info = context) and takes the brand color when open. */
  & .case-details {
    --details-icon: 1.4em;
    --details-gap: 0.55em; /* icon ↔ title, a little closer than --space-xs */
    border-block: 0; /* no lines: the disclosure reads by its icon and + */
    border-radius: var(--p-radius);
    background: none;
  }

  & .case-details + .case-details {
    border-block-start: 0;
  }

  & .case-details > summary {
    display: flex;
    align-items: center;
    gap: var(--details-gap);
    width: 100%;
    padding: var(--space-s) 0;
    border-radius: var(--p-radius);
    font-family: var(--p-font-display);
  }

  & .case-details > summary::after {
    content: "+";
    margin-inline-start: auto;
    font-size: 1.4em;
    font-weight: 400;
    line-height: 0.9;
    color: var(--p-ink);
    /* Closed: no floating "+"; the icon and the hover underline invite the click.
       Open: a "×" appears so the reader knows how to close it. */
    opacity: 0;
    transform: rotate(0deg) scale(0.8);
    transition:
      opacity 180ms cubic-bezier(0.23, 1, 0.32, 1),
      transform 200ms cubic-bezier(0.23, 1, 0.32, 1);
  }

  & .case-details[open] > summary::after {
    opacity: 1;
    transform: rotate(45deg) scale(1);
  }

  & .case-details__icon,
  & .case-details[open] .case-details__icon {
    inline-size: var(--details-icon);
    block-size: var(--details-icon);
    flex: none;
    margin-block-start: 0;
    padding: 0;
    background: none;
    color: var(--p-ink-muted);
  }

  & .case-details[open] .case-details__icon {
    color: var(--details-fill);
  }

  /* The bulb carries its weight at the top: lift it a little so it
     sits on the middle of the words (value chosen with the tuner) */
  & .case-details__icon--bulb {
    translate: 0 -3px;
  }

  /* Open state: the icon turns orange and the label gets a highlight
     drawn from left to right, like a marker, in the same tone (--p-mark).
     Both share one duration and curve so they read as one gesture:
     280ms in, 180ms out (exits are quieter), same ease-out.
     .case-details__mark is an inline span inside the label, so the
     stroke follows the text line by line. */
  & .case-details__icon {
    transition: color 180ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  & .case-details[open] .case-details__icon {
    transition: color 280ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  & .case-details__mark {
    background: linear-gradient(
        0deg,
        transparent 12%,
        var(--p-mark) 12%,
        var(--p-mark) 88%,
        transparent 88%
      )
      left / 0% 100% no-repeat;
    transition: background-size 180ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  & .case-details[open] .case-details__mark {
    background-size: 100% 100%;
    transition: background-size 280ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  @media (prefers-reduced-motion: reduce) {
    & .case-details__icon,
    & .case-details[open] .case-details__icon,
    & .case-details__mark,
    & .case-details[open] .case-details__mark {
      transition: none;
    }
  }

  /* One color for every disclosure icon: "Why…" and "More context…"
     both open in the brand orange (icon only, 4.3:1 on the page) */
  & .case-details__icon--info {
    --details-fill: var(--color-primary);
  }

  & .case-details__label {
    font-size: var(--size-step-0);
    font-weight: 600;
    line-height: 1.4;
    text-decoration: none;
    color: var(--p-ink);
  }

  & .case-details__label::after {
    content: none;
  }

  /* Underline on hover only while closed: open, the highlight marks it */
  & .case-details:not([open]) > summary:hover .case-details__label {
    text-decoration: underline;
    text-decoration-color: var(--p-link);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.2ex;
  }

  & .case-details__body {
    max-width: none;
    padding: 0 0 var(--space-m);
    padding-inline-start: calc(var(--details-icon) + var(--details-gap));
  }

  & .case-details__body,
  & .case-details__body > :is(p, ul, ol) {
    font-family: var(--p-font-text);
    font-size: var(--p-text);
    color: var(--p-ink); /* same ink as the body text */
  }

  /* ─── 11. TABLE ─────────────────────────────────────────── */
  /* Prosa table: frame and cell lines, label-style header row */
  & .case-table {
    border: var(--p-stroke) solid var(--p-rule);
    font-family: var(--p-font-display);
    font-size: var(--size-step-0);
  }

  & .case-table :is(th, td),
  & .case-table :is(th, td):first-child {
    padding: var(--space-xs) var(--space-s);
    border: var(--p-stroke) solid var(--p-rule-soft);
  }

  & .case-table thead th,
  & .case-table thead th:first-child {
    background: var(--p-tint);
    border-block-end: var(--p-stroke) solid var(--p-rule);
    font-size: var(--size-step--1);
    font-weight: 700;
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
    color: var(--p-ink);
  }

  & .case-table tbody th {
    font-family: var(--p-font-text);
    font-size: var(--size-step-0);
    font-weight: 400;
  }

  & .case-table-wrap:focus-visible {
    outline: var(--p-stroke-focus) solid var(--p-ink);
    outline-offset: 3px;
  }

  /* ─── 12. TIMELINE ──────────────────────────────────────── */
  & ol.case-timeline {
    --timeline-bg: var(--p-paper);
    font-family: var(--p-font-display);
  }

  & .case-timeline__event {
    font-size: var(--size-step-0);
    line-height: 1.35;
  }

  /* ─── 12b. TIMELINE ────────────────────────────────────── */
  /* Built from the timeline recipe: every element sits at its month
     index. May = 0 … Dec = 7, so a position is --i / --tl-steps × 100%
     of the track and a duration is --span / --tl-steps × 100%.
     Same look as the case diagrams: JetBrains Mono, small caps labels,
     quiet greys, no frame. Values follow the recipe (px).
     Horizontal from 900px; below, the same --i drive a vertical layout.

     Markup (helpdesk.html):
     figure.case-tl > p.case-tl__title
       + div.case-tl__track
           > ol.case-tl__scale[aria-hidden] > li[--i] (one per month)
           + ol.case-tl__events > li[--i, --span?, --c, --c2?]
     Colour never carries the meaning alone: the list order and the
     <time> in every item tell the same story. */
  & .case-tl {
    /* Tokens: change the ramp (five lines) to recolour it */
    --tl-bg: var(--p-paper);
    --tl-ink: #2b2b2b;
    --tl-text: #4a4640;
    --tl-muted: #6f6a63;
    --tl-faint: #c9c5be;
    --tl-line: #e2dfd9;
    --tl-tone-1: #c9c5be;
    --tl-tone-2: #a09b93;
    --tl-tone-3: #77726b;
    --tl-tone-4: #524e48;
    --tl-tone-5: #2b2b2b;
    --tl-steps: 7; /* intervals between May and December */
    --tl-axis-y: 34px; /* axis height inside the track */
    --tl-dot: 14px;
    --tl-dot-final: 19px;

    max-width: var(--p-figure-max);
    margin-inline: 0;
    padding: 0;
    border: var(--p-stroke) solid var(--p-rule-soft); /* the block's frame */
    font-family: "JetBrains Mono", "IBM Plex Mono", "SF Mono", Menlo, Consolas,
      monospace;
    color: var(--tl-text);
  }

  /* Label. The recipe's #8a8780 is 3.4:1 at 12px; --tl-muted passes AA */
  /* p.case-tl__title outranks the shared label style (section 3) */
  /* Header block: the label, closed by a soft line */
  & .case-tl > p.case-tl__title {
    margin: 0;
    padding: 14px var(--space-l);
    border-block-end: var(--p-stroke) solid var(--p-rule-soft);
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--tl-muted);
  }

  & .case-tl__track {
    position: relative;
    container-type: inline-size; /* 100cqi = track width, for labels */
  }

  /* Axis */
  & .case-tl__track::before {
    content: "";
    position: absolute;
    background: var(--tl-line);
  }

  & .case-tl__scale,
  & .case-tl__events {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* Month scale: decorative, the dates live in each <time> */
  & .case-tl__scale > li {
    position: absolute;
    margin: 0;
    font-size: 11px;
    line-height: 1;
    letter-spacing: 1px;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--tl-faint);
  }

  & .case-tl__scale > li.is-active {
    font-weight: 700;
    color: var(--tl-muted);
  }

  /* Tick */
  & .case-tl__scale > li::after {
    content: "";
    position: absolute;
    background: var(--tl-line);
  }

  & .case-tl__events > li {
    position: absolute;
    margin: 0;
  }

  /* Start dot (every event) and end dot (a range) */
  & .case-tl__events > li::before,
  & .case-tl__events > li.is-range::after {
    content: "";
    position: absolute;
    z-index: 2;
    inline-size: var(--tl-dot);
    block-size: var(--tl-dot);
    border-radius: 50%;
    background: var(--c);
    box-shadow: 0 0 0 3px var(--tl-bg); /* separates the dot from the line */
    transform: translate(-50%, -50%);
  }

  & .case-tl__events > li::before {
    inset-block-start: 0;
    inset-inline-start: 0;
  }

  & .case-tl__events > li.is-range::after {
    background: var(--c2);
  }

  /* Final: the same dot, a little bigger */
  & .case-tl__events > li.is-outcome::before {
    inline-size: var(--tl-dot-final);
    block-size: var(--tl-dot-final);
  }

  /* Planned: not done yet. A hollow dot and a quieter label */
  & .case-tl__events > li.is-planned::before {
    background: var(--tl-bg);
    box-shadow:
      inset 0 0 0 2px var(--c),
      0 0 0 3px var(--tl-bg);
  }
  & .case-tl__events > li.is-planned .case-tl__event {
    color: var(--tl-muted);
  }

  /* Range bar between its two dots, in a gradient */
  & .case-tl__bar {
    position: absolute;
    z-index: 1;
    border-radius: 2px;
  }

  & .case-tl__event {
    position: absolute;
    display: block;
    margin: 0;
    font-size: 15px;
    line-height: 1.35;
    color: var(--tl-text);
  }

  & .case-tl__events > li.is-outcome .case-tl__event {
    font-weight: 700;
    color: var(--tl-ink);
  }

  & .case-tl__date {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  /* Vertical (below 900px): --i drives top */
  & .case-tl__track {
    block-size: calc(var(--tl-steps) * var(--tl-step-h, 44px)); /* --tl-step-h: more air when there are few steps */
    margin-block: 36px var(--tl-end, 32px); /* --tl-end: room for a last label that wraps */
    margin-inline-start: calc(var(--space-l) + 48px); /* month names */
  }

  & .case-tl__track::before {
    inset-block: 0;
    inset-inline-start: -1px;
    inline-size: 2px;
  }

  & .case-tl__scale > li {
    inset-block-start: calc(var(--i) / var(--tl-steps) * 100%);
    inset-inline-end: calc(100% + 18px);
    transform: translateY(-50%);
  }

  & .case-tl__scale > li::after {
    inset-block-start: 50%;
    inset-inline-start: calc(100% + 12px);
    inline-size: 12px;
    block-size: 1.5px;
    transform: translateY(-50%);
  }

  & .case-tl__events > li {
    inset-block-start: calc(var(--i) / var(--tl-steps) * 100%);
    inset-inline-start: 0;
    inline-size: 0;
    block-size: calc(var(--span, 0) / var(--tl-steps) * 100%);
  }

  & .case-tl__events > li.is-range::after {
    inset-block-start: 100%;
    inset-inline-start: 0;
  }

  & .case-tl__bar {
    inset-block: 0;
    inset-inline-start: -2px;
    inline-size: 4px;
    background: linear-gradient(to bottom, var(--c), var(--c2));
  }

  & .case-tl__event {
    inset-block-start: -10px;
    inset-inline-start: 22px;
    inline-size: max-content;
    max-inline-size: 60vw;
  }

  /* Horizontal (from 900px): --i drives left */
  @media (min-width: 900px) {
    & .case-tl__track {
      block-size: var(--tl-track-h, 110px); /* taller when a label wraps: set --tl-track-h on the figure */
      margin-block: 32px 8px;
      /* start: half a month name and the first dot stay inside;
         end: room for the last event's label */
      margin-inline: calc(var(--space-l) + 16px) calc(var(--space-l) + 140px);
    }

    & .case-tl__track::before {
      inset-block: var(--tl-axis-y) auto;
      inset-inline: 0;
      inline-size: auto;
      block-size: 2px;
      margin-block-start: -1px;
    }

    & .case-tl__scale > li {
      inset-block-start: 0;
      inset-inline: calc(var(--i) / var(--tl-steps) * 100%) auto;
      transform: translateX(-50%);
    }

    & .case-tl__scale > li::after {
      inset-block-start: calc(var(--tl-axis-y) - 6px);
      inset-inline-start: 50%;
      inline-size: 1.5px;
      block-size: 12px;
      transform: none;
    }

    & .case-tl__events > li {
      inset-block-start: var(--tl-axis-y);
      inset-inline-start: calc(var(--i) / var(--tl-steps) * 100%);
      inline-size: calc(var(--span, 0) / var(--tl-steps) * 100%);
      block-size: 0;
    }

    & .case-tl__events > li.is-range::after {
      inset-block-start: 0;
      inset-inline-start: 100%;
    }

    & .case-tl__bar {
      inset-block: -2px auto;
      inset-inline: 7px 0;
      inline-size: auto;
      block-size: 4px;
      background: linear-gradient(to right, var(--c), var(--c2));
    }

    /* Text under the dot, starting at the dot's left edge */
    & .case-tl__event {
      inset-block-start: calc(60px - var(--tl-axis-y));
      inset-inline-start: -7px;
      inline-size: max-content;
      /* never past the next milestone: --room = months until it */
      max-inline-size: calc(var(--room, 99) / var(--tl-steps) * 100cqi - 12px);
    }

    /* A range label centred over its bar (add .is-centered to the li) */
    & .case-tl__events > li.is-centered .case-tl__event {
      inset-inline-start: 50%;
      max-inline-size: none;
      transform: translateX(-50%);
    }
  }

  /* ─── 12c. COMPONENT STATES (.case-states) ────────────── */
  /* One component in several states, shown alone instead of a whole
     screen per state. A segmented button group on top (after the Aura
     demo tabs), a stage in the Nexo page grey, a caption footer.
     All panels share one grid cell, so the figure keeps the height of
     the tallest and never jumps when the state changes. Each card image
     is scaled by its own CSS width (--w) against the widest (674px), so
     the three cards keep one scale. */
  & .case-states {
    /* After Tailwind's site: diagonal hairlines fill the gap around the
       stage; the stage itself is a plain light grey, so nothing competes
       with the component */
    --states-line: rgba(0, 0, 0, 0.1); /* black lines, very light */
    --states-hatch: repeating-linear-gradient(
        315deg,
        rgba(0, 0, 0, 0.06) 0 1px,
        transparent 0 50%
      )
      0 0 / 10px 10px;
    --states-ground: #f6f6f5;
    --states-ease: cubic-bezier(0.32, 0.72, 0, 1);
    --states-frame-h: 320px; /* the stage's least height */
    --states-gap: var(--space-s); /* hatched gap around the stage */
    --frame-zoom: 1;
    width: var(--p-screen-w);
    max-width: none;
    margin-inline-start: calc(50% - var(--p-screen-w) / 2);
    position: relative;
    border: var(--p-stroke) solid var(--states-line);
    /* The stage's two vertical guide lines run the figure's full height
       (drawn here, so nothing has to clip them), over the hatch */
    background:
      linear-gradient(var(--states-line), var(--states-line)) left var(--states-gap) top 0 / 1px 100% no-repeat,
      linear-gradient(var(--states-line), var(--states-line)) right var(--states-gap) top 0 / 1px 100% no-repeat,
      var(--states-hatch),
      var(--p-paper);
  }

  & .case-states__tabs {
    display: flex;
    gap: 4px;
    width: fit-content;
    max-width: calc(100% - 2 * var(--space-s));
    margin: var(--space-s) auto 0;
    padding: 4px;
    overflow-x: auto;
    border: var(--p-stroke) solid var(--states-line);
    border-radius: 999px;
    background: var(--p-tint);
    scrollbar-width: none;
  }

  & .case-states__tab {
    position: relative;
    flex: 0 0 auto;
    overflow: hidden;
    padding: 0.55em 1.1em;
    border: 0;
    border-radius: 999px;
    background: transparent;
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    color: var(--p-ink-muted);
    cursor: pointer;
    transition:
      background-color 200ms var(--states-ease),
      color 200ms var(--states-ease);
  }

  & .case-states__tab[aria-selected="true"] {
    background: var(--p-raised);
    box-shadow: 0 0 0 var(--p-stroke) var(--p-rule-soft);
    color: var(--p-ink);
  }

  @media (hover: hover) and (pointer: fine) {
    & .case-states__tab[aria-selected="false"]:hover {
      color: var(--p-ink);
    }
  }

  & .case-states__tab:focus-visible {
    outline: 2px solid var(--p-ink);
    outline-offset: 2px;
  }

  & .case-states__panels {
    position: relative;
    display: grid;
  }

  /* Reset: a quiet text button in the stage's bottom right corner,
     shown only once the reader has used the component */
  & .case-states__reset {
    position: absolute;
    z-index: 2;
    inset-block-end: 0.6rem;
    inset-inline-end: 0.6rem;
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.3em 0.6em;
    border: 0;
    border-radius: 999px;
    background: transparent;
    font-family: var(--p-font-display);
    font-size: 0.8rem;
    color: var(--p-ink-muted);
    cursor: pointer;
    transition: color 150ms ease, background-color 150ms ease;
  }

  @media (hover: hover) and (pointer: fine) {
    & .case-states__reset:hover {
      background: #f6f6f5;
      color: var(--p-ink);
    }
  }

  & .case-states__reset[hidden] {
    display: none;
  }

  & .case-states__reset:focus-visible {
    outline: 2px solid var(--p-ink);
    outline-offset: 2px;
  }

  & .case-states__panel {
    grid-area: 1 / 1;
    display: grid;
    grid-template-rows: 1fr auto;
    opacity: 0;
    visibility: hidden;
    transition:
      opacity 200ms var(--states-ease),
      visibility 0s 200ms;
  }

  & .case-states__panel.is-active {
    opacity: 1;
    visibility: visible;
    transition:
      opacity 250ms var(--states-ease),
      visibility 0s;
  }

  /* The stage: a plain box inside the hatched gap */
  /* The stage holds the card's own height (--frame-content, reported by
     the frame); open lists don't count, they float over what follows */
  & .case-states__stage {
    position: relative;
    container-type: inline-size;
    height: calc(var(--frame-content, var(--states-frame-h)) * var(--frame-zoom) + 2px);
    margin: var(--states-gap) var(--states-gap) 0;
    border: var(--p-stroke) solid var(--states-line);
    background: var(--states-ground);
  }

  /* As on Tailwind's site, the stage's top and bottom edges run on as
     guide lines to the figure's edges (the vertical pair is drawn by the
     figure's background) */
  & .case-states__stage::before {
    content: "";
    position: absolute;
    inset: -1px calc(-1 * var(--states-gap) - 1px);
    border-block: var(--p-stroke) solid var(--states-line);
    pointer-events: none;
  }

  /* The tabs and the caption sit over the vertical lines */
  & .case-states__tabs,
  & .case-states__caption {
    position: relative;
    z-index: 1;
  }

  /* The real component (registro.html?only=license), on a transparent
     page: the pattern shows around the card */
  /* Out of flow at the stage's top: as tall as the card needs, and taller
     only while a list is open, overlapping the caption and the page below
     (above them), so lists are never cut and nothing moves */
  & .case-states__frame {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    z-index: 2;
    display: block;
    width: 100%;
    height: var(--states-frame-h);
    border: 0;
    background: transparent;
    color-scheme: light;
  }

  & .case-states__stage.is-overlaying .case-states__frame {
    z-index: 5;
  }

  & .case-states__caption {
    max-width: none;
    margin: var(--space-s) 0 0;
    padding: 0.7em var(--space-s);
    border-block-start: var(--p-stroke) solid var(--states-line);
    background: var(--p-paper); /* the caption sits off the hatch */
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    line-height: 1.45;
    color: var(--p-ink-muted);
  }

  /* A single state (no tabs): the dashed "Explored, not built" label
     takes the tabs' place, centred in the hatched band */
  & .case-states > .case-figure__label {
    position: relative;
    z-index: 1;
    display: block;
    width: fit-content;
    margin: var(--states-gap) auto 0;
    background: var(--p-paper);
  }

  /* The hero as the solution (.case-states--hero): same frame as the
     component figures (hatched gap on four sides, guide lines, caption
     bar), as wide as the hero screen, the caption centred. The stage
     takes the screenshot's own height. */
  & .case-states--hero {
    --p-hero-w: min(100rem, max(100cqi, 100vw - 2 * var(--space-l)));
    width: var(--p-hero-w);
    margin-inline-start: calc(50% - var(--p-hero-w) / 2);
    margin-block-start: var(--space-xl);
  }
  /* The stage keeps the component figures' grey ground, and the screen
     sits inside it with air around, framed by its own line */
  /* Also a screenshot in a window inside any single-state frame (Admin) */
  & :is(.case-states--hero .case-states__stage, .case-states__stage:has(> .case-hero-window)) {
    height: auto;
    container-type: normal;
    padding: clamp(var(--space-s), 3vw, var(--space-xl));
  }
  & .case-hero-window {
    border: var(--p-stroke) solid var(--states-line);
    background: var(--p-paper);
    box-shadow: 0 1px 2px rgb(43 40 38 / 0.04), 0 8px 24px rgb(43 40 38 / 0.06);
  }
  & .case-states--hero .case-states__caption {
    text-align: center;
    text-wrap: balance;
  }
  & .case-hero-window__bar {
    display: flex;
    justify-content: center;
    padding: 0.6em var(--space-xs);
    border-block-end: var(--p-stroke) solid var(--states-line);
    background:
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) var(--space-xs) 50% / 0.6em 0.6em,
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) calc(var(--space-xs) + 1em) 50% / 0.6em 0.6em,
      radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) calc(var(--space-xs) + 2em) 50% / 0.6em 0.6em,
      var(--p-paper);
    background-repeat: no-repeat;
    font-size: 0.8rem;
  }
  & .case-hero-window__bar span {
    max-width: calc(100% - 9em);
    padding: 0.35em 1.2em;
    overflow: hidden;
    border: var(--p-stroke) solid var(--p-rule-soft);
    background: var(--p-tint);
    font-family: var(--p-font-display);
    font-size: 0.72rem;
    line-height: 1;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--p-ink-muted);
  }
  & .case-hero-window img {
    display: block;
    width: 100%;
    height: auto;
  }

  /* Inside a disclosure the body is indented: centre on the section */
  & .case-details__body > .case-states {
    --p-details-indent: calc(var(--details-icon) + var(--details-gap));
    margin-inline-start: calc((100cqi - var(--p-screen-w)) / 2 - var(--p-details-indent));
  }

  /* Phones: the three tabs fit in one row, the card uses the width */
  @media (max-width: 600px) {
    & .case-states {
      --states-gap: var(--space-2xs, 0.5rem);
      --frame-zoom: 0.66;
    }
    /* A component that needs more width than a phone gives it (the
       org-chart navigator) keeps a smaller scale so nothing is cut */
    & .case-states--wide {
      --frame-zoom: 0.54;
    }

    & .case-states__tabs {
      max-width: calc(100% - 2 * var(--space-2xs, 0.5rem));
      margin-block-start: var(--space-2xs, 0.5rem);
    }

    & .case-states__tabs {
      gap: 2px;
    }

    & .case-states__tab {
      padding: 0.55em 0.7em;
      font-size: 12px;
    }

    /* The card keeps its real layout: the frame is wider than the stage,
       scaled down by --frame-zoom so it fits the phone. A transform and not
       `zoom`: browsers disagree on whether a zoomed element's width is
       zoomed too, and where it isn't the card sat off to the right. */
    & .case-states__frame {
      width: calc(100% / var(--frame-zoom));
      height: var(--states-frame-h);
      transform: scale(var(--frame-zoom));
      transform-origin: 0 0;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .case-states__tab,
    & .case-states__reset,
    & .case-states__panel,
    & .case-states__panel.is-active {
      transition: none;
    }
  }

  /* ─── 13. RESPONSIVE AND MOTION ─────────────────────────── */
  @media (max-width: 600px) {
    & .case-meta {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    & :is(.case-decision__tradeoff, .case-after__change) {
      padding: var(--space-s);
      padding-inline-start: calc(var(--callout-strip) + var(--space-s));
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .case-details > summary::after {
      transition: none;
    }
  }
}

/* ============================================================
   PROTOTYPE MODAL (.case-modal)
   Outside the .case--prosa scope: the <dialog> lives at the end of
   <body>. The dialog fills the window and stays transparent; inside it,
   the window (.case-modal__window) takes about 90% and the page shows
   dimmed around it, so the prototype feels like the real app without
   losing the case. Close sits outside the window, on the dimmed page.
   ============================================================ */
.case-modal {
  --modal-paper: #fbfaf8;
  --modal-tint: #f6f4f0;
  --modal-line: #e1dfda;
  --modal-ink: #3d3935; /* softened, never pure black */
  --modal-muted: var(--color-mid);
  --modal-radius: 4px; /* a little warmth, only in the focused view */
  --modal-ease: cubic-bezier(0.32, 0.72, 0, 1);
  --modal-ease: cubic-bezier(0.32, 0.72, 0, 1);
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  font-family: var(--font-sans);
  color: var(--modal-ink);
}

.case-modal[open] {
  display: grid;
  place-items: center;
}

.case-modal::backdrop {
  background: rgba(30, 28, 26, 0.6);
  animation: case-modal-fade 220ms var(--modal-ease);
}

/* The page under the modal does not scroll */
html:has(.case-modal[open]) {
  overflow: hidden;
}

.case-modal__window {
  display: flex;
  flex-direction: column;
  width: 90vw;
  height: 90vh;
  overflow: hidden;
  border: 1px solid var(--modal-line);
  border-radius: var(--modal-radius);
  background: var(--modal-paper);
  box-shadow: 0 24px 80px rgba(30, 28, 26, 0.35);
  animation: case-modal-in 220ms var(--modal-ease);
}

/* Bar: same browser chrome as the screens in the case */
.case-modal__bar {
  display: grid;
  grid-template-columns: 1fr minmax(0, auto) 1fr;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--modal-line);
  font-size: 0.8rem;
  line-height: 1;
  color: var(--modal-muted);
}

.case-modal__dots {
  inline-size: 2.6em;
  block-size: 0.6em;
  background:
    radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) 0 50% / 0.6em 0.6em,
    radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) 50% 50% / 0.6em 0.6em,
    radial-gradient(circle closest-side, var(--gray-400) 92%, transparent) 100% 50% / 0.6em 0.6em;
  background-repeat: no-repeat;
}

.case-modal__url {
  min-width: 0;
  padding: 0.35em 1.2em;
  overflow: hidden;
  border: 1px solid var(--modal-line);
  border-radius: var(--modal-radius);
  background: var(--modal-tint);
  font-size: 0.9em;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Close: on the dimmed page, top right, above the window. Light text on
   the dark backdrop, with its Esc shortcut. */
.case-modal__actions {
  position: fixed;
  top: calc(5vh - 2.4rem);
  right: 5vw;
  z-index: 1;
}

.case-modal__close {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.4em 0.2em;
  border: 0;
  border-radius: var(--modal-radius);
  background: none;
  font: 500 0.85rem/1 var(--font-sans);
  color: rgba(251, 250, 248, 0.85);
  cursor: pointer;
}

.case-modal__close kbd {
  padding: 0.2em 0.45em;
  border: 1px solid rgba(251, 250, 248, 0.45);
  border-radius: var(--modal-radius);
  font: inherit;
  font-size: 0.85em;
}

.case-modal__close:hover {
  color: var(--modal-paper);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.case-modal__close:focus-visible {
  color: var(--modal-paper);
  outline: 2px solid var(--modal-paper);
  outline-offset: 2px;
}

.case-modal__screen {
  flex: 1;
  width: 100%;
  min-height: 0;
  border: 0;
  background: #fff;
}

@keyframes case-modal-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
}

@keyframes case-modal-fade {
  from {
    opacity: 0;
  }
}

/* Exit: shorter and quieter than the enter. The page script adds
   .is-closing, waits for it to end, then closes the dialog. */
.case-modal.is-closing .case-modal__window {
  animation: case-modal-out 150ms var(--modal-ease) forwards;
}

.case-modal.is-closing::backdrop {
  animation: case-modal-fade-out 150ms var(--modal-ease) forwards;
}

.case-modal.is-closing .case-modal__actions {
  opacity: 0;
  transition: opacity 150ms var(--modal-ease);
}

@keyframes case-modal-out {
  to {
    opacity: 0;
    transform: translateY(6px);
  }
}

@keyframes case-modal-fade-out {
  to {
    opacity: 0;
  }
}

/* Exit: shorter and quieter than the enter. The page script adds
   .is-closing, waits for it to end, then closes the dialog. */
.case-modal.is-closing .case-modal__window {
  animation: case-modal-out 150ms var(--modal-ease) forwards;
}

.case-modal.is-closing::backdrop {
  animation: case-modal-fade-out 150ms var(--modal-ease) forwards;
}

.case-modal.is-closing .case-modal__actions {
  opacity: 0;
  transition: opacity 150ms var(--modal-ease);
}

@keyframes case-modal-out {
  to {
    opacity: 0;
    transform: translateY(6px);
  }
}

@keyframes case-modal-fade-out {
  to {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .case-modal__window,
  .case-modal::backdrop,
  .case-modal.is-closing .case-modal__window,
  .case-modal.is-closing::backdrop {
    animation: none;
  }

  .case-modal.is-closing .case-modal__actions {
    transition: none;
  }
}

/* ─── CASE MAP (.case-body + .case-toc, built by case-toc.js) ──────────
   From "The problem" on, the sections sit in .case-body. A full-width
   line opens it (the hero above is the summary). Wide screens: the list
   is a sticky column on the left and the sections take the rest.
   Narrow screens: a compact bar stuck to the top shows the current
   section and opens the list. Every section on screen is marked
   (aria-current), as in MDN's "In this article". */
.case-content .case.case--v4.case--prosa {
  --toc-w: 14rem;
  --toc-gap: clamp(2rem, 4vw, 4rem);
  --toc-bar-h: 3.25rem;

  & .case-body {
    position: relative;
    margin-block-start: var(--space-2xl-3xl);
  }

  /* The line that opens the case's body: edge to edge of the window */
  & .case-body::before {
    content: "";
    display: block;
    grid-column: 1 / -1;
    block-size: var(--p-stroke);
    /* border-image outset: one fill drawn past both edges, no layout */
    /* lighter than the frames: a quiet seam, not a heavy black rule */
    --body-line: color-mix(in srgb, var(--p-rule) 22%, var(--p-paper));
    border-image: linear-gradient(var(--body-line), var(--body-line)) fill 0 / 0 / 0 100vmax;
  }

  /* One width for every box in the case's body: callouts, notes, stats,
     timelines, tables and plain figures share the left and right edges
     of the screens and diagrams (the section's full width). Text inside
     a box keeps the reading measure; the box grows, the line doesn't. */
  & .case-body
    :is(
      .case-decision__tradeoff,
      .case-after,
      .case-after__change,
      .case-stats,
      .case-tl,
      .case-timeline,
      .case-table-wrap,
      .case-figure--dark:not(.case-figure--unbuilt, .case-figure--screen, .case-figure--diagram)
    ):not(.case-details__body > *) {
    width: 100%;
    max-width: none;
  }
  /* Inside a disclosure the body is indented: a box steps back out to
     the section's edges, like the figures there */
  & .case-body .case-details__body > :is(.case-figure--dark:not(.case-figure--unbuilt, .case-figure--screen, .case-figure--diagram), .case-table-wrap, .case-stats) {
    width: 100cqi;
    max-width: none;
    margin-inline-start: calc(-1 * var(--p-details-indent, calc(var(--details-icon) + var(--details-gap))));
  }
  & .case-body :is(.case-decision__tradeoff, .case-after__change) {
    padding-inline-end: max(
      var(--space-m),
      100% - var(--measure) - var(--callout-strip, 1rem) - var(--space-m)
    );
  }
  & .case-body .case-after > :not(.case-after__change) {
    max-width: var(--measure);
  }

  /* A list that grows from the timeline above it: one soft vertical
     line drops from the first milestone (same x as the track's start)
     along the list, which keeps its bullets, indented to its right */
  & .case-tl + .case-tl-branch {
    --branch-x: calc(var(--space-l) + 16px);
    position: relative;
    margin-block-start: 0;
    padding-block-start: var(--space-l);
    /* the bullet hangs 1em left of the text: keep a full --space-l
       between it and the line */
    padding-inline-start: calc(var(--branch-x) + var(--space-l) + 1em);
  }
  & .case-tl + .case-tl-branch > li {
    list-style: none;
    position: relative;
  }
  /* Small bullets (4px) in the line's colour: part of the branch, not
     more timeline dots */
  & .case-tl + .case-tl-branch > li::before {
    content: "";
    position: absolute;
    inset-block-start: calc(0.86em - 2px); /* the middle of the x-height */
    inset-inline-start: -1em;
    inline-size: 4px;
    block-size: 4px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--p-rule-soft), var(--p-ink) 22%); /* the line's grey, a step darker */
  }
  & .case-tl + .case-tl-branch::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: calc(var(--branch-x) - 1px);
    inline-size: 2px;
    background: var(--p-rule-soft);
  }
  @media (max-width: 899.98px) {
    & .case-tl + .case-tl-branch {
      --branch-x: calc(var(--space-l) + 48px);
    }
  }

  /* The first section no longer draws its own line */
  & .case-body__main > .case-section:first-child {
    margin-block-start: var(--space-l);
    padding-block-start: 0;
    border-block-start: 0;
  }

  /* Landing on a section from the list: its title clears the top */
  & .case-body :is(.case-section, .case-decision) {
    scroll-margin-block-start: calc(var(--toc-bar-h) + var(--space-m));
  }

  /* ── The list (shared) ── */
  & .case-toc {
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    line-height: 1.35;
    color: var(--p-ink-muted);
  }
  & .case-toc__title {
    margin: 0 0 var(--space-xs);
    font-size: var(--size-step--1);
    font-weight: 600;
    color: var(--p-ink);
  }
  & .case-toc__list,
  & .case-toc__list ol {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  & .case-toc__list {
    border-inline-start: 1px solid var(--p-rule-soft);
  }
  /* Nested decisions: indented by their text, not by the list, so the
     active mark always sits on the same left track */
  & .case-toc__list ol a {
    padding-inline-start: calc(0.75em + 0.85rem);
  }
  & .case-toc a {
    display: flex;
    gap: 0.5em;
    margin-inline-start: -1px; /* sit on the track */
    padding: 0.35em 0.75em;
    border-inline-start: 2px solid transparent;
    color: inherit;
    text-decoration: none;
  }
  & .case-toc__list ol a {
    font-size: 0.93em;
  }
  & .case-toc__num {
    flex: none;
    font-variant-numeric: tabular-nums;
    color: var(--p-ink-muted);
  }
  /* On screen: darker text and the track in ink, no ground */
  & .case-toc a[aria-current] {
    color: var(--p-ink);
    border-inline-start-color: var(--p-rule);
  }
  /* A nested decision on screen: only its text turns dark and bold; the
     section above it ("03 Decisions") keeps the mark on the track */
  & .case-toc__list ol a[aria-current] {
    border-inline-start-color: transparent;
    font-weight: 600;
  }
  @media (hover: hover) and (pointer: fine) {
    & .case-toc a:not([aria-current]):hover {
      color: var(--p-ink);
    }
  }
  & .case-toc a:focus-visible,
  & .case-toc__toggle:focus-visible {
    outline: 2px solid var(--p-ink);
    outline-offset: 2px;
  }

  /* ── Wide: a sticky column on the left ── */
  @media (min-width: 1200px) {
    & .case-body {
      --body-w: min(100vw - 2 * var(--space-l), 84rem);
      display: grid;
      grid-template-columns: var(--toc-w) minmax(0, 1fr);
      column-gap: var(--toc-gap);
      width: var(--body-w);
      margin-inline-start: calc(50% - var(--body-w) / 2);
      /* Figures center on their section and never pass into the list */
      --p-screen-w: min(var(--p-screen-max), 100cqi);
    }
    & .case-body .case-figure--dark.case-figure--diagram {
      --p-diagram-w: min(var(--p-diagram-max), 100cqi);
    }
    & .case-toc {
      position: sticky;
      inset-block-start: var(--space-l);
      align-self: start;
      max-block-size: calc(100dvh - 2 * var(--space-l));
      overflow-y: auto;
      margin-block-start: var(--space-l);
    }
    & .case-toc__toggle {
      display: none;
    }
    & .case-body :is(.case-section, .case-decision) {
      scroll-margin-block-start: var(--space-l);
    }
  }

  /* ── Narrow: a compact bar stuck to the top ── */
  @media (max-width: 1199.98px) {
    & .case-toc {
      position: sticky;
      inset-block-start: 0;
      z-index: 6;
    }
    /* The bar's ground and bottom line run edge to edge (on a pseudo, so
       the list can still drop below the bar) */
    & .case-toc::before {
      content: "";
      position: absolute;
      inset: 0;
      z-index: -1;
      background: var(--p-paper);
      box-shadow: 0 0 0 100vmax var(--p-paper);
      clip-path: inset(0 -100vmax);
    }
    & .case-toc::after {
      content: "";
      position: absolute;
      inset-inline: 0;
      inset-block-end: 0;
      z-index: -1;
      block-size: 1px;
      background: var(--p-rule-soft);
      box-shadow: 0 0 0 100vmax var(--p-rule-soft);
      clip-path: inset(0 -100vmax);
    }
    & .case-toc__title {
      display: none;
    }
    & .case-toc__toggle {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--space-s);
      inline-size: 100%;
      min-block-size: var(--toc-bar-h);
      padding: 0;
      border: 0;
      background: none;
      font: inherit;
      font-size: var(--size-step-0);
      font-weight: 600;
      color: var(--p-ink);
      text-align: start;
      cursor: pointer;
    }
    & .case-toc__current {
      display: flex;
      gap: 0.5em;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    & .case-toc__toggle svg {
      flex: none;
      transition: transform 200ms var(--modal-ease, ease);
    }
    & .case-toc.is-open .case-toc__toggle svg {
      transform: rotate(180deg);
    }
    /* The list drops down under the bar */
    & .case-toc__list {
      position: absolute;
      inset-inline: 0;
      inset-block-start: 100%;
      max-block-size: min(70dvh, 32rem);
      overflow-y: auto;
      padding: var(--space-xs) var(--space-s);
      border: 1px solid var(--p-rule-soft);
      background: var(--p-raised);
      box-shadow: 0 12px 32px rgb(43 40 38 / 0.12);
      opacity: 0;
      transform: translateY(-4px);
      visibility: hidden;
      transition:
        opacity 150ms ease-in,
        transform 150ms ease-in,
        visibility 0s linear 150ms;
    }
    & .case-toc.is-open .case-toc__list {
      opacity: 1;
      transform: none;
      visibility: visible;
      transition:
        opacity 200ms var(--modal-ease, ease),
        transform 200ms var(--modal-ease, ease);
    }
    & .case-body__main > .case-section:first-child {
      margin-block-start: var(--space-m);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    & .case-toc a,
    & .case-toc__toggle svg,
    & .case-toc__list {
      transition: none !important;
    }
  }
}

/* ─── DECISION HEAD (title · lead · the reasoning) ───────────────────
   The title already names the decision, so no "Decision:" label: a
   short lead in the sans, then the rest of the argument behind a
   compact "The reasoning" toggle. A dotted line on the left ties the
   three together. The figure and the trade-off follow. */
.case-content .case.case--v4.case--prosa {
  & .case-decision__head {
    max-width: var(--measure);
    padding-inline-start: var(--space-s);
    /* a dashed line with a wider gap than the browser's dotted border:
       3px dash, 5px gap */
    --head-dash: color-mix(in srgb, var(--p-rule-soft), var(--p-ink) 25%);
    background: linear-gradient(var(--head-dash) 0 3px, transparent 3px 8px) left top / 1px 8px repeat-y;
  }
  & .case-decision__head > h3 {
    margin-block-start: 0;
  }
  & .case-decision__lead {
    margin-block-start: var(--space-xs);
    font-family: var(--p-font-display);
    font-size: var(--size-step-0);
    font-weight: 600;
    line-height: 1.45;
    color: var(--p-ink);
  }
  & .case-reasoning {
    margin-block-start: var(--space-s);
  }
  & .case-reasoning > summary {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    list-style: none;
    cursor: pointer;
    font-family: var(--p-font-display);
    font-size: var(--size-step--1);
    letter-spacing: var(--p-tracking-label);
    text-transform: uppercase;
    color: var(--p-ink-muted);
  }
  & .case-reasoning > summary::-webkit-details-marker {
    display: none;
  }
  & .case-reasoning > summary::before {
    content: "";
    inline-size: 0.45em;
    block-size: 0.45em;
    border-inline-end: 1.5px solid currentColor;
    border-block-end: 1.5px solid currentColor;
    transform: translateY(-0.12em) rotate(45deg);
    transition: transform 200ms var(--modal-ease, ease);
  }
  & .case-reasoning[open] > summary::before {
    transform: translateY(0.12em) rotate(-135deg);
  }
  @media (hover: hover) and (pointer: fine) {
    & .case-reasoning > summary:hover {
      color: var(--p-ink);
    }
  }
  & .case-reasoning > summary:focus-visible {
    outline: 2px solid var(--p-ink);
    outline-offset: 3px;
  }
  & .case-reasoning > p {
    margin-block-start: var(--space-xs);
    font-family: var(--p-font-text);
    font-size: var(--p-text);
    line-height: var(--p-leading);
    color: var(--p-ink);
  }
  @media (prefers-reduced-motion: reduce) {
    & .case-reasoning > summary::before {
      transition: none;
    }
  }
}


/* ============================================================
   GATE — a case readable up to a point, the rest behind a password.
   Turn it on with .case--gated on the .case and a .case-gate block
   where the reading should stop. Same voice as the drawer's
   "coming soon" state: small uppercase status, Geist 800 title,
   serif line, quiet outlined link.
   ============================================================ */

/* Everything after the gate disappears: the rest of its section and
   every section after it */
.case--gated .case-gate ~ *,
.case--gated :is(.case-section, .case-header, .case-brief):has(.case-gate) ~ * {
  display: none !important;
}

/* The map still shows what the case covers, but only the open
   section can be followed */
.case-toc a.is-locked {
  pointer-events: none;
  opacity: 0.3;
}

.case-content .case.case--prosa .case-gate,
.case.case--prosa .case-gate {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* the block sits centered; its lines start together on the left */
  gap: 0;
  inline-size: min(100%, 34rem);
  max-width: var(--measure);
  margin-inline: 0; /* on the text's left edge, with THE PAIN */
  /* Integrated: no box. The form floats over the last, faded lines of
     the opening paragraph, as a layer laid on top of the content. */
  margin-block: 0 var(--space-2xl);
  padding: 0;
  background: none;
  text-align: start;
}

/* Pulled up over the faded tail of the paragraph (beats the section's
   flow spacing, which sets the gap between blocks) */
.case-content .case.case--v4.case--prosa :is(.case-section, .case-brief) > .case-gate,
.case.case--v4.case--prosa :is(.case-section, .case-brief) > .case-gate {
  margin-block-start: -0.15em;
}

/* Medium-style: the summary's title and its first row (The pain) read
   in full; the fade starts right after that row, and the gate sits
   on the faded end, as a layer over the content. */
.case--gated > .case-brief:has(+ .case-gate) {
  user-select: none;
}

/* Rows are measured by content, not height, so it holds at any width:
   The pain reads whole, What I did fades out over its first lines,
   the rest of the summary isn't shown */
.case--gated > .case-brief:has(+ .case-gate) .case-brief__row:nth-child(2) {
  max-block-size: 4.2em;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.45) 0%, rgb(0 0 0 / 0.15) 45%, transparent 90%);
  mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.45) 0%, rgb(0 0 0 / 0.15) 45%, transparent 90%);
}

.case--gated > .case-brief:has(+ .case-gate) .case-brief__row:nth-child(n + 3) {
  display: none;
}

/* No closing line under the summary: it dissolves, it doesn't end */
.case-content .case.case--v4.case--prosa.case--gated > .case-brief:has(+ .case-gate) .case-brief__list,
.case.case--v4.case--prosa.case--gated > .case-brief:has(+ .case-gate) .case-brief__list {
  border-block-end: 0;
}

/* Less air between the metadata and the faded summary, so the gate
   lands inside the first view of the drawer */
.case-content .case.case--v4.case--prosa.case--gated > .case-brief,
.case.case--v4.case--prosa.case--gated > .case-brief {
  margin-block-start: var(--space-l);
}

.case-content .case.case--v4.case--prosa > .case-gate,
.case.case--v4.case--prosa > .case-gate {
  margin-block-start: 0.75em;
}

/* A locked case ends at the gate: no "That's … / Close case" footer
   in the drawer (the top bar still closes it) */
.drawer:has(.case--gated) .drawer-footer {
  display: none;
}

/* The fade: the opening paragraph dissolves line by line, so "The
   problem" stays the most legible thing and the rest reads as more */
.case--gated :is(.case-section, .case-brief) > :has(+ .case-gate) {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgb(0 0 0 / 0.85) 18%, rgb(0 0 0 / 0.3) 45%, rgb(0 0 0 / 0.06) 70%, transparent 88%);
  mask-image: linear-gradient(to bottom, #000 0%, rgb(0 0 0 / 0.85) 18%, rgb(0 0 0 / 0.3) 45%, rgb(0 0 0 / 0.06) 70%, transparent 88%);
}

/* The heading stays for screen readers; on screen the placeholder says it */
.case-content .case.case--v4.case--prosa .case-gate .case-gate__title,
.case--prosa .case-gate .case-gate__title {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.case--prosa .case-gate .case-gate__status {
  display: block;
  margin: 0 0 10px;
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-mid);
}

.case-gate__form {
  display: flex;
  justify-content: flex-start;
  gap: 6px;
  inline-size: 100%;
  margin: 0;
}

.case-gate__input {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 44px;
  padding: 0 14px;
  border: 1px solid #d9d4cc;
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 1px 2px rgb(43 40 38 / 0.06);
  font: 500 15px/1 var(--font-sans);
  color: #3d3935;
}

.case-gate__input::placeholder {
  color: #8a847e;
}

.case-gate__input:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.case-gate__btn {
  flex: none;
  min-block-size: 44px;
  padding: 0 20px;
  border: 0;
  border-radius: 8px;
  background: var(--color-accent); /* dark green */
  color: #fbfaf8;
  font: 600 15px/1 var(--font-sans);
  cursor: pointer;
  transition:
    background 0.15s,
    transform 0.15s cubic-bezier(0.23, 1, 0.32, 1);
}

@media (hover: hover) and (pointer: fine) {
  .case-gate__btn:hover {
    background: #234c39;
  }
}

.case-gate__btn:active {
  transform: scale(0.97);
}

.case-gate__btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.case--prosa .case-gate :is(.case-gate__note, .case-gate__ask) {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  color: var(--color-mid);
}

.case--prosa .case-gate .case-gate__ask {
  margin-block-start: 10px;
}

.case--prosa .case-gate .case-gate__note {
  margin-block-start: 10px;
}

.case--prosa .case-gate .case-gate__ask a {
  font-weight: 600;
  color: #3d3935;
  text-decoration: underline;
  text-decoration-color: var(--color-primary);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.2ex;
}

@media (hover: hover) and (pointer: fine) {
  .case--prosa .case-gate .case-gate__ask a:hover {
    color: var(--color-primary);
  }
}

@media (max-width: 480px) {
  .case-gate__input {
    flex-basis: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .case-gate__btn {
    transition: none;
  }
}


/* ============================================================
   GATE, SHEET VERSION (trial) — like a news paywall: a white sheet
   slides over the case from below, its top edge cutting across
   "What I did", with a soft shadow. Content centered in a narrow
   column. Remove .case-gate--sheet in the HTML to go back.
   ============================================================ */
.case-content .case.case--v4.case--prosa > .case-gate.case-gate--sheet,
.case.case--v4.case--prosa > .case-gate.case-gate--sheet {
  position: relative;
  z-index: 2;
  display: flex; /* the form sits in the middle of the locked area */
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  inline-size: auto;
  max-width: none;
  margin: 0;
  padding: var(--space-xl) 0;
  min-block-size: 45vh;
  text-align: start;
}

/* The sheet itself: full width of the page, white, shadow on top */
.case-gate--sheet::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline: calc(50% - 50vw);
  z-index: -1;
  background: #fbfaf8; /* the page's own paper: no slab, like Medium */
}

/* The row under the sheet fades out as it goes under (no blur) */
.case--gated > .case-brief:has(+ .case-gate--sheet) .case-brief__row:nth-child(2) {
  max-block-size: 5.6em; /* about three lines show through */
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.85) 0%, rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0.2) 80%, transparent 100%);
  mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.85) 0%, rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0.2) 80%, transparent 100%);
}

/* And a gradient rises from the sheet into the page, so the content
   reads as continuing underneath instead of being cut by a line */
.case-gate--sheet::after {
  content: "";
  position: absolute;
  inset-block-end: 100%;
  inset-inline: calc(50% - 50vw);
  z-index: -1;
  block-size: 4.5em; /* stops before The pain, which reads in full */
  background: linear-gradient(to bottom, rgb(251 250 248 / 0), rgb(251 250 248 / 0.5) 60%, rgb(251 250 248 / 0.9));
  pointer-events: none;
}

.case-gate--sheet .case-gate__inner {
  inline-size: min(100%, 34rem);
  margin: 0; /* on the text's left edge, with In a few words and THE PAIN */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: start;
}

.case-content .case.case--v4.case--prosa .case-gate--sheet .case-gate__headline,
.case--prosa .case-gate--sheet .case-gate__headline {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--size-step-1);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: #3d3935;
  text-wrap: balance;
}

.case-gate--sheet .case-gate__headline strong {
  font-weight: 700;
}

/* Label stays for screen readers; the placeholder names the field */
.case-gate--sheet .case-gate__label {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Input and button side by side, compact */
.case-gate--sheet .case-gate__form {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  inline-size: 100%;
  align-items: stretch;
  gap: 6px;
  margin-block-start: var(--space-s);
}

.case-gate--sheet .case-gate__input {
  flex: 0 1 340px; /* 340px wide, narrower on a phone so Unlock stays beside it */
  inline-size: auto;
  min-inline-size: 0;
  min-block-size: 46px;
  border-radius: 6px;
  border-color: #b9b4ac;
}

.case-gate--sheet .case-gate__btn {
  flex: none;
  inline-size: auto;
  min-block-size: 46px;
  margin: 0;
  padding: 0 22px;
  border-radius: 6px;
}

.case--prosa .case-gate--sheet :is(.case-gate__note, .case-gate__ask) {
  margin-block-start: 12px;
  font-size: var(--size-step-0);
  text-align: start;
}

/* Gate on a phone: stacked, full-width controls, link on its own line */
@media (max-width: 767px) {
  .case-content .case.case--v4.case--prosa > .case-gate.case-gate--sheet,
  .case.case--v4.case--prosa > .case-gate.case-gate--sheet {
    padding-block: var(--space-2xl) var(--space-xl);
    min-block-size: 0;
  }

  .case-gate--sheet .case-gate__inner {
    inline-size: 100%;
  }

  .case-content .case.case--v4.case--prosa .case-gate--sheet .case-gate__headline,
  .case--prosa .case-gate--sheet .case-gate__headline {
    font-size: 1.125rem;
  }

  .case-gate--sheet .case-gate__form {
    flex-direction: column;
    gap: 10px;
  }

  .case-gate--sheet .case-gate__input,
  .case-gate--sheet .case-gate__btn {
    flex: none;
    inline-size: 100%;
    min-block-size: 48px;
  }

  .case--prosa .case-gate--sheet .case-gate__ask {
    margin-block-start: var(--space-s);
    font-size: 1rem;
  }

  .case--prosa .case-gate--sheet .case-gate__ask a {
    display: block; /* its own line */
    inline-size: fit-content;
    margin-block-start: 2px;
    padding-block: 8px; /* a bigger target for the thumb */
  }
}

/* Two paragraphs in a closing callout read as two thoughts */
.case--prosa .case-after__change p + p {
  margin-block-start: 0.75em;
}

/* Question titles: the "?" stays attached, as English writes it, with
   a hair of room and a touch more weight so it doesn't read as a letter */
.case--prosa .case-details__q {
  margin-inline-start: 0.06em;
  font-weight: 700;
}

/* ─── FollowCare screens (Chronic Care only) ───────────────
   Here and not in the case file: the portfolio drawer injects only
   .case, so a <style> in the case head never reaches it. Phones: real app captures
   at 390 × 844, side by side in the stage; below 600px they scroll
   sideways one by one. Hero: the patient phone over the corner of
   the clinician window. */
.case-content .case.case--v4.case--prosa .case-states__stage:has(.case-phones) {
  height: auto;
  container-type: normal;
}
.case-content .case.case--v4.case--prosa .case-phones {
  display: flex;
  justify-content: center;
  gap: clamp(0.75rem, 3vw, 2.5rem);
  padding: clamp(1rem, 3vw, 2rem) 0;
}
.case-content .case.case--v4.case--prosa .case-phones img,
.case-content .case.case--v4.case--prosa .case-hero-pair__phone {
  display: block;
  height: auto;
  border: 1px solid var(--states-line, #e1dfda);
  border-radius: 1.75rem;
  background: #fff;
  box-shadow: 0 1px 2px rgb(43 40 38 / 0.04), 0 8px 24px rgb(43 40 38 / 0.08);
}
.case-content .case.case--v4.case--prosa .case-phones img {
  width: min(30%, 18rem);
}
.case-content .case.case--v4.case--prosa .case-hero-pair {
  position: relative;
  padding: 0 14% 6% 0;
}
.case-content .case.case--v4.case--prosa .case-hero-pair__phone {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 22%;
}
@media (max-width: 600px) {
  .case-content .case.case--v4.case--prosa .case-phones {
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-inline: 1rem;
    scroll-padding-inline: 1rem;
  }
  .case-content .case.case--v4.case--prosa .case-phones img {
    flex: none;
    width: 70%;
    scroll-snap-align: start;
  }
  .case-content .case.case--v4.case--prosa .case-hero-pair__phone {
    width: 30%;
    border-radius: 0.9rem;
  }
}

/* ─── Admin diagrams (Admin Console only) ─────────────────
   Inline SVG drawn in the diagrams.css look (JetBrains Mono, hairline
   cards, solid offset shadow). Scales with the frame, text included. */
.case-content .case.case--v4.case--prosa .dga {
  display: block;
  width: 100%;
  height: auto;
}

/* ─── Browser bars on phones ──────────────────────────────
   On a phone the screenshot shrinks to a third of its size but the bar
   kept desktop text, so the address read bigger than the screen it
   belongs to. Below 600px the bar, its dots and the address pill scale
   down with the screenshot. Applies to the hero window and to every
   .case-figure--screen. */
@media (max-width: 600px) {
  .case-content .case.case--v4.case--prosa .case-hero-window__bar,
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--screen::before,
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--hero::before {
    font-size: 0.5rem;
  }
  .case-content .case.case--v4.case--prosa .case-hero-window__bar span,
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--screen::after,
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--hero::after {
    font-size: 0.5rem;
    padding: 0.3em 0.9em;
  }
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--screen::after,
  .case-content .case.case--v4.case--prosa .case-figure--dark.case-figure--hero::after {
    margin-block: 0.5em;
  }
}

/* ─── Phone rails on phones ───────────────────────────────
   Below 600px .case-phones scrolls sideways one screen at a time.
   The side that still has screens fades out, and a control under the
   rail (built by case-toc.js) moves between them and says where you
   are. On wider screens all phones show and the control is hidden. */
.case-content .case.case--v4.case--prosa .case-rail-nav {
  display: none;
}
@media (max-width: 600px) {
  .case-content .case.case--v4.case--prosa .case-phones {
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 3rem), transparent);
    mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 3rem), transparent);
  }
  .case-content .case.case--v4.case--prosa .case-phones::-webkit-scrollbar { display: none; }
  .case-content .case.case--v4.case--prosa .case-phones.is-start {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 3rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 3rem), transparent);
  }
  .case-content .case.case--v4.case--prosa .case-phones.is-end {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem);
    mask-image: linear-gradient(to right, transparent, #000 1.5rem);
  }
  .case-content .case.case--v4.case--prosa .case-rail-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding-block: 0.25rem 1rem;
    font-family: var(--p-font-display);
    font-size: 0.85rem;
    color: var(--p-ink-muted);
    font-variant-numeric: tabular-nums;
  }
  .case-content .case.case--v4.case--prosa .case-rail-nav b {
    font-weight: 500;
    color: var(--p-ink);
  }
  .case-content .case.case--v4.case--prosa .case-rail-nav__btn {
    position: relative;
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: var(--p-stroke) solid var(--p-rule-soft);
    border-radius: 50%;
    background: var(--p-paper);
    color: var(--p-ink);
    cursor: pointer;
    transition: transform 100ms ease-out, opacity 120ms ease-out;
  }
  /* 44px to the finger without growing on screen */
  .case-content .case.case--v4.case--prosa .case-rail-nav__btn::before {
    content: "";
    position: absolute;
    inset: -0.25rem;
  }
  .case-content .case.case--v4.case--prosa .case-rail-nav__btn:active { transform: scale(0.96); }
  .case-content .case.case--v4.case--prosa .case-rail-nav__btn:disabled {
    opacity: 0.35;
    cursor: default;
  }
}
