/* =========================================================================
   ELSE website: MAGAZINE CASE-STUDY TEMPLATE
   4 Nov 2026. Owner: Andry. Spec: magazine-template-spec-2026-11-04.md (the
   source of truth; dated decisions). Behaviour: else-magazine.js.
   Loaded only on magazine pages (Base.astro, template="magazine"), after
   else-colour.css, else-typography.css and else-spacing.css, whose tokens it
   uses. Every rule is scoped to html.magazine-ground, so it can never touch
   a standard page.

   MARKUP (src/components/magazine/MagazineCaseStudy.astro): the standard
   case study, in its reading order, with the magazine's layers inside the
   body. Rendered on the server; nothing is moved by script.
     <html class="magazine-ground" data-cover-theme="dark|light">
     <body data-template="magazine" data-surface="image-dark|image-light">
     <article class="article-page magazine">
       <header class="article-head wrap mag-band">            title band
         <div class="mag-band-bg" aria-hidden="true"><img alt=""></div>
         eyebrow row, h1, footnote (award · tags)
       </header>
       <div class="hero-img wrap"><img></div>                  cover photo
       <div class="prose wrap">
         <div class="mag-part mag-intro">                       intro
           <div class="mag-bg" aria-hidden="true"><img alt=""></div>
           <div class="mag-panel"><div class="mag-box"><div class="mag-flow mag-text">
             <p class="intro">…</p></div></div></div></div>
         <div class="mag-part mag-video"><div class="mag-flow"><div class="embed embed--poster"><img><button>   video:
           poster and Play (Embed.astro, click to load); Play swaps in <div class="embed"><iframe>…
         <div class="mag-part mag-section mag-section--image">   a section with its image
           <div class="mag-panel">…<div class="mag-text"> h2, body </div>…</div>
           <div class="mag-flow mag-media"><figure class="figure"><img alt="…"></figure></div></div>
         <div class="mag-part mag-section mag-section--cover">   sections without an image (one block, on the cover)
           <div class="mag-bg" aria-hidden="true">…</div><div class="mag-panel">…</div></div>
         <div class="mag-part mag-results">                     Results
           <div class="mag-bg" aria-hidden="true">…</div><div class="mag-panel">… h2, Stats …</div></div>
       </div>
     </article>
     <section class="section wrap" aria-labelledby="related-title">  Related work
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. TOKENS (proposed in the spec; for the Design System)
   ------------------------------------------------------------------------- */
