/* ============================================================================
   explorist.io — house stylesheet
   Tokens copied from brand/visual/brand-sheet.html (Color.md, settled 2026-09-04).
   Type per brand/visual/Typography.md. Layout per brand/visual/Layout.md.
   Plain CSS: no framework, no build step, no CDN. Edit this file directly.
   ========================================================================== */

/* ---------- 1. Faces (self-hosted, Typography.md §4) -----------------------
   Variable TTFs from github.com/google/fonts, converted to woff2 with fontTools.
   The full faces are kept, not the Google CSS API build, because that build
   strips the OpenType features (onum, lnum, smcp, frac) the style rules need.  */

@font-face {
  font-family: "EB Garamond";
  src: url("fonts/eb-garamond-var.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "EB Garamond";
  src: url("fonts/eb-garamond-italic-var.woff2") format("woff2");
  font-weight: 400 800;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Goudy Bookletter 1911";
  src: url("fonts/goudy-bookletter-1911.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IM Fell Great Primer SC";
  src: url("fonts/im-fell-great-primer-sc.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/ibm-plex-sans-var.woff2") format("woff2");
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- 2. Tokens -------------------------------------------------------
   Day and night hold one value each, paired by light-dark(). Which half the
   page reads is decided by color-scheme: the default follows the system, and
   the toggle writes data-mode on <html> to override it. One block, so the two
   modes cannot drift apart. No pure white, no pure black (Color.md rule 3).    */

:root {
  color-scheme: light dark; /* no choice made: follow the system, live */

  /* palette — light-dark(day, night) */
  --blue: light-dark(#20388f, #284a7c);
  --blue-deep: light-dark(#142668, #0e1c36);
  --tone: light-dark(#8f9bd0, #7d98c2);
  /* small apparatus text: the tone blue, darkened until it reads at 4.5:1 on
     both paper and raised (WCAG AA). --tone stays for rules and the sheen. */
  --quiet: light-dark(#56639e, #8aa3cc);
  --tint: light-dark(#e3e4ee, #284a7c);
  --ink: light-dark(#2d2b29, #e8e1d2);
  --paper: light-dark(#f4eedc, #142848);
  --raised: light-dark(#faf6ea, #1b335c);
  --actor: light-dark(#d27f22, #e08a3a);
  --actor-deep: light-dark(#b0661a, #c9752c);
  --on-actor: #faf6ec;
  --display: light-dark(#20388f, #e8e1d2); /* blue by day, paper text by night */
  --link: light-dark(#b0661a, #e08a3a);

  /* the frame: one shade lighter than text ink by day, tone blue by night
     (decisions 19 and 20) */
  --frame: light-dark(#6a655e, #7d98c2);
  --hatch-1: light-dark(rgba(45, 43, 41, 0.16), rgba(125, 152, 194, 0.3));
  --hatch-2: light-dark(rgba(45, 43, 41, 0.09), rgba(125, 152, 194, 0.16));

  /* faces */
  --fell: "IM Fell Great Primer SC", serif;
  --goudy: "Goudy Bookletter 1911", serif;
  --garamond: "EB Garamond", Garamond, Georgia, serif;
  --plex: "IBM Plex Sans", system-ui, sans-serif;
}

/* When the visitor picks a mode, the values for that mode are set explicitly.
   light-dark() alone would do, but a change of color-scheme does not start a
   CSS transition in every browser, and the switch (section 10) uses transitions. The values are the same as above,
   copied by hand: keep the three lists together. */
:root[data-mode="day"] {
  color-scheme: light;
  --blue: #20388f;
  --blue-deep: #142668;
  --tone: #8f9bd0;
  --quiet: #56639e;
  --tint: #e3e4ee;
  --ink: #2d2b29;
  --paper: #f4eedc;
  --raised: #faf6ea;
  --actor: #d27f22;
  --actor-deep: #b0661a;
  --display: #20388f;
  --link: #b0661a;
  --frame: #6a655e;
}
:root[data-mode="night"] {
  color-scheme: dark;
  --blue: #284a7c;
  --blue-deep: #0e1c36;
  --tone: #7d98c2;
  --quiet: #8aa3cc;
  --tint: #284a7c;
  --ink: #e8e1d2;
  --paper: #142848;
  --raised: #1b335c;
  --actor: #e08a3a;
  --actor-deep: #c9752c;
  --display: #e8e1d2;
  --link: #e08a3a;
  --frame: #7d98c2;
}

/* Non-color tokens cannot ride light-dark(), so they carry a mode block each.
   Keep this list short; anything that is a color belongs above. */
:root { --grain-blend: multiply; --grain-opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) {
    --grain-blend: screen; --grain-opacity: 0.5;
  }
}
:root[data-mode="night"] {
  --grain-blend: screen; --grain-opacity: 0.5;
}

/* ---------- 3. Base --------------------------------------------------------- */

* { box-sizing: border-box; margin: 0; padding: 0; }

html { background: var(--paper); }

body {
  background: var(--paper);
  color: var(--ink);
  font: 17px/1.55 var(--garamond);
  font-feature-settings: "onum", "liga", "kern"; /* oldstyle figures in prose */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--goudy);
  font-weight: 400;
  line-height: 1.12;
  color: var(--display);
}
h1 { font-size: 3.2rem; letter-spacing: -0.005em; }
h2 { font-size: 2rem; }
h3 { font-size: 1.35rem; }

p { max-width: 34em; }
p + p { margin-top: 0.7em; }

/* No one-word last lines: headings balance their lines, prose avoids orphans. */
h1, h2, h3, h4 { text-wrap: balance; }
p, li, blockquote { text-wrap: pretty; }

a { color: var(--link); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.12em; }

em, i { font-style: italic; }

::selection { background: var(--actor); color: var(--on-actor); }

/* Keyboard focus is always visible, and never only a color change. */
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--actor);
  outline-offset: 3px;
}

/* ---------- 4. Apparatus (sans; Typography.md rule 2) ----------------------- */

.sans, .kicker, .btn, .list, .quadrant, table, figcaption, .caption {
  font-family: var(--plex);
  font-feature-settings: "lnum", "tnum"; /* lining figures in apparatus */
}

.kicker {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--quiet);
}

.wordmark {
  font-family: var(--fell);
  text-transform: lowercase;
  letter-spacing: 0.06em;
  color: var(--ink);
}

.btn {
  display: inline-block;
  background: var(--actor);
  color: var(--on-actor);
  font-size: 14px;
  font-weight: 500;
  padding: 0.55em 1.15em;
  border: 0;
  border-radius: 3px;
  text-decoration: none;
  cursor: pointer;
  transition: background 180ms ease-out;
}
.btn:hover { background: var(--actor-deep); }
.btn:active { background: var(--blue-deep); }

.quiet { color: var(--quiet); }

hr.rule { border: 0; border-top: 1px solid var(--tone); }

/* ---------- 5. The mode button ---------------------------------------------
   The one place an icon is allowed (Layout.md iconography rule), flagged as a
   substitution until a house set exists. Task 8 builds the sunrise; this is the
   stub that carries the state.                                                 */

.mode-toggle {
  position: fixed;
  top: 50px;
  right: 50px;
  z-index: 20;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: var(--raised);
  color: var(--ink);
  border: 1px solid var(--frame);
  border-radius: 50%;
  cursor: pointer;
  font: inherit;
  transition: border-color 180ms ease-out, color 180ms ease-out, background 180ms ease-out;
}
.mode-toggle:hover { border-color: var(--actor); color: var(--actor-deep); }
.mode-toggle:active { background: var(--paper); }
.mode-toggle svg { width: 20px; height: 20px; display: block; pointer-events: none; }
/* The icon shows the mode you would switch to: a moon by day, a sun by night. */
.mode-toggle .icon-sun { display: none; }
:root[data-mode="night"] .mode-toggle .icon-sun { display: block; }
:root[data-mode="night"] .mode-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .mode-toggle .icon-sun { display: block; }
  :root:not([data-mode="day"]) .mode-toggle .icon-moon { display: none; }
}

/* ---------- 6. The drawn frame (task 2) -------------------------------------
   frame.svg is a nine-slice drawing: corners and edges keep their line weight
   at any montage size, so the band never stretches. It paints in currentColor,
   which the montage sets to --frame.                                              */

.framed { position: relative; }
.framed > .frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  z-index: 4;
}
/* The outer rule again, in orange, waiting. Hover, keyboard focus and tap all
   bring it up; the rule is the signal, never the only one. */
.framed > .frame-hot {
  opacity: 0;
  transition: opacity 200ms ease-out;
}
.framed:hover > .frame-hot,
.framed:focus-visible > .frame-hot,
.framed:active > .frame-hot { opacity: 1; }

/* The drawing itself is markup, not a picture: it carries no size and no colour
   of its own. The ink is set here, once, and the whole frame reads currentColor.
   Pattern content takes its colour from where the pattern sits, so the hot set
   gets its own line. */
.frame-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  color: #6a655e; /* the day frame, literal: this set never changes colour */
}
.frame-defs .night { color: #7d98c2; }
.frame-defs .hot { color: var(--actor); }
/* Each montage carries both frames; the mode decides which one shows, and
   the switch (section 10) cross-fades them. */
.framed > .frame-night { opacity: 0; }
:root[data-mode="night"] .framed > .frame-day { opacity: 0; }
:root[data-mode="night"] .framed > .frame-night { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .framed > .frame-day { opacity: 0; }
  :root:not([data-mode="day"]) .framed > .frame-night { opacity: 1; }
}

/* ---------- 6b. Hover sheen (task 7, decision 24) ------------------------------
   Hovering a montage colours the ink lines under the cursor: they pick up a band
   of orange, gold, and the house blue that slides as the pointer moves, like
   light on foil. Only the lines take colour.
   The layer is a colour sheet seen through two masks at once: the line work and
   a soft spot at the pointer. On the placeholder the line work is the hatch; on
   a real montage it is NAME-lines.jpg, the drawing inverted, whose white strokes
   on black make a luminance mask. hover.js moves the spot and the sheen;
   without it the layer never shows and the orange rule still does the work.   */

/* The sheen layer lives inside the picture and fills it, so it is the picture's
   own box that it is masked against. It used to sit beside the picture with its
   own 37 px inset; once it moved inside, that inset applied twice and the sheen
   landed a frame's width down and in from the drawing. */
/* Two masks, two boxes. The line work masks the .sheen layer itself and the
   pointer's spot masks its ::before child, which carries the colour sheet.
   They used to sit as two layers on one element, intersected by
   mask-composite; a Chrome update (observed 2026-09-21) began compositing
   that pair to an empty mask, on the placeholder hatch and the drawing
   alike, and the nesting needs no composite property at all: a mask on a
   parent and a mask on its child always multiply. */
.sheen {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transition: opacity 220ms ease-out;
}
.sheen::before {
  content: "";
  position: absolute;
  inset: 0;
  /* The band has to be narrower than the lit spot, or the whole spot takes one
     flat colour and reads as a stain rather than a sheen. At 55% of the montage
     the pointer carries two or three bands with it. The cool note is the tone
     blue, not the deep blue: a dark blue on a light montage reads as a smudge. */
  background: linear-gradient(105deg,
    var(--actor-deep) 0%, var(--actor) 12%, #f0c477 26%, #e6dcc0 38%,
    var(--tone) 50%, #e6dcc0 62%, #f0c477 74%, var(--actor) 88%, var(--actor-deep) 100%);
  background-size: 55% 100%;
  background-position: var(--mx, 50%) 0;
  -webkit-mask-image: radial-gradient(circle calc(var(--d) * 0.5) at var(--mx, 50%) var(--my, 50%), #000 0%, rgba(0,0,0,0.55) 45%, transparent 100%);
  mask-image: radial-gradient(circle calc(var(--d) * 0.5) at var(--mx, 50%) var(--my, 50%), #000 0%, rgba(0,0,0,0.55) 45%, transparent 100%);
}
.sheen.placeholder-ink {
  -webkit-mask-image: repeating-linear-gradient(45deg, #000 0 1px, transparent 1px 6px);
  mask-image: repeating-linear-gradient(45deg, #000 0 1px, transparent 1px 6px);
}
/* task 6: <div class="sheen" style="--lines:url(montages/berkshire-lines.jpg)"> */
.sheen.drawing-ink {
  -webkit-mask-image: var(--lines);
  mask-image: var(--lines);
  -webkit-mask-size: cover;
  mask-size: cover;
  /* The strokes have to land on the drawing exactly. object-fit: cover centres
     and sits on the bottom edge; a mask defaults to the top left corner, which is
     what threw the sheen off the lines. Same box, same anchor, same fit. */
  -webkit-mask-position: center bottom;
  mask-position: center bottom;
  mask-mode: luminance;
}
.montage.lit .sheen { opacity: 1; }

/* ---------- 7. Page grain ---------------------------------------------------
   Paper texture. Flat ink on paper; no emboss, bevel or shadow anywhere
   (decision 15).                                                               */

.grain {
  position: absolute;
  inset: 0;
  /* Above the drawing (1), under the sheen (3) and the frame (4). The grain is
     the montage's paper, so it has to fall on the drawing too: with the drawing
     above it, the drawing was the one ungrained rectangle on the montage and read
     as a lighter panel against its own ground. */
  z-index: 2;
  pointer-events: none;
  mix-blend-mode: var(--grain-blend);
  opacity: var(--grain-opacity);
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .18 0 0 0 0 .17 0 0 0 0 .16 0 0 0 .05 0'/></filter><rect width='200' height='200' filter='url(%23n)'/></svg>");
}

/* ---------- 8. The main page: the montage grid ------------------------------------
   Four montages in golden section, 8 : 5 : 3 : 2, on the whole viewport, with the
   round nav at the golden spiral's centre (decisions 3, 7, 8, 11, 13). One screen,
   no scroll. The narrow layout is task 5; until then the montage grid is the page from
   900 px up, and below that the montages simply stack in source order.            */

.home { overflow: hidden; }

.montages {
  /* The round nav's diameter: 350 px on a 1440 px window, held between 220 and
     420 (decision 13). The montage grid keeps it, because the montages have to dodge it. */
  --d: clamp(220px, 24.3vw, 420px);
  position: relative;
  height: 100svh;
  min-height: 560px;
}

.montage {
  position: absolute;
  display: block;
  text-decoration: none;
  color: var(--ink);
  background: var(--raised);
  overflow: hidden;
}
.montage:focus-visible { outline-offset: -4px; }

/* 8 : 5 : 3 : 2. The vertical cut is the golden section of the width, the
   horizontal cut the golden section of the height. */
.montage-berkshire { left: 0;     top: 0;   width: 62.5%; height: 100%; }
.montage-spacex    { left: 62.5%; top: 0;   width: 37.5%; height: 60%; }
.montage-next      { left: 62.5%; top: 60%; width: 25%;   height: 40%; }
.montage-shop      { left: 87.5%; top: 60%; width: 12.5%; height: 40%; }

/* The picture sits inside the frame's 37 px. Until a drawing lands it is the
   hatched placeholder from the prototype, with the montage's brief on it; a montage
   that has its drawing turns the hatch off. */
.picture {
  position: absolute;
  inset: 37px;
  overflow: hidden;
  container-type: inline-size; /* the drawing's height reads the picture's width (cqw) */
}
/* The hatch is a colour seen through a mask, not a gradient of colours, so it
   can transition with the rest of the page when the mode switches. */
.picture.has-drawing::before, .picture.has-drawing::after { content: none; }
.picture::before, .picture::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-color: var(--hatch-1);
  -webkit-mask-image: repeating-linear-gradient(45deg, #000 0 1px, transparent 1px 6px);
  mask-image: repeating-linear-gradient(45deg, #000 0 1px, transparent 1px 6px);
}
.picture::after {
  background-color: var(--hatch-2);
  -webkit-mask-image: repeating-linear-gradient(-45deg, #000 0 1px, transparent 1px 9px);
  mask-image: repeating-linear-gradient(-45deg, #000 0 1px, transparent 1px 9px);
}
/* A drawing is landscape and sits on the bottom edge of the montage, not stretched to the
   square. --drawing-h leaves paper above it, so the collage ends where the
   collage ends; the drawing is wider than the montage, so a wider window reveals
   more of it rather than scaling it up. Per montage, because each one's subject
   sits at its own height. */
.picture.has-drawing { --drawing-h: 80%; }
/* The SpaceX montage fills its picture edge to edge (Max, 2026-09-21). The
   Berkshire drawing keeps 12% of paper above it (Max, 2026-09-25: a little
   taller than the 20% it had). */
.montage-spacex .picture.has-drawing { --drawing-h: 100%; }
.montage-berkshire .picture.has-drawing { --drawing-h: 88%; }
/* The two portrait montages (in the works, the shop) are drawn tall and fill
   their picture top to bottom; the label's quiet zone is inside the drawing. */
.montage-next .picture.has-drawing, .montage-shop .picture.has-drawing { --drawing-h: 100%; }
.picture img,
.picture.has-drawing > .sheen {
  position: absolute;
  left: 0;
  right: 0;
  top: auto;          /* height decides the box; bottom pins it to the bottom edge */
  bottom: 0;
  height: 100%;
}
.picture img { z-index: 1; }
/* On a wide, short window the picture is wider than the drawing, and a fixed
   height would crop the drawing's top (Max, 2026-09-24). So the drawing takes
   its own height at the picture's width (2:3 of it), never less than
   --drawing-h and never more than the whole picture: a wider window uses the
   paper above it before it cuts anything. */
.picture.has-drawing img,
.picture.has-drawing > .sheen { height: clamp(var(--drawing-h), 66.667cqw, 100%); }
/* In the works is anchored at the top: its drawing is the head and the city,
   and the paper under them is where the label sits (Max, 2026-09-24). */
.montage-next .picture img { object-position: center top; }
.montage-next .sheen.drawing-ink { -webkit-mask-position: center top; mask-position: center top; }
.picture img {
  width: 100%;
  object-fit: cover;
  object-position: center bottom;
  display: block;
}
/* Day and night drawings are two files, switched here rather than by a
   <picture> media query: the media query cannot see the visitor's own choice. */
.picture .night { opacity: 0; }
:root[data-mode="night"] .picture .day { opacity: 0; }
:root[data-mode="night"] .picture .night { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .picture .day { opacity: 0; }
  :root:not([data-mode="day"]) .picture .night { opacity: 1; }
}
/* On a montage the day drawing never fades: the night one fades in over it.
   Two fades at once let the paper behind show through half way, so a drawing
   that stops short of its frame (Berkshire) went darker than the paper round
   it mid-switch. One fade over an opaque drawing is the same straight mix as
   the paper's own colour change, so the two stay level the whole way (Max,
   2026-09-25). The tiles' pictures are transparent and keep both fades. */
:root[data-mode="night"] .montage .picture .day { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .montage .picture .day { opacity: 1; }
}

.placeholder {
  position: absolute;
  left: 50%;
  top: 40%;
  transform: translate(-50%, -50%);
  max-width: 70%;
  padding: 0.4em 0.8em;
  border: 1px solid var(--ink);
  background: var(--raised);
  font-family: var(--plex);
  font-size: 11px;
  line-height: 1.35;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
}

/* The label, inside the frame (decision 16). No box: each drawing ends a strip
   above the frame and fades into the paper, and the caption spans the frame
   on that paper (Max, 2026-09-25, "G" in the caption spike). It replaced a
   caption box that took half of the small montages, which in turn replaced
   paper that hugged each text line. */
.label {
  position: absolute;
  left: 57px;
  right: 57px;
  bottom: 50px;
  z-index: 5;
}
.label .kicker { display: block; margin-bottom: 6px; }
.label h2 { font-size: 36px; color: var(--ink); }
.label p { margin: 6px 0 0; font-size: 17px; line-height: 1.5; }
.label .list {
  display: block;
  margin-top: 10px;
  color: var(--actor-deep);
  font-size: 12px;
}
/* The small montages take smaller type, so their fades stay short. */
.montage-spacex .label { left: 53px; right: 53px; bottom: 44px; }
.montage-next .label { left: 50px; right: 50px; bottom: 40px; }
.montage-spacex .label h2 { font-size: 24px; }
.montage-next .label h2 { font-size: 19px; }
.montage-spacex .label p, .montage-next .label p { margin-top: 4px; font-size: 14px; line-height: 1.4; }
.montage-spacex .label .kicker, .montage-next .label .kicker { margin-bottom: 3px; font-size: 10px; }
.montage-spacex .label .list { margin-top: 6px; font-size: 11px; }
/* The shop is two units wide: title only. */
/* The frame's band is about 30 px wide on every montage, so the caption starts
   past it, not on it. */
.montage-shop .label { left: 42px; right: 36px; bottom: 44px; }
.montage-shop .label h2 { font-size: 18px; white-space: nowrap; }

/* The strip and the fade, per montage. --lift is the strip of paper under the
   drawing. The fade is paper, solid for --solid of its height and then easing
   off, --fade tall: in px, because the caption it carries is a fixed size.
   The paper is a background colour seen through an alpha mask, not a
   gradient of colours, so it transitions with the page when the mode switches
   (section 10); a colour gradient would jump. z 3 puts it over the sheen. */
@media (min-width: 900px) {
  .montage-berkshire { --lift: 48px; --fade: 120px; --solid: 36%; }
  .montage-spacex    { --lift: 44px; --fade: 150px; --solid: 50%; }
  .montage-next      { --lift: 40px; --fade: 116px; --solid: 42%; }
  .montage-shop      { --lift: 24px; --fade: 60px;  --solid: 20%; }
  .montage .picture { bottom: calc(37px + var(--lift)); }
  .montage .picture.has-drawing::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: var(--fade);
    z-index: 3;
    background-color: var(--raised);
    -webkit-mask-image: linear-gradient(to top, #000 var(--solid), rgba(0, 0, 0, 0.7) calc(var(--solid) + (100% - var(--solid)) * 0.4), transparent);
    mask-image: linear-gradient(to top, #000 var(--solid), rgba(0, 0, 0, 0.7) calc(var(--solid) + (100% - var(--solid)) * 0.4), transparent);
    pointer-events: none;
  }
}
/* Wide, Berkshire's caption is two columns: kicker and title on the left, the
   line and the list on the right, so the caption and its fade stay short.
   Narrower, the line would wrap to four lines, so it stacks (section 9c). */
@media (min-width: 1200.02px) {
  .montage-berkshire .label {
    display: grid;
    grid-template-columns: auto minmax(0, 30em);
    column-gap: 40px;
    align-items: end;
  }
  .montage-berkshire .label .kicker { grid-column: 1; grid-row: 1; }
  .montage-berkshire .label h2 { grid-column: 1; grid-row: 2; }
  .montage-berkshire .label p { grid-column: 2; grid-row: 1 / span 2; align-self: end; margin: 0; font-size: 16px; }
  .montage-berkshire .label .list { grid-column: 2; grid-row: 3; }
}

/* ---------- 9. The round nav (the main page's navigation) ----------------------
   350 px on a 1440 px window, never under 220 or over 420 (decision 13). It sits
   at the golden spiral's centre, not the centre of the page (decision 8).            */

.home-nav {
  position: absolute;
  left: 62.5%;
  top: 24%;
  transform: translate(-50%, -50%);
  z-index: 6;
  width: var(--d);
  height: var(--d);
  text-align: center;
  border-radius: 50%;
  overflow: hidden; /* the word tabs at east and west would otherwise cross the rule */
  background: var(--paper);
  border: 1px solid var(--ink);
}
/* One flat rule outside, one tint ring inside (decision 15: flat rules, no
   shadow). The second outer rule that used to sit 9 px out is gone: it read as
   padding and made the links look off centre (checkpoint 1 correction). */
.home-nav::after {
  content: "";
  position: absolute;
  inset: calc(var(--d) * 0.13);
  border-radius: 50%;
  border: 1px solid var(--tint);
  pointer-events: none;
}
/* The lockup is the brand's own lockup-v drawing (Logo.md, assets/export), and
   with the one-liner under it forms one block, pinned to the circle's centre.
   Nothing else in the round nav is in flow, so nothing can push it off centre. */
.home-nav .center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  justify-items: center;
  row-gap: calc(var(--d) * 0.04);
}
.home-nav .lockup { display: block; width: calc(var(--d) * 0.36); }
.home-nav .lockup img { display: block; width: 100%; height: auto; }
.home-nav small {
  display: block;
  width: max-content;
  max-width: calc(var(--d) * 0.5);
  font-style: italic;
  font-size: calc(var(--d) * 0.046);
  line-height: 1.3;
  text-align: center;
}

/* The four nav link, at the compass points. Always visible, never on hover
   (decision 10). Each link is a quarter of the ring between the outer circle
   and the inner one: the whole quadrant is the link, the word sits at its
   centre, and on hover the quadrant fills with the frame's hatching. */
.home-nav .links { position: absolute; inset: 0; }
.quadrant {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  cursor: pointer;
  text-decoration: none;
  background:
    repeating-linear-gradient(45deg, var(--hatch-1) 0 1px, transparent 1px 5px),
    repeating-linear-gradient(-45deg, var(--hatch-2) 0 1px, transparent 1px 8px);
  opacity: 0;
  transition: opacity 180ms ease-out;
}
.quadrant:hover, .quadrant:focus-visible { opacity: 1; }
.quadrant:focus-visible { outline: none; }
.quadrant.n { clip-path: polygon(85.36% 14.64%, 81.17% 10.91%, 76.60% 7.66%, 71.69% 4.95%, 66.51% 2.81%, 61.13% 1.25%, 55.60% 0.31%, 50.00% 0.00%, 44.40% 0.31%, 38.87% 1.25%, 33.49% 2.81%, 28.31% 4.95%, 23.40% 7.66%, 18.83% 10.91%, 14.64% 14.64%, 23.84% 23.84%, 26.93% 21.07%, 30.31% 18.67%, 33.95% 16.66%, 37.78% 15.08%, 41.77% 13.93%, 45.86% 13.23%, 50.00% 13.00%, 54.14% 13.23%, 58.23% 13.93%, 62.22% 15.08%, 66.05% 16.66%, 69.69% 18.67%, 73.07% 21.07%, 76.16% 23.84%); }
.quadrant.e { clip-path: polygon(85.36% 85.36%, 89.09% 81.17%, 92.34% 76.60%, 95.05% 71.69%, 97.19% 66.51%, 98.75% 61.13%, 99.69% 55.60%, 100.00% 50.00%, 99.69% 44.40%, 98.75% 38.87%, 97.19% 33.49%, 95.05% 28.31%, 92.34% 23.40%, 89.09% 18.83%, 85.36% 14.64%, 76.16% 23.84%, 78.93% 26.93%, 81.33% 30.31%, 83.34% 33.95%, 84.92% 37.78%, 86.07% 41.77%, 86.77% 45.86%, 87.00% 50.00%, 86.77% 54.14%, 86.07% 58.23%, 84.92% 62.22%, 83.34% 66.05%, 81.33% 69.69%, 78.93% 73.07%, 76.16% 76.16%); }
.quadrant.s { clip-path: polygon(14.64% 85.36%, 18.83% 89.09%, 23.40% 92.34%, 28.31% 95.05%, 33.49% 97.19%, 38.87% 98.75%, 44.40% 99.69%, 50.00% 100.00%, 55.60% 99.69%, 61.13% 98.75%, 66.51% 97.19%, 71.69% 95.05%, 76.60% 92.34%, 81.17% 89.09%, 85.36% 85.36%, 76.16% 76.16%, 73.07% 78.93%, 69.69% 81.33%, 66.05% 83.34%, 62.22% 84.92%, 58.23% 86.07%, 54.14% 86.77%, 50.00% 87.00%, 45.86% 86.77%, 41.77% 86.07%, 37.78% 84.92%, 33.95% 83.34%, 30.31% 81.33%, 26.93% 78.93%, 23.84% 76.16%); }
.quadrant.w { clip-path: polygon(14.64% 14.64%, 10.91% 18.83%, 7.66% 23.40%, 4.95% 28.31%, 2.81% 33.49%, 1.25% 38.87%, 0.31% 44.40%, 0.00% 50.00%, 0.31% 55.60%, 1.25% 61.13%, 2.81% 66.51%, 4.95% 71.69%, 7.66% 76.60%, 10.91% 81.17%, 14.64% 85.36%, 23.84% 76.16%, 21.07% 73.07%, 18.67% 69.69%, 16.66% 66.05%, 15.08% 62.22%, 13.93% 58.23%, 13.23% 54.14%, 13.00% 50.00%, 13.23% 45.86%, 13.93% 41.77%, 15.08% 37.78%, 16.66% 33.95%, 18.67% 30.31%, 21.07% 26.93%, 23.84% 23.84%); }
/* The word sits on the ring's centre line, 43.5% of the diameter from the
   middle. It is drawn by its own layer, so it stays put whatever the quadrant
   under it does. */
.home-nav .links .word {
  position: absolute;
  pointer-events: none;
  transform: translate(-50%, -50%);
  padding: 3px 8px;
  background: var(--paper);
  color: var(--actor-deep);
  font-family: var(--plex);
  font-feature-settings: "lnum", "tnum";
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  transition: color 180ms ease-out;
}
.home-nav .links .word.n { left: 50%; top: 6.5%; }
.home-nav .links .word.s { left: 50%; top: 93.5%; }
.home-nav .links .word.e { left: 93.5%; top: 50%; }
.home-nav .links .word.w { left: 6.5%; top: 50%; }
.quadrant.n:hover ~ .word.n, .quadrant.e:hover ~ .word.e,
.quadrant.s:hover ~ .word.s, .quadrant.w:hover ~ .word.w,
.quadrant.n:focus-visible ~ .word.n, .quadrant.e:focus-visible ~ .word.e,
.quadrant.s:focus-visible ~ .word.s, .quadrant.w:focus-visible ~ .word.w { color: var(--ink); }

/* The round nav covers the SpaceX montage's left edge, Gwynne Shotwell
   included. While the pointer is on that montage the round nav fades back so
   the drawing shows through; moving onto the round nav brings it up again,
   because the pointer has left the montage (Max, 2026-09-24). */
.home-nav { transition: opacity 260ms ease-out; }
.montages:has(.montage-spacex:hover) .home-nav { opacity: 0.35; }

/* ---------- 9b. The bar (decision 12) --------------------------------------
   The inner pages' top bar: lockup left, the four nav links right, 52 px, sticky.
   The main page carries it only under 900 px, where the round nav is gone.   */

.bar {
  display: none;
  position: sticky;
  top: 0;
  z-index: 10;
  align-items: center;
  justify-content: space-between;
  height: 52px;
  padding: 0 16px;
  background: var(--paper);
  border-bottom: 1px solid var(--frame);
}
.bar .brand { display: block; height: 26px; }
.bar .brand img { display: block; height: 100%; width: auto; }
.bar .brand .night { display: none; }
:root[data-mode="night"] .bar .brand .day { display: none; }
:root[data-mode="night"] .bar .brand .night { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .bar .brand .day { display: none; }
  :root:not([data-mode="day"]) .bar .brand .night { display: block; }
}
.bar .links { display: flex; gap: 14px; }
.bar .links a {
  padding: 8px 2px;
  color: var(--actor-deep);
  font-family: var(--plex);
  font-feature-settings: "lnum", "tnum";
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.bar .links a:hover { color: var(--ink); }
.bar .links a[aria-current="page"]:not(.btn) { color: var(--ink); }

/* ---------- 9c. Narrower windows (task 5) -----------------------------------
   Between 900 and 1200 px the montage grid holds, but the three smaller montages drop
   their paragraph so nothing overflows a frame. Under 900 px the montages stack
   in one column with their full text, the round nav goes, and the bar takes
   over (decision 21).                                                          */

@media (max-width: 1200px) {
  .montage-spacex .label p, .montage-next .label p, .montage-shop .label p { display: none; }
  .montage-spacex .label h2 { font-size: 22px; }
  .montage-next .label h2 { font-size: 18px; }
  .montage-shop .label { left: 40px; right: 34px; bottom: 42px; }
  .montage-shop .label h2 { font-size: 16px; line-height: 1.1; white-space: normal; }
  /* Berkshire's caption stacks here (section 8), and drops its list. */
  .montage-berkshire .label h2 { font-size: 30px; }
  .montage-berkshire .label .list { display: none; }
}
@media (min-width: 900px) and (max-width: 1200px) {
  .montage-berkshire { --fade: 180px; --solid: 50%; }
}

/* A short window leaves the two right-hand montages too little height for a
   caption box with copy in it: the box covered the faces. Title and kicker
   only there; the Berkshire montage keeps its line. */
@media (min-width: 900px) and (max-height: 780px) {
  .montage-spacex .label p, .montage-next .label p { display: none; }
}
/* Where the small montages have dropped their line, their fades shrink. */
@media (min-width: 900px) and (max-width: 1200px), (min-width: 900px) and (max-height: 780px) {
  .montage-spacex { --fade: 110px; --solid: 40%; }
  .montage-next { --fade: 84px; --solid: 30%; }
}

@media (max-width: 899.98px) {
  .home { overflow: auto; }
  .bar { display: flex; }
  .bar .links { gap: 10px; }
  .bar .links a { font-size: 12px; }
  .montages {
    position: static;
    display: flex;
    flex-direction: column;
    height: auto;
    min-height: 0;
  }
  /* Stacked, the label moves out from over the drawing to under it, inside
     the frame: on a phone there is no room for both, and the label was
     covering the faces. The montage is a column: picture, then caption. */
  .montage {
    position: relative; left: auto; top: auto; width: 100%; height: auto;
    display: flex; flex-direction: column; padding: 37px;
  }
  .montage .picture { position: relative; inset: auto; }
  .montage-berkshire .picture { height: 60vw; }
  .montage-spacex .picture    { height: 64vw; }
  .montage-next .picture      { height: 52vw; }
  .montage-shop .picture      { height: 52vw; }
  .placeholder { top: 30%; }
  /* stacked: every label sits the same way, full text, the paragraphs back */
  .montage .label { position: relative; left: auto; right: auto; bottom: auto; margin-top: 14px; }
  .montage .label .kicker { margin-bottom: 6px; font-size: 11.5px; }
  .montage .label p { display: block; font-size: 15px; }
  .montage .label h2 { font-size: 28px; }
  .montage-shop .label h2, .montage-next .label h2 { font-size: 22px; }
  /* Stacked, the shop's tall drawing is cut to a wide box: hold the shelf in
     it, not the empty floor under it. */
  .montage-shop .picture img { object-position: center 32%; }
  .montage-shop .sheen.drawing-ink { -webkit-mask-position: center 32%; mask-position: center 32%; }
  .home-nav { display: none; }
  /* No mode button on a phone: the page follows the system there. */
  .mode-toggle { display: none; }
}

/* ---------- 10. The switch (task 8, decision 25) ----------------------------
   Day to night is a timed transition, not an instant swap. light-dark() hands every property a new
   computed colour when the mode flips; while the root carries .switching (mode.js,
   1.1 s) those properties are allowed to transition to it. The frame is two drawings,
   day and night, cross-faded by opacity (section 6). The round nav takes 350 ms and
   the montage grid 800 ms starting 100 ms later, so the round nav brightens first. 900 ms in all is a deliberate exception to Layout.md's 150 to 250 ms rule,
   flagged for the brand owner.                                                 */

:root.switching *, :root.switching *::before, :root.switching *::after {
  transition:
    background-color 800ms cubic-bezier(.4,0,.2,1) 100ms,
    color 800ms cubic-bezier(.4,0,.2,1) 100ms,
    border-color 800ms cubic-bezier(.4,0,.2,1) 100ms,
    opacity 800ms cubic-bezier(.4,0,.2,1) 100ms !important;
}
:root.switching .home-nav, :root.switching .home-nav *, :root.switching .home-nav *::after {
  transition-duration: 350ms !important;
  transition-delay: 0ms !important;
}
/* Day and night pictures sit on top of each other and cross-fade rather than
   swap: the round nav's lockup here, the montages' drawings in section 8. */
.home-nav .lockup { position: relative; }
.home-nav .lockup img { display: block; transition: opacity 400ms; }
.home-nav .lockup .night { position: absolute; inset: 0; opacity: 0; }
:root[data-mode="night"] .home-nav .lockup .day { opacity: 0; }
:root[data-mode="night"] .home-nav .lockup .night { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .home-nav .lockup .day { opacity: 0; }
  :root:not([data-mode="day"]) .home-nav .lockup .night { opacity: 1; }
}

/* ---------- 11. Motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ---------- 12. Inner pages (01.3) ------------------------------------------
   Story pages, shop, about, subscribe. One bar, one measure, and no drawn
   frame: the frame belongs to the main page's montages (Max, 2026-09-24). The
   main page is the exception on this site; every other page is this.          */

/* The bar (section 9b) hides by default and the main page shows it only when
   narrow. On an inner page it is the navigation at every width (decision 12). */
.inner .bar { display: flex; height: 64px; padding: 0 40px; }
.inner .bar .brand { height: 30px; }
.inner .bar .links { align-items: center; gap: 22px; }
.inner .bar .links .btn { color: var(--on-actor); padding: 0.45em 1em; }
.inner .bar .links .btn:hover { color: var(--on-actor); }

/* A page with no story of its own (about, subscribe, shop) flies the house
   blue, and so does SpaceX (Max, 2026-09-24). */
.inner { --flag: var(--display); }

/* The story's own colour creeps in (decision 5): headline, kicker and rules
   only. Orange stays the only actor, at every width, in both modes. The three
   blocks are the section 2 pattern — light-dark() for the system default, then
   a literal value per mode so the switch can transition it. */
.flag-berkshire { --flag: light-dark(#6952a2, #a293d4); }
:root[data-mode="day"] .flag-berkshire { --flag: #6952a2; }
:root[data-mode="night"] .flag-berkshire { --flag: #a293d4; }

.page { max-width: 1400px; margin: 0 auto; padding: 0 40px; }
.page.narrow { max-width: 760px; }

/* 12.1 The hero drawing. No frame at all; the drawing dissolves into the paper
   at its edges (decision 22). The 16:9 -story cut, day and night. */
.hero { margin: 34px auto 0; }
.hero .drawing {
  position: relative;
  aspect-ratio: 16 / 9;
  max-height: 62vh;
  margin-inline: auto;
}
.hero .drawing img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-mask-image: radial-gradient(ellipse 78% 80% at 50% 50%, #000 58%, transparent 100%);
  mask-image: radial-gradient(ellipse 78% 80% at 50% 50%, #000 58%, transparent 100%);
}
.hero .drawing .night { opacity: 0; }
:root[data-mode="night"] .hero .drawing .day { opacity: 0; }
:root[data-mode="night"] .hero .drawing .night { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .hero .drawing .day { opacity: 0; }
  :root:not([data-mode="day"]) .hero .drawing .night { opacity: 1; }
}

/* 12.2 The head: the story in prose on the left, the facts in the ruled spec
   table on the right (Layout.md, the two house document patterns). */
.head {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 60px;
  align-items: start;
  margin-top: 28px;
}
.head .kicker { color: var(--flag); }
.head aside { display: grid; gap: 40px; }
.head h1 { margin: 8px 0 16px; font-size: 52px; color: var(--flag); }
.head p { max-width: 62ch; font-size: 19px; }
.head p + p { margin-top: 0.6em; }

.spec {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
  font-size: 13px;
}
.spec td { padding: 8px 0; border-bottom: 1px solid var(--tint); vertical-align: top; }
.spec td:last-child { text-align: right; color: var(--ink); }
.spec td:first-child { color: var(--quiet); padding-right: 14px; white-space: nowrap; }
.spec tr:first-child td { border-top: 2px solid var(--flag); }
.spec tr:last-child td { border-bottom: 2px solid var(--flag); }

/* 12.2b The pull quote: one line from the sources, set large, dated. The
   story in the builders' own words, under the facts about it. */
.pull { margin: 0; padding-left: 20px; border-left: 2px solid var(--flag); }
.pull blockquote {
  font-family: var(--garamond);
  font-style: italic;
  font-size: 23px;
  line-height: 1.4;
  color: var(--ink);
}
.pull figcaption { margin-top: 10px; font-size: 12.5px; color: var(--quiet); }

/* 12.3 A section: a flag-coloured kicker on a rule of its own. */
.section { margin-top: 52px; }
.section > .kicker {
  display: block;
  color: var(--flag);
  border-top: 1px solid var(--flag);
  padding-top: 10px;
  margin-bottom: 22px;
}

/* 12.4 The production tiles. Every one ends at a purchase or a download
   (decision 2). Raised paper and one hairline, no drawn frame (Max,
   2026-09-24). The title's link stretches over the whole tile, so the tile is
   one click; a second button (the book's wholesale link) sits above that
   stretched link and keeps its own address. */
.grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 32px 24px; }
.tile {
  position: relative;
  display: grid;
  grid-template-rows: auto auto 1fr auto; /* picture, title, text, actions */
  gap: 10px;
  color: var(--ink);
}
.tile .mount {
  position: relative;
  height: 300px;
  overflow: hidden;
  background: var(--raised);
  border: 1px solid var(--tint);
  border-radius: 3px;
  transition: border-color 180ms ease-out;
}
.tile .mount .picture { inset: 0; }
.tile:hover .mount, .tile:focus-within .mount { border-color: var(--actor); }
.tile h3 { margin-top: 4px; color: var(--ink); }
.tile h3 a { color: inherit; text-decoration: none; }
.tile h3 a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.tile h3 a:focus-visible { outline: none; }
.tile:has(h3 a:focus-visible) { outline: 2px solid var(--actor); outline-offset: 6px; border-radius: 3px; }
.tile p { margin: 0; font-size: 15px; max-width: none; }
.tile .row { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.tile .where { font-family: var(--plex); font-size: 13px; color: var(--quiet); }
/* A button that repeats the title's address is a <span>: the stretched link
   under it takes the click. A button with its own address is an <a>, lifted
   above the stretched link. */
.tile .actions { display: flex; gap: 8px; }
.tile .actions a { position: relative; z-index: 2; }
.tile:hover .actions span.btn { background: var(--actor-deep); }
.tile-wide { grid-column: span 3; }
.tile-third { grid-column: span 2; }
.tile-third .mount { height: 220px; }
/* A tile's picture is the thing itself, grey or house ink on a transparent
   ground (images/README.md), fitted whole inside the mount with paper around
   it. Day and night are two files where the ink differs, switched like the
   montages' (section 6); a grey cut-out is one file for both. */
.tile .mount .picture.has-image { inset: 18px 24px; }
.picture.has-image::before, .picture.has-image::after { content: none; }
.picture.has-image img,
.picture.has-image video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}
/* A video cannot be transparent in every browser, so it is blended instead:
   the day file (ink on white) multiplies into the light ground, and the night
   file (the object on black) lightens into the dark one, which keeps the black
   ground out and the dark cloth dark. The picture is its own stacking context
   (container-type), so it carries the ground the videos blend with. */
.picture.has-image:has(video) { background: var(--raised); }
.picture.has-image video.day { mix-blend-mode: multiply; }
.picture.has-image video.night { mix-blend-mode: lighten; }
/* A book that opens rises out of its frame at the top (anim.py --headroom).
   Its picture fills the whole tile, so the top of the frame is the tile's top
   edge and the cover lifts out of the tile, not off a cut line in mid-air.
   anim.py puts the shut book in the middle of its frame, and the frame sits
   in the middle of the tile. The frame carries its own margin, so no inset. */
.tile .mount .picture.has-image[data-motion="open"] { inset: 0; }
/* A pan (tiles.js) moves the picture inside its box, measured from the top left. */
.picture.has-image[data-motion="pan"] img { transform-origin: 0 0; will-change: transform; }

/* 12.5 The subscribe block. One form, the tag hardcoded per page
   (06-subscribe-destination/CAPTURE-SPEC.md §2). Ruled like the spec table,
   and the address is written on a line, the way a printed reply card asks
   for it. No mark here: the bar already carries it (Logo.md rule 3). */
.subscribe-block {
  margin: 64px auto 0;
  padding: 26px 0 30px;
  border-top: 2px solid var(--flag);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 8px 48px;
  align-items: end;
}
.subscribe-block { scroll-margin-top: 96px; } /* "Tell me when" jumps here, under the sticky bar */
.subscribe-block > div > h2 { font-size: 28px; color: var(--flag); margin: 0; }
.subscribe-block p { margin-top: 8px; font-size: 17px; }
.subscribe-block form.subscribe { margin-top: 0; }
form.subscribe { display: flex; flex-wrap: wrap; gap: 10px 14px; margin-top: 18px; align-items: end; }
form.subscribe label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%);
}
form.subscribe input[type="email"] {
  flex: 1 1 240px;
  min-width: 0;
  padding: 0.35em 0.1em 0.3em;
  font: 20px/1.3 var(--garamond);
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--ink);
  border-radius: 0;
}
form.subscribe input[type="email"]::placeholder { color: var(--quiet); font-style: italic; opacity: 1; }
form.subscribe input[type="email"]:focus-visible { outline: none; border-bottom: 2px solid var(--actor); margin-bottom: -1px; }
form.subscribe .trap { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
form.subscribe .note {
  flex: 1 0 100%;
  font-family: var(--plex);
  font-size: 12px;
  color: var(--quiet);
}
/* On a prose page the block sits in the one narrow column: stack it. */
.prose .subscribe-block, .narrow .subscribe-block { grid-template-columns: 1fr; }
.prose .subscribe-block form.subscribe { margin-top: 14px; }

/* 12.6 The footer. Small print, the motto, and nothing that asks for a click
   the page has not earned. */
.foot {
  margin-top: 70px;
  border-top: 1px solid var(--tint);
  padding: 22px 0 44px;
  font-family: var(--plex);
  font-size: 13px;
  color: var(--quiet);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  align-items: baseline;
}
.foot a { color: var(--quiet); text-decoration: none; }
.foot a:hover { color: var(--actor-deep); }
.foot .motto { margin-left: auto; font-family: var(--garamond); font-style: italic; }

/* 12.6b The shop: a head like a story page's, then the tiles. */
.shop-head { margin-top: 56px; }
.shop-head .kicker { color: var(--flag); }
.shop-head h1 { margin: 8px 0 14px; font-size: 52px; color: var(--flag); }
.shop-head p { font-size: 19px; }

/* 12.7 Prose pages (about, subscribe). One measure, no grid. */
.prose h1 { color: var(--flag); font-size: 46px; margin-bottom: 18px; }
.prose h2 { font-size: 24px; margin-top: 34px; }
.prose p { font-size: 18px; margin-top: 0.7em; max-width: 34em; }
.prose .kicker { display: block; color: var(--flag); margin-top: 40px; }
.prose ul { margin: 0.7em 0 0 1.1em; }
.prose li { margin-top: 0.35em; font-size: 18px; }

/* 12.8 Narrow */
@media (max-width: 1100px) {
  .head { grid-template-columns: 1fr; gap: 28px; }
  .subscribe-block { grid-template-columns: 1fr; }
  .subscribe-block form.subscribe { margin-top: 14px; }
  .head h1 { font-size: 40px; }
  .grid { grid-template-columns: repeat(4, 1fr); }
  .tile-wide, .tile-third { grid-column: span 2; }
  .tile .mount, .tile-third .mount { height: 240px; }
}
@media (max-width: 720px) {
  .page { padding: 0 20px; }
  /* The bar has to fit a 390 px phone with no horizontal scroll: the lockup
     shrinks, the words go to 12 px, and the button loses its padding. */
  .inner .bar { height: 56px; padding: 0 16px; }
  .inner .bar .brand { height: 22px; }
  .inner .bar .links { gap: 10px; }
  .inner .bar .links a { font-size: 12px; padding: 6px 0; }
  .inner .bar .links .btn { padding: 0.4em 0.7em; font-size: 12px; }
  .head h1 { font-size: 32px; }
  .prose h1 { font-size: 32px; }
  .grid { grid-template-columns: repeat(2, 1fr); }
  .tile-wide, .tile-third { grid-column: span 2; }
  .hero .drawing { max-height: none; }
  .foot .motto { margin-left: 0; flex-basis: 100%; }
}

/* 12.9 The mode button on an inner page rides in the bar, not fixed to the
   corner: at 64 px the bar owns the top right. Same button, same script. */
.inner .mode-toggle {
  position: static;
  width: 34px;
  height: 34px;
  margin-left: 4px;
}
.inner .mode-toggle svg { width: 17px; height: 17px; }
@media (max-width: 720px) {
  .inner .mode-toggle { display: none; } /* a phone follows the system, as on the main page */
}

/* 12.10 The about page. The credo over three drawings that take turns, the
   whole width of the page, then what we believe, how we make things
   (Berkshire as the worked example), and the founder. No drawn frame and no
   second mark (Logo.md rule 3). */
/* The opening. Each drawing keeps its left side empty, and the words sit
   there, in the page's own column. The drawings are toned to the page's
   paper and fade out at the top and bottom edges, so the hero has no box.
   slides.js turns them (Max, 2026-09-25). */
.about-hero { position: relative; margin-top: 12px; }
.about-hero .slides { position: relative; aspect-ratio: 2400 / 1018; }
.about-hero .slide {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  transition: opacity 1400ms ease-in-out;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 90%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 90%, transparent);
}
.about-hero .slide.on { opacity: 1; }
.about-hero .slide img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: right center; }
/* The night drawing fades in over the day one, which never fades: two fades
   at once would let the page show through half way (section 8, the same fix). */
.about-hero .slide .night { opacity: 0; }
:root[data-mode="night"] .about-hero .slide .night { opacity: 1; }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .about-hero .slide .night { opacity: 1; }
}
.about-hero .words { position: absolute; top: 6%; left: 0; right: 0; z-index: 1; }
.about-hero .words > * { max-width: 40%; }
.about-hero .kicker { display: block; color: var(--flag); }
.credo {
  margin-top: 14px;
  font-size: clamp(40px, 4.8vw, 84px);
  line-height: 1.02;
  letter-spacing: -0.012em;
  color: var(--flag);
}
.credo span { display: block; }
.lede {
  margin-top: 22px;
  font-size: clamp(18px, 1.5vw, 23px);
  line-height: 1.45;
}
/* The controls: under the drawing at the right, clear of the line work. */
.slide-nav { display: flex; justify-content: flex-end; align-items: center; gap: 14px; margin-top: 6px; font-family: var(--plex); font-size: 12px; color: var(--quiet); }
.slide-nav[hidden] { display: none; }
.slide-nav .step {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--tone);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
  transition: border-color 180ms ease-out, color 180ms ease-out;
}
.slide-nav .step:hover { border-color: var(--actor); color: var(--actor-deep); }
.slide-nav .step svg { width: 14px; height: 14px; }
.slide-nav .dots { display: flex; gap: 8px; }
.slide-nav .dots button { width: 9px; height: 9px; padding: 0; border-radius: 50%; border: 1px solid var(--tone); background: transparent; cursor: pointer; }
.slide-nav .dots button[aria-current="true"] { background: var(--actor); border-color: var(--actor); }
.slide-nav .count { min-width: 3.2em; text-align: right; }

/* A section's headline, under its kicker rule: one plain sentence in ink. */
.about .section > h2 {
  max-width: 22em;
  font-size: 40px;
  color: var(--ink);
}
.about .section > h2 + p { margin-top: 14px; font-size: 19px; max-width: 36em; }
.about .section { margin-top: 96px; }

/* What we believe: four principles, numbered, each pinned to a fact. */
.beliefs {
  list-style: none;
  counter-reset: belief;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: auto auto auto;
  gap: 0 40px;
  margin-top: 40px;
}
/* Each principle is a column of a subgrid, so the four headlines and the four
   texts start level even when one headline takes two lines. */
.beliefs li {
  counter-increment: belief;
  grid-row: span 3;
  display: grid;
  grid-template-rows: subgrid;
  row-gap: 0;
}
.beliefs li::before {
  content: counter(belief);
  display: block;
  margin-bottom: 12px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--tint);
  font-family: var(--goudy);
  font-size: 64px;
  line-height: 1;
  color: var(--flag);
}
/* When one headline takes two lines, the one-line headlines sit on its last
   line, so every text starts right under its own headline. */
.beliefs h3 { align-self: end; font-size: 26px; color: var(--ink); }
.beliefs p { margin-top: 10px; font-size: 17px; }

/* How we make things: the four steps as a sequence on one line, and under
   them one band of raised paper that runs the Berkshire example through all
   four. Each step is a column of a subgrid, so the four titles, the four
   texts and the four examples line up whatever their length. */
.steps {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: auto auto auto auto;
  column-gap: 0;
  margin-top: 44px;
}
.steps > li {
  grid-row: 1 / span 4;
  display: grid;
  grid-template-rows: subgrid;
  row-gap: 0;
}
/* The line and the band below take rows 1 and 4 across all four columns, so
   auto-placement would push the steps under them: each step names its column. */
.steps > li:nth-child(1) { grid-column: 1; }
.steps > li:nth-child(2) { grid-column: 2; }
.steps > li:nth-child(3) { grid-column: 3; }
.steps > li:nth-child(4) { grid-column: 4; }
.steps > li > * { padding-right: 36px; }
/* the line the four numbers sit on */
.steps::after {
  content: "";
  grid-column: 1 / -1;
  grid-row: 1;
  align-self: center;
  height: 1px;
  margin-left: 17px;
  background: var(--tone);
}
/* the band under the four examples */
.steps::before {
  content: "";
  grid-column: 1 / -1;
  grid-row: 4;
  margin: 0 -24px;
  background: var(--raised);
  border: 1px solid var(--tint);
  border-radius: 3px;
}
.step-num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0 !important;
  border: 1px solid var(--flag);
  border-radius: 50%;
  background: var(--paper);
  color: var(--flag);
  font-family: var(--plex);
  font-feature-settings: "lnum", "tnum";
  font-size: 14px;
  font-weight: 500;
}
.steps h3 { margin-top: 20px; font-size: 24px; color: var(--ink); }
.steps li > p { margin-top: 10px; margin-bottom: 34px; font-size: 17px; }
.steps .example {
  position: relative;
  z-index: 1;
  margin: 0;
  padding-top: 20px;
  padding-bottom: 26px;
  font-size: 17px;
}
.steps .example .kicker {
  display: block;
  margin-bottom: 6px;
  color: var(--flag);
}
/* The band carries one label, over its first column. The others keep the
   line so the four examples start level. */
.steps > li + li .example .kicker { visibility: hidden; }

/* The founder: name on the left, three sentences on the right. */
.founder-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 20px 48px;
  align-items: baseline;
}
.founder-body h2 { font-size: 40px; color: var(--ink); }
.founder-body p { font-size: 20px; line-height: 1.5; max-width: 32em; }

@media (max-width: 1100px) {
  /* Narrower, the words would cover the drawing: they sit above it instead,
     and the drawing shows its right-hand part, where the work is. */
  .about-hero { display: flex; flex-direction: column; }
  .about-hero > .page { width: 100%; } /* a flex item with auto margins would shrink to its text */
  .about-hero .words { position: static; order: -1; margin-top: 24px; }
  .about-hero .words > * { max-width: 36em; }
  .about-hero .slides { aspect-ratio: 16 / 9; margin-top: 8px; }
  .about .section { margin-top: 80px; }
  .about .section > h2, .founder-body h2 { font-size: 34px; }
  .beliefs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 44px 48px; }
  /* Two by two, the one band would break in half: each example takes its
     own raised box and its own label, and the line goes. */
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; column-gap: 48px; row-gap: 48px; }
  .steps > li, .steps > li:nth-child(n) { grid-row: auto; grid-column: auto; display: block; }
  .steps > li > * { padding-right: 0; }
  .steps::before, .steps::after { content: none; }
  .steps li > p { margin-bottom: 0; }
  .steps .example {
    margin-top: 18px;
    padding: 16px 20px 18px;
    background: var(--raised);
    border: 1px solid var(--tint);
    border-radius: 3px;
  }
  .steps > li + li .example .kicker { visibility: visible; }
}

@media (max-width: 720px) {
  .about-hero .slides { aspect-ratio: 4 / 3; }
  .credo { font-size: 42px; }
  .lede { margin-top: 16px; font-size: 19px; }
  .about .section { margin-top: 64px; }
  .about .section > h2, .founder-body h2 { font-size: 30px; }
  .about .section > h2 + p { font-size: 18px; }
  .beliefs { grid-template-columns: 1fr; gap: 36px; margin-top: 28px; }
  .beliefs li::before { font-size: 52px; }
  .steps { grid-template-columns: 1fr; row-gap: 40px; margin-top: 32px; }
  .founder-body { grid-template-columns: 1fr; }
  .founder-body p { font-size: 18px; }
}

/* 12.11 Product pages: one page per physical thing, the book and the poster
   (Max, 2026-09-25). A digital thing links straight to itself and has no page.
   The picture on the left, the cover or the sheet as printed; on the right the title, a short
   description, the ways to buy it and the facts. Under them, the thing's own
   pages or close-ups, each a link to its full-size file. */
.product {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 56px;
  align-items: start;
  margin-top: 40px;
}
.product .kicker { color: var(--flag); text-decoration: none; }
.product .kicker:hover { color: var(--actor-deep); }
.product h1 { margin: 10px 0 16px; font-size: 44px; color: var(--flag); }
.product p { font-size: 18px; }
.product .spec { margin-top: 30px; }
/* The thing is shown flat, as printed, with raised paper round it. */
.product-picture {
  position: sticky;
  top: 96px;
  padding: 32px;
  background: var(--raised);
  border: 1px solid var(--tint);
  border-radius: 3px;
}
.product-picture img { display: block; width: 100%; height: auto; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18); }
/* A cover is portrait: it stands no taller than the window under the bar. */
.product-picture.cover img { width: auto; max-width: 100%; max-height: calc(100vh - 200px); margin: 0 auto; }

/* The ways to buy it: ruled like the spec table, one row per format, the
   button at the end of the row. */
.buy { margin-top: 26px; }
.buy td { vertical-align: middle; padding: 10px 0; }
.buy td:nth-child(2) { color: var(--quiet); padding-right: 14px; }
.buy td:first-child { color: var(--ink); font-weight: 500; }
.buy .btn { min-width: 96px; text-align: center; }

/* The pages: a contact sheet. A page is paper on paper, so it carries a
   hairline and a small shadow to read as a sheet. At night the white is
   brought down a step so it does not glare. */
.shots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 36px 28px; }
.shots.wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.shots figure { margin: 0; }
.shots a { display: block; }
.shots img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--tint);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  transition: border-color 180ms ease-out;
}
.shots a:hover img { border-color: var(--actor); }
.shots figcaption { margin-top: 10px; font-size: 13px; color: var(--quiet); }
:root[data-mode="night"] .shots img, :root[data-mode="night"] .product-picture img { filter: brightness(0.88); }
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="day"]) .shots img,
  :root:not([data-mode="day"]) .product-picture img { filter: brightness(0.88); }
}

@media (max-width: 1100px) {
  .product { grid-template-columns: 1fr; gap: 32px; }
  .product-picture { position: relative; top: auto; }
  .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .product { margin-top: 24px; }
  .product h1 { font-size: 32px; }
  .product-picture { padding: 16px; }
  .shots, .shots.wide { grid-template-columns: 1fr; }
}