html.magazine-ground {
  /* fixed copies of the base colours, for places that swap --color-ink etc. */
  --color-ink-base:        var(--color-ink);
  --color-surface-base:    var(--color-surface);
  /* the section panels' backdrop on a photo: ink 80% (+ the 16px blur). 80% is
     where the light grey on-image text reaches 4.5:1 over pure white. */
  --scrim-on-image:        color-mix(in srgb, var(--color-ink) 80%, transparent);
  --scrim-light:           color-mix(in srgb, var(--color-surface) 80%, transparent);   /* light covers */
  --scrim-blur:            var(--space-4);    /* 16px */
  --scrim-scale:           1.04;              /* blurred photo copies, scaled so the soft edges stay off screen */
  --color-copy-on-image:   color-mix(in srgb, var(--color-copy) 45%, var(--color-paper));   /* #b6b6be */
  --guide-line-on-image:   0.5px solid color-mix(in srgb, var(--color-copy-on-image) 50%, transparent);
  /* the reading section: 6 grid columns of text (~78 characters) + 96px each side = 784px */
  --rw-pad:                calc(var(--guide-outset) + var(--layout-gutter));   /* 96px */
  --rw-measure:            calc(6 * var(--grid-col) + 5 * var(--grid-gap));   /* 592px */
  --rw-copy-w:             calc(var(--rw-measure) + 2 * var(--rw-pad));        /* 784px */
  --mag-title-w:           calc(min(var(--layout-max), var(--page-w)) - 2 * var(--layout-gutter));   /* the page title's width */
  /* scroll lengths, in screens (else-magazine.js adds any long-text overflow) */
  --scene-hold:            100vh;
  --scene-intro:           200vh;   /* the sweep + its reveal screen */
  --scene-video:           200vh;
  --scene-section:         250vh;   /* the sweep + 1.5 screens of phases */
  --scene-block:           160vh;   /* each further block in a section */
  /* standard scroll transitions */
  --type-soft:             8;       /* letters across which Type in fades */
  --type-blur:             var(--space-1);   /* 4px: the soft blur text comes in from */
  --line-soft:             1.5;     /* lines across which Line in fades */
  --recede-perspective:    1200px;
  --recede-depth:          1200px;  /* half size at 1200/1200 */
  --recede-blur:           var(--space-4);   /* 16px at full depth */
  --recede-horizon:        0.3333;  /* the vanishing point: a third of the way down */
  --section-exit-at:       0.5;     /* a section's exit starts when the next one's edge is half way up */
  --view-start:            0.92;    /* in-view reveals start just above the bottom of the screen */
  --view-type:             0.25;    /* titles type in over a quarter of a screen */
  --view-line:             0.12;    /* lines over 0.12 of a screen */
  --video-letterbox:       var(--color-ink);

  /* DARK DOT-FIELD GROUND (3 Nov): ink, with the dot field mirrored (light at
     25% over ink, as the light ground has ink at 25% over paper). The dot
     field re-reads these every 250ms, so else-dot-field.js needs no change. */
  --ground-dot:            color-mix(in srgb, var(--color-surface) 25%, var(--color-ink));
  --pattern-dot:           var(--ground-dot);
  --color-guide:           var(--ground-dot);
  --dot-graph-hub-fill:    var(--ground-dot);
  background: var(--color-ink);
}
/* text roles on the dark ground: the image-dark surface (else-colour.css SURFACES) is set on <body> */
html.magazine-ground body { background: transparent; }
html.magazine-ground #dot-labels .dot-node { background: var(--color-ink-base); color: var(--color-copy-on-image); border-color: currentColor; }
/* underline gaps (skip ink) are cut in the colour behind the link: ink */
html.magazine-ground body { --skip-ink-colour: var(--color-ink-base); }
/* the phone menu panel is light: while it is open, the header over it (logo, close icon) takes the light roles too */
html.magazine-ground.nav-open .site-header {
  --text-emphasis: var(--color-ink-base); --text-subtle: var(--color-copy); --text-default: color-mix(in srgb, var(--text-subtle) 50%, var(--text-emphasis));
  --button-fill: var(--color-ink-base); --button-label: var(--color-paper); --logo-fill: var(--brand-dark-blue);
}
/* quotes: the bar in the emphasis colour, as the text */
html.magazine-ground .magazine .pullquote { border-left-color: var(--text-emphasis); }
/* quotes in the body (all widths): else-typography.css QUOTES is written for .prose > blockquote; the same rules for
   a quote one layer down (.mag-flow), so the attribution keeps its sentence case and size */
html.magazine-ground .prose .mag-flow > blockquote p { color: var(--text-emphasis); font-size: var(--step-1); font-style: italic; }
html.magazine-ground .prose .mag-flow > blockquote cite {
  font-family: var(--font-text); font-size: var(--size-small); font-weight: var(--weight-text); font-style: normal;
  letter-spacing: var(--tracking-text-small); --line-height-role: var(--line-height-text); text-transform: none; color: var(--text-subtle);
}
/* tinted boxes keep the paper roles, as tags keep ink */
html.magazine-ground .callout { --text-emphasis: var(--color-ink-base); --text-subtle: var(--color-copy); --text-default: color-mix(in srgb, var(--text-subtle) 50%, var(--text-emphasis)); }
/* the menu panel (phones) stays light until a dark mode is defined */
html.magazine-ground .nav-panel { --text-emphasis: var(--color-ink-base); --text-subtle: var(--color-copy); --text-default: color-mix(in srgb, var(--text-subtle) 50%, var(--text-emphasis)); --skip-ink-colour: var(--color-surface-base); --button-fill: var(--color-ink-base); --button-label: var(--color-paper); }

/* -------------------------------------------------------------------------
   2. PHONES (< 640px): NOT the magazine (3 Nov). The standard case study in
   the dark theme: the same components, type, spacing and order. The magazine
   layers are display: contents (their content lays out as the body's own
   children) and the decorative copies are hidden. The standard body rules
   are written for direct children of .prose (else-spacing.css, ARTICLE BODY
   RHYTHM; else-typography.css, INTRO and QUOTES), so they are mirrored here
   for the same elements one layer down (.mag-flow), with the same tokens.
   Block margins collapse across display: contents, as they do in .prose.
   ------------------------------------------------------------------------- */
@media (width < 640px) {
  html.magazine-ground .page-panel { background: var(--color-ink-base); }   /* the ink panel: the dot field's labels must not run through the text */
  html.magazine-ground .magazine :is(.mag-part, .mag-panel, .mag-box, .mag-flow) { display: contents; }
  html.magazine-ground .magazine :is(.mag-bg, .mag-band-bg) { display: none; }

  /* else-spacing.css, article body rhythm, for .mag-flow children */
  html.magazine-ground .prose .mag-flow > h2 { margin-top: var(--space-body-major); }
  html.magazine-ground .prose .mag-flow > h3 { margin-top: var(--space-body-minor); }
  html.magazine-ground .prose .mag-flow > .intro { margin-bottom: var(--space-intro); }
  html.magazine-ground .prose .mag-flow > :is(p, ul, ol) { margin-block: var(--space-paragraph); }
  html.magazine-ground .prose .mag-flow > :is(figure, .figure, img, p:has(> img:only-child)) { margin-block: var(--space-inline-media); }
  /* the first element of the body; the element after the intro or an image: no top margin */
  html.magazine-ground .prose > .mag-part:first-child .mag-flow > :first-child,
  html.magazine-ground .prose .mag-part:is(:has(.intro), :has(> .mag-media)) + .mag-part :is(.mag-text, .mag-video > .mag-flow) > :first-child { margin-top: 0; }
  html.magazine-ground .prose .mag-flow > .intro + * { margin-top: 0; }
  /* else-typography.css, intro paragraph (and its phone rule) */
  html.magazine-ground main .prose .mag-flow > .intro {
    font-family: var(--font-display);
    font-size: var(--contrast-medium);
    font-weight: var(--weight-heading);
    letter-spacing: var(--tracking-heading);
    --line-height-role: var(--line-height-heading);
    color: var(--text-emphasis);
    -webkit-hyphens: manual;
            hyphens: manual;
    text-wrap: balance;
  }
  /* the video loads only when asked (no autoplay on phones) */
  /* LIGHT COVERS on phones: the page is the standard dark layout whatever the cover, so the light cover's surface
     (image-light, rendered on <body> and the header for 640px up) takes the image-dark roles here. Same values as
     else-colour.css SURFACES, image-dark. The open menu keeps its own light roles (above). */
  html.magazine-ground[data-cover-theme="light"] body,
  html.magazine-ground[data-cover-theme="light"]:not(.nav-open) .site-header {
    --text-emphasis: var(--color-surface-base);
    --text-subtle:   var(--color-copy-on-image);
    --text-default:  color-mix(in srgb, var(--text-subtle) 50%, var(--text-emphasis));
    --button-fill:   var(--color-surface-base);
    --button-label:  var(--color-ink-base);
    --logo-fill:     var(--color-surface-base);
    color: var(--text-default);
  }
}

/* -------------------------------------------------------------------------
   3. FROM 640px: THE MAGAZINE
   Full-bleed layers use --page-w (the page's real width, else-spacing.css), not 100vw, which includes the space
   kept for the scrollbar and would push them past the right edge.
   ------------------------------------------------------------------------- */
@media (width >= 640px) {
  /* no fixed-width content panel: full width, transparent, on the dark ground */
  html.magazine-ground .page-panel { width: 100%; max-width: none; margin: 0; border: 0; background: transparent; overflow: visible; }
  html.magazine-ground :is(main > article > *, main > :not(article), .site-header, .site-footer)::before,
  html.magazine-ground :is(.site-header, .site-footer)::after { content: none; }

  /* HEADER: on the cover photo; it stays put with the photo while the intro sweeps over it (fixed, under everything
     after the cover). */
  html.magazine-ground .page-panel > .site-header { position: fixed; inset: 0 0 auto; z-index: 2; margin-inline: auto; background: none; }
  /* HEADER BAR (Andry, 4 Nov): the header sits on a full-bleed bar matching the title band (the panel ink, 80%, over
     the photo blurred 16px), so its links keep their contrast over any cover. The header is fixed over the fixed
     photo and touches no other band, so a backdrop blur gives the same result here without a seam. */
  html.magazine-ground .page-panel > .site-header::before {
    content: ""; position: absolute; inset: 0 auto 0 50%; width: var(--page-w); transform: translateX(-50%); z-index: -1;
    border: 0; margin: 0; background: var(--scrim-on-image);
    -webkit-backdrop-filter: blur(var(--scrim-blur)); backdrop-filter: blur(var(--scrim-blur)); pointer-events: none;
  }
  /* the title band pushes the header out (Andry, 4 Nov): once the band's top edge reaches the header bar's bottom edge,
     the header rises with it, edge to edge, and is gone when the band reaches the top of the screen. A scroll-driven
     animation on the band's own view timeline, so it stays locked at any scroll speed; else-magazine.js does the same
     in browsers without scroll timelines. */
  @supports (animation-timeline: view()) {
    html.magazine-ground .page-panel { timeline-scope: --mag-band; }
    html.magazine-ground .magazine > .mag-band > .mag-band-bg { view-timeline: --mag-band block; }
    html.magazine-ground .page-panel > .site-header {
      animation: mag-header-out linear both;
      animation-timeline: --mag-band;
      animation-range: exit calc(-1 * var(--header-height)) exit 0%;
    }
  }
  @keyframes mag-header-out { from { transform: translateY(0); } to { transform: translateY(-100%); } }
  html.magazine-ground main { position: relative; }
  html.magazine-ground main > .magazine { margin: 0; padding: 0; }

  /* COVER: the photo is fixed full screen behind the cover */
  html.magazine-ground .magazine > .hero-img {
    position: fixed; inset: 0; z-index: 0;
    width: 100%; max-width: none; height: 100vh; margin: 0; padding: 0;
  }
  /* margin 0: the standard hero's guide-outset bleed (negative margins, else-spacing.css) would shift it left on
     windows wider than the layout */
  html.magazine-ground .magazine > .hero-img img { width: 100%; height: 100%; max-width: none; margin: 0; object-fit: cover; outline: 0; }

  /* TITLE BAND (3 Nov): eyebrow, page title, award on a full-bleed band with
     the section panels' backdrop, 64px above the eyebrow and below the award.
     In the page flow at the bottom of the first screen, so native scrolling
     keeps it locked to the incoming intro at any speed. */
  html.magazine-ground .magazine > .mag-band {
    position: relative; z-index: 1;
    display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 1fr auto auto auto;
    gap: 0; min-height: 100vh; box-sizing: border-box; padding-block: 0;
  }
  html.magazine-ground .magazine > .mag-band > * { grid-column: 1; position: relative; z-index: 1; margin: 0; }
  html.magazine-ground .magazine > .mag-band > .eyebrow-row { grid-row: 2; padding-block: var(--space-section) var(--space-hero-eyebrow); }
  html.magazine-ground .magazine > .mag-band > h1 { grid-row: 3; }
  html.magazine-ground .magazine > .mag-band > h1:last-child { padding-bottom: var(--space-section); }
  html.magazine-ground .magazine > .mag-band > .meta { grid-row: 4; margin-top: var(--space-hero-footnote); padding-bottom: var(--space-section); }
  /* no seam at the join (3 Nov): the band blurs the PHOTO itself (once, fixed, clipped to the band) under the panel
     ink, as the intro's background does, instead of a backdrop blur that runs out of pixels at its own edge */
  html.magazine-ground .magazine > .mag-band > .mag-band-bg {
    grid-row: 2 / 5; z-index: 0; align-self: stretch;
    width: var(--page-w); margin-left: calc(50% - var(--page-w) / 2); clip-path: inset(0); pointer-events: none;
  }
  html.magazine-ground .mag-band-bg > img,
  html.magazine-ground .magazine .mag-bg > img {
    position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; outline: 0;
  }
  html.magazine-ground .mag-band-bg > img,
  html.magazine-ground .magazine :is(.mag-intro, .mag-results, .mag-end) > .mag-bg > img { filter: blur(var(--scrim-blur)); transform: scale(var(--scrim-scale)); }
  html.magazine-ground .mag-band-bg::after,
  html.magazine-ground .magazine :is(.mag-intro, .mag-results, .mag-end) > .mag-bg::after { content: ""; position: fixed; inset: 0; background: var(--scrim-on-image); }
  html.magazine-ground .mag-band-bg::after { position: absolute; }

  /* THE BODY: one scene per part, each clipping its own fixed layers, so the next part's edge rises over the last */
  html.magazine-ground .magazine > .prose { position: relative; z-index: 3; width: 100%; max-width: none; margin: 0; padding: 0; }
  html.magazine-ground .magazine .mag-part { position: relative; clip-path: inset(0); isolation: isolate; margin: 0; }
  html.magazine-ground .magazine .mag-bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
  html.magazine-ground .magazine .mag-panel { position: fixed; inset: 0; z-index: 1; display: flex; align-items: center; box-sizing: border-box; }
  html.magazine-ground .magazine .mag-box { box-sizing: border-box; }
  html.magazine-ground .magazine .mag-text > :first-child { margin-top: 0; }
  html.magazine-ground .magazine .mag-text > :last-child { margin-bottom: 0; }
  /* magazine title style (3 Nov): section titles and the intro are the only title on their screen: --step-4, Bitter
     600 (as the page title), 24px to the body */
  html.magazine-ground .magazine .mag-text > :is(h2, .intro) {
    font-family: var(--font-display); font-size: var(--step-4); font-weight: var(--weight-display);
    letter-spacing: var(--tracking-display); --line-height-role: var(--line-height-display);
    color: var(--text-emphasis); text-wrap: balance; margin: 0;
  }
  html.magazine-ground .magazine .mag-text > h2 + * { margin-top: var(--space-page-title); }
  html.magazine-ground .magazine .mag-text > :is(p, ul, ol) { margin-block: var(--space-paragraph); }
  html.magazine-ground .magazine .mag-text > h2:not(:first-child) { margin-top: var(--space-body-major); }
  html.magazine-ground .magazine .mag-text > .pullquote { margin-block: var(--space-body-minor); }

  /* INTRO: its own slide on the cover photo (blurred, under the panel ink); the copy at the page title's width,
     centred on the screen. Type in, then Recede. */
  html.magazine-ground .magazine .mag-intro { height: var(--scene-intro); }
  html.magazine-ground .magazine .mag-intro .mag-box { width: var(--mag-title-w); margin-inline: auto; padding-block: var(--space-section); }

  /* VIDEO: full screen, letterboxed on ink, never cropped (the video's own text and the player controls stay whole) */
  html.magazine-ground .magazine .mag-video { height: var(--scene-video); }
  html.magazine-ground .magazine .mag-video .embed { position: fixed; inset: 0; z-index: 0; margin: 0; aspect-ratio: auto; background: var(--video-letterbox); }
  html.magazine-ground .magazine .mag-video .embed iframe {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: min(100vw, calc(100vh * 16 / 9)); height: min(100vh, calc(100vw * 9 / 16)); max-width: none;
  }
  /* Backdrop (else-magazine.js): the muted background loop over the poster, under the Play button, letterboxed like
     the player; it takes no pointer events. The pause button sits bottom right, above it. Design pending Andry. */
  html.magazine-ground .magazine .mag-video .embed-backdrop { position: absolute; inset: 0; pointer-events: none; }
  /* While the loop runs, "Watch with sound" and the pause button sit together bottom right, off the video's content. */
  html.magazine-ground .magazine .mag-video .embed-controls {
    position: absolute; display: flex; gap: var(--space-4);
    /* inside the letterboxed frame's bottom-right corner (the frame is sized like the player, above) */
    right: calc((100vw - min(100vw, 100vh * 16 / 9)) / 2 + var(--layout-gutter));
    bottom: calc((100vh - min(100vh, 100vw * 9 / 16)) / 2 + var(--space-8));
  }
  html.magazine-ground .magazine .mag-video .embed-loop { margin: 0; cursor: pointer; }
  /* Full-screen video fills the viewport on one axis, so its focus ring (global.css) sits just inside the frame. */
  html.magazine-ground .magazine .mag-video .embed.has-focus iframe { outline-offset: calc(-1 * var(--focus-ring)); }

  /* CONTENT SECTIONS (Read & Watch, 3 Nov): light text on a dark text area (ink 80% + 16px blur: white titles
     8.3:1, light-grey body 4.56:1 over any image), 784px wide from the browser edge, straight edges. The box is
     the full height of the screen (Andry, 4 Nov) with its text vertically centred (64 above, 96 below and each side
     at least); long text starts at the top and scrolls. The full-height panel is a transparent carrier for the slide. */
  html.magazine-ground .magazine .mag-section { height: var(--scene-section); }
  html.magazine-ground .magazine .mag-section .mag-panel { right: auto; width: var(--page-w); align-items: center; }
  html.magazine-ground .magazine .mag-section.is-long .mag-panel { align-items: flex-start; }
  html.magazine-ground .magazine .mag-section .mag-box {
    width: var(--rw-copy-w); max-width: 100vw; min-height: 100vh;
    display: flex; flex-direction: column; justify-content: center;
    padding: var(--space-section) var(--rw-pad) calc(var(--space-section) * var(--padding-end-ratio));
    background: var(--scrim-on-image);
    -webkit-backdrop-filter: blur(var(--scrim-blur)); backdrop-filter: blur(var(--scrim-blur));
  }
  /* the image makes room: a field in the cover's ground (ink; the light surface on light covers) shows behind the box, where the image moves away from */
  html.magazine-ground .magazine .mag-section::before { content: ""; position: fixed; inset: 0; z-index: 0; background: var(--mag-field, var(--color-ink-base)); pointer-events: none; }
  html.magazine-ground .magazine .mag-section > :is(.mag-media, .mag-bg) { position: fixed; inset: 0; z-index: 0; margin: 0; }
  /* a Figure, or a Markdown image (a paragraph holding only the image): both fill the screen */
  html.magazine-ground .magazine .mag-media > :is(.figure, p) { width: 100%; height: 100%; margin: 0; }
  html.magazine-ground .magazine .mag-media img { display: block; width: 100%; height: 100%; max-width: none; object-fit: cover; outline: 0; }
  html.magazine-ground .magazine .mag-media figcaption { display: none; }
  /* list markers come in with their item's first line (--reveal on the li, else-magazine.js), so a bullet never
     shows before its text */
  html.magazine-ground .magazine .mag-text li::marker { color: color-mix(in srgb, currentColor calc(var(--reveal, 1) * 100%), transparent); }
  /* the pull-quote bar comes in with its block (--reveal, 0-1): drawn as a separate bar in the border's place */
  html.magazine-ground .magazine .mag-text > .pullquote { position: relative; border-left-color: transparent; }
  html.magazine-ground .magazine .mag-text > .pullquote::before {
    content: ""; position: absolute; top: 0; bottom: 0; left: -3px; width: 3px; background: var(--text-emphasis);
    transform: scaleY(var(--reveal, 1)); transform-origin: top; opacity: var(--reveal, 1); pointer-events: none;
  }

  /* RESULTS (3 Nov): closes the article like the intro. Its background stays to the end of the page and Related
     work and the footer scroll up over it. Title centred; the metrics in three equal cells across the page-title
     width, 24px under the title, 32px padding, hairline dividers the full height of the row. */
  html.magazine-ground .magazine .mag-results { height: var(--scene-intro); clip-path: inset(0 0 -100000px 0); }
  /* no Results: an empty closing backdrop, no height of its own; its blurred cover stays to the end of the page, so
     Related work and the footer push the last section out over it */
  html.magazine-ground .magazine .mag-end { height: 0; clip-path: inset(0 0 -100000px 0); }
  html.magazine-ground .magazine .mag-results .mag-box { width: var(--mag-title-w); margin-inline: auto; padding-block: var(--space-section); }
  html.magazine-ground .magazine .mag-results .mag-text {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 0; row-gap: var(--space-page-title); align-items: stretch;
  }
  html.magazine-ground .magazine .mag-results .mag-text > * { margin: 0; }
  html.magazine-ground .magazine .mag-results .mag-text > h2 { grid-column: 1 / -1; text-align: center; }
  html.magazine-ground .magazine .mag-results .mag-text > :not(h2) { position: relative; padding: var(--space-8); text-align: center; }
  html.magazine-ground .magazine .mag-results .stat-value { color: var(--text-emphasis); }
  /* a list as Results (O2): each item is a cell, centred, no marker, with the same hairline between cells */
  html.magazine-ground .magazine .mag-results .mag-text > :is(ul, ol) { display: contents; }
  html.magazine-ground .magazine .mag-results .mag-text li {
    position: relative; margin: 0; padding: var(--space-8); list-style: none; text-align: center; color: var(--text-emphasis);
  }
  html.magazine-ground .magazine .mag-results .mag-text li + li::before {
    content: ""; position: absolute; top: 0; bottom: 0; left: 0; border-left: var(--guide-line-on-image);
    transform: scaleY(var(--reveal, 1)); transform-origin: top; opacity: var(--reveal, 1); pointer-events: none;
  }
  html.magazine-ground .magazine .mag-results .mag-text > :not(h2) + :not(h2)::before {
    content: ""; position: absolute; top: 0; bottom: 0; left: 0; border-left: var(--guide-line-on-image);
    transform: scaleY(var(--reveal, 1)); transform-origin: top; opacity: var(--reveal, 1); pointer-events: none;
  }

  /* RELATED WORK AND THE FOOTER scroll up over Results, in the on-image colours; the footer on a full-bleed band
     with the section panels' backdrop; no keyline above it (the band's edge does the job) */
  html.magazine-ground main > :not(article), html.magazine-ground .page-panel > .site-footer { position: relative; z-index: 4; background: none; }
  html.magazine-ground { --guide-line: var(--guide-line-on-image); }
  html.magazine-ground .page-panel > .site-footer::before {
    content: ""; position: absolute; inset: 0 auto 0 50%; width: var(--page-w); transform: translateX(-50%); z-index: -1;
    border: 0; margin: 0; background: var(--scrim-on-image);
    -webkit-backdrop-filter: blur(var(--scrim-blur)); backdrop-filter: blur(var(--scrim-blur)); pointer-events: none;
  }

  /* LIGHT COVERS (3 Nov): a white band and the standard dark elements (body grey and ink half and half on the
     bands). Fred. Olsen's cover measures dark (0.17); kept for the next magazine. */
  html.magazine-ground[data-cover-theme="light"] { --scrim-on-image: var(--scrim-light); --guide-line-on-image: 0.5px solid color-mix(in srgb, var(--color-guide) 50%, transparent); --mag-field: var(--color-surface-base); }
  /* the ground under the scenes is light too, so whatever shows through (and what accessibility checks measure
     against) matches the light backdrops, with the standard dot field (ink at 25% over the surface) */
  html.magazine-ground[data-cover-theme="light"] {
    background: var(--color-surface);
    --ground-dot: color-mix(in srgb, var(--color-ink) 25%, var(--color-surface));
  }
  /* the text sits on the light band, bar and boxes: underline gaps are cut in that colour, not ink */
  html.magazine-ground[data-cover-theme="light"] body { --skip-ink-colour: var(--color-surface-base); }

  /* TRANSITIONS: base states. else-magazine.js splits text into letters (Type in) and words (Line in) and drives
     them with the scroll; with reduced motion it doesn't split, so nothing moves and the text is simply there. */
  html.magazine-ground .mag-tw { white-space: nowrap; }
  html.magazine-ground :is(.mag-tc, .mag-tl) { will-change: opacity, filter; }
}
