/* /lib/article: the reading layout every article shares.
   A text column with a measure, Tufte-style notes in the right margin on a
   wide screen (folded under their numbers on a phone), figures in the column
   or in the margin where the text refers to them, and the chrome: the
   wordmark as the way back, the language top right, the section dots along
   the bottom. No stage, no steps that scroll past a drawing: this is a page
   you read.

   Layout only. Colours, type scale and spacing tokens come from /style.css;
   nothing here sets a font-size outside that scale. The one colour this adds
   is the marker white, the ground of a plate. A page's own stylesheet comes
   after this one and may override any of it; it adds what is the page's own
   (the essay's kicker wave, a form) and nothing generic.

   Nothing pops in. A figure keeps its box until its drawing is there, a
   picture until it has loaded, and the margin stays out of sight until it
   is placed; then each comes in softly (figures.js, notes.js, motion.js).
   Before the script runs this stylesheet holds them the same way, from the
   first frame, but only where scripting is on, and for 8 s at most: without
   the script, or if it never comes, the page is as it always was. */

:root {
  --essay-w: 64ch;      /* the measure, in the body size */
  --note-w: 16.5rem;    /* the margin column on a wide screen: notes and margin figures */
  --note-gap: 2.25rem;  /* between the text and its margin */
  --mark: #FFFFFF;
  /* what a figure shows while its drawing is on its way: the ink, very
     faint (and the same laid on the paper, as a veil over a drawing) */
  --wash: color-mix(in srgb, var(--ink) 5%, transparent);
  --wash-on-paper: color-mix(in srgb, var(--ink) 5%, var(--paper));
  /* the wordmark's foot: its top, and its height at its width (the svg's box
     is 85.58 × 33.844) */
  --home-foot: calc(clamp(1rem, 2.5vw, 2rem) + clamp(4.5rem, 8vw, 6rem) * 33.844 / 85.58);
  /* where a jump lands: clear of the wordmark and a little more */
  --jump-top: max(clamp(4.5rem, 10vh, 7rem), calc(var(--home-foot) + 1.25rem));
}

/* a reading page: the scrollbar stays (you want to know how long it is),
   and nothing snaps */
html { scrollbar-width: thin; }

/* ---------- the chrome ---------- */

/* a way back, top left: the wordmark, small, over the text's corner */
.home {
  position: fixed;
  top: clamp(1rem, 2.5vw, 2rem);
  left: max(var(--edge), calc((100% - var(--measure)) / 2 + var(--edge)));
  z-index: 6;
  display: block;
  line-height: 0;
}

.home svg {
  display: block;
  width: clamp(4.5rem, 8vw, 6rem);
  height: auto;
  fill: var(--ink);
}

.home:hover svg { fill: var(--ink-muted); }

/* the language, top right, level with the wordmark, one asterisk in from the
   edge; the asterisk (/style.css) takes the corner, pinned with it */
.aibadge { position: fixed; }

.langtoggle {
  position: fixed;
  top: max(clamp(1rem, 2.5vw, 2rem), env(safe-area-inset-top));
  right: calc(max(var(--edge), calc((100% - var(--measure)) / 2 + var(--edge))) + var(--aibadge) + var(--aibadge-gap));
  z-index: 6;
}

/* the fixed chrome sits over scrolling text: a paper halo, so a line slides
   out from under it instead of colliding */
.home,
.langtoggle {
  background: var(--paper);
  border-radius: 2px;
  box-shadow: 0 0 0 0.4rem var(--paper), 0 0 1rem 0.9rem var(--paper);
}

/* the name never breaks across lines */
.nowrap { white-space: nowrap; }

/* ---------- the page ---------- */

.guide--text {
  display: block;
  max-width: var(--measure);
  margin-inline: auto;
  padding: clamp(7rem, 14vh, 10rem) var(--edge) clamp(7rem, 12vh, 9rem);
}

.essay { position: relative; }

/* room under the text for a note or a figure that hangs below its end
   (notes.js sets --margin-room; the text's own height is what is left) */
.essay::after {
  content: "";
  display: block;
  height: var(--margin-room, 0px);
}

/* anything a link can jump to lands clear of the wordmark */
.essay [id] { scroll-margin-top: var(--jump-top); }

/* the body size; every classed line below (kicker, dateline, notes, captions)
   overrides it at the same weight */
.essay :where(p, li) {
  font-size: var(--t-base);
  line-height: 1.55;
}

/* ---------- the head: an optional kicker, the title, the dateline ---------- */

.essay__head {
  max-width: var(--essay-w);
  margin: 0 0 clamp(3rem, 7vh, 5rem);
}

.essay__kicker {
  margin: 0;
  font-size: var(--t-display);
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.essay__title {
  margin: 0;
  font-size: var(--t-action);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.015em;
}

.essay__kicker + .essay__title { margin-top: 0.35em; }

.essay__dateline,
.essay__lang {
  margin: 0;
  font-size: var(--t-meta);
  color: var(--ink-muted);
}

.essay__dateline { margin-top: 1em; }
.essay__lang { margin-top: 0.3em; }
.essay__lang[hidden] { display: none; }

/* a standfirst, if the piece has one: the angle in one line, intro size */
.essay__standfirst {
  margin: 1em 0 0;
  font-size: var(--t-intro);
  line-height: 1.3;
  letter-spacing: -0.005em;
}

/* ---------- the sections ---------- */
/* separated by space, no rules */

.essay__section {
  position: relative;
  max-width: var(--essay-w);
  margin-top: clamp(2.75rem, 7vh, 4.5rem);
  scroll-margin-top: var(--jump-top);
}

.essay__head + .essay__section { margin-top: 0; }

/* the driver's step: an empty overlay over the section, which it observes
   and labels (page.js makes one per section); the text beside it is never
   touched */
.essay__section > .step {
  position: absolute;
  inset: 0;
  display: block;
  min-height: 0;
  padding: 0;
  pointer-events: none;
  scroll-margin-top: var(--jump-top); /* a hash lands here: clear of the wordmark */
}

.essay h2 {
  margin: 0 0 1em;
  font-size: var(--t-intro);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.015em;
}

/* a paragraph's space above it is its own (a note or a figure may sit
   between two in the markup), none for the first thing in a section */
.essay__section > :where(p, ul, ol, .fig, .ritual) { margin-top: 1em; }
.essay__section > :where(.step, h2) + :where(p, ul, ol) { margin-top: 0; }
.essay__section > .fig { margin-top: 1.5em; }
.essay__section > .fig + :where(p, ul, ol) { margin-top: 1.5em; }

/* quotations and the like: set in from the margin */
.essay__list,
.essay__chant { padding-left: 1.5em; }

.essay__section > .essay__chant + .essay__chant { margin-top: 0.35em; }

.essay__muted { color: var(--ink-muted); }

/* bullets and numbered lists, plainly */
.essay__bullets {
  margin: 0;
  padding: 0 0 0 1.3em;
  list-style: none;
}

.essay__bullets li { position: relative; }

.essay__bullets li::before {
  content: "–";
  position: absolute;
  left: -1.3em;
  color: var(--ink-muted);
}

.essay__bullets li + li { margin-top: 0.35em; }

.essay__steps {
  margin: 0;
  padding: 0 0 0 1.6em;
  list-style: decimal;
}

.essay__steps li + li { margin-top: 0.5em; }
.essay__steps li::marker { color: var(--ink-muted); }
.essay__steps .essay__bullets { margin-top: 0.35em; }

.essay__section > .essay__muted + :where(ul, ol) { margin-top: 0.5em; }

/* ---------- the notes ---------- */
/* A reference is a small raised number; the note itself follows the
   paragraph in the page. Wide: the note stands in the right margin, level
   with its number (notes.js places it; before the script runs, or without
   it, it floats there approximately). Narrow: it folds under its number and
   a tap opens it below the paragraph; without the script it is simply there. */

.fn {
  position: relative;
  top: -0.45em;
  font-size: var(--t-meta);
  line-height: 0;
  vertical-align: baseline;
}

.fn a {
  padding: 0.3em 0.3em;   /* a finger's worth */
  margin: -0.3em -0.2em;
  color: var(--ink-muted);
  text-decoration: none;
}

.fn a:hover,
.fn a:focus-visible,
.fn a[aria-expanded="true"],
.fn a.is-lit {
  color: var(--ink);
  text-decoration: underline;
}

.note {
  position: relative;
  margin: 0.9em 0 0;
  padding-left: 1.5em;
  font-size: var(--t-meta);
  line-height: 1.4;
  color: var(--ink);
}

.note:focus { outline: none; }

/* the number hangs in front of the note, and is the way back */
.note .note__num {
  position: absolute;
  left: 0;
  color: var(--ink-muted);
  text-decoration: none;
}

.note .note__num:hover { color: var(--ink); }

/* a note just pointed at: a thin ink rule beside it for a moment. A section
   a link has just landed on gets the same rule beside its heading; a
   reference landed on is inked and underlined, as under the pointer, and a
   figure's caption is inked (page.js, motion.js) */
.note::before,
.essay__section:has(> h2)::before {
  content: "";
  position: absolute;
  left: -0.9rem;
  top: 0.2em;
  bottom: 0.2em;
  width: 1.5px;
  background: var(--ink);
  opacity: 0;
  transition: opacity 400ms;
  pointer-events: none;
}

/* the section's rule stands beside its heading's first line (the heading
   opens the section; the section is positioned already, the heading is not) */
.essay__section:has(> h2)::before {
  top: calc(var(--t-intro) * 0.2);
  bottom: auto;
  height: calc(var(--t-intro) * 0.8);
}

.note.is-lit::before,
.note:focus-visible::before,
.essay__section.is-lit::before { opacity: 1; }

/* folded (the script sets is-folding on narrow screens) */
.essay.is-folding .note { display: none; }
.essay.is-folding .note.is-open { display: block; }

/* ---------- figures ---------- */
/* A figure sits where the text refers to it: in the column (.fig--wide) or
   in the margin beside the paragraph before it (.fig--margin; inline below
   that paragraph on a narrow screen). The caption is the muted meta size.
   What a figure holds: a canvas (a drawing from numbers), an svg (a
   diagram), one picture (.fig--plate) or two (.fig--pair). */

.fig {
  margin: 0;
  max-width: var(--essay-w);
  --fig-ratio: 4 / 3;
}

.fig--wide { width: 100%; }

.fig figcaption {
  margin-top: 0.6em;
  max-width: 46ch;
  font-size: var(--t-meta);
  line-height: 1.4;
  color: var(--ink-muted);
  transition: color 400ms;
}

/* a figure a link has just landed on: its caption inked for a moment */
.fig.is-lit > figcaption { color: var(--ink); }

.fig canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: var(--fig-ratio);
}

.fig--margin { --fig-ratio: 1; }

.fig .fig__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* the ink line and the paper fill, for diagrams drawn as svg */
.fig .fig__svg .ink { fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.fig .fig__svg .ghost { fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-dasharray: 4 4; stroke-linejoin: round; }
.fig .fig__svg .fill { fill: var(--paper); }
.fig .fig__svg .tone { fill: rgba(26, 26, 26, 0.22); }
.fig .fig__svg .white { fill: var(--mark); }
.fig .fig__svg text {
  font-family: "Strawford", system-ui, sans-serif;
  font-size: var(--t-meta);
  fill: var(--ink);
}
.fig .fig__svg text.muted { fill: var(--ink-muted); }

.fig img {
  display: block;
  width: 100%;
  height: auto;
  border: 1.5px solid var(--ink);
  background: var(--mark);
}

.fig__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  align-items: start;
}

.fig__pair > div { display: grid; gap: 0.35rem; }

/* "before" and "after", only where the caption doesn't say */
.fig__word {
  font-size: var(--t-meta);
  color: var(--ink-muted);
}

@media (max-width: 720px) {
  .fig__pair { grid-template-columns: 1fr; }
}

/* ---------- waiting, and arriving ---------- */
/* Until its drawing is there, a figure keeps the box the drawing will fill,
   washed faintly with ink (figures.js sets is-waiting). The box is the
   figure's --fig-ratio: 4:3 in the column and 1:1 in the margin unless the
   page writes another on the figure or its renderer declares one; data-w
   and data-h on the figure give it exactly, where the browser reads them.
   A canvas that hasn't drawn yet and a picture on its way show the same
   wash in their own box, the picture's pixels kept out of sight until it is
   in. Then the wash lifts off the drawing (is-arriving), and the figure is
   as it always was. */

.essay .fig.is-waiting:not(:has(> :not(figcaption, noscript)))::before {
  content: "";
  display: block;
  aspect-ratio: var(--fig-ratio);
  background: var(--wash);
}

.essay .fig.is-waiting > canvas { background: var(--wash); }

.essay .fig img.is-waiting {
  object-position: -200vw 0;
  background-color: var(--wash);
  border-color: transparent;
}

@supports (aspect-ratio: attr(data-w type(<number>)) / attr(data-h type(<number>))) {
  .essay figure.fig[data-w][data-h]::before { aspect-ratio: attr(data-w type(<number>)) / attr(data-h type(<number>)); }
}

/* in: the wash it waited behind lies over it as a veil and lifts (its own
   outline, drawn inward over the whole box; motion.js sizes it). The
   drawing itself is never faded, so it is drawn exactly as it always was */
.essay .fig .is-arriving {
  outline: var(--veil, 0px) solid transparent;
  outline-offset: calc(-1 * var(--veil, 0px));
  animation: article-veil 200ms ease-out;
}

@keyframes article-veil {
  from { outline-color: var(--wash-on-paper); }
}

/* the margin, shown once it is placed: from nothing */
.essay.is-revealing .note,
.essay.is-revealing .fig--margin { animation: article-in 200ms ease-out; }

@keyframes article-in {
  from { opacity: 0; }
}

/* ---------- the end ---------- */

.essay__end {
  display: grid;
  gap: 0.5em;
  margin-top: clamp(3.5rem, 8vh, 6rem);
  max-width: var(--essay-w);
}

.essay__end p { margin: 0; }
.essay__end .more { font-size: var(--t-base); }
.essay__end .back { font-size: var(--t-meta); color: var(--ink-muted); }

/* ---------- the section dots ---------- */
/* The front page's wave, as one ink dot per section along its centre line.
   The current one is bigger, its name beside it. The path itself is
   invisible; the driver lays the dots along it. The text column is on the
   left, so the menu keeps the phone's treatment at every width: a paper
   fade along the bottom, the dots at the text's edge. */

.stepnav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 0.8em;
  padding: 0.7rem var(--edge) max(0.8rem, env(safe-area-inset-bottom))
    max(var(--edge), calc((100% - var(--measure)) / 2 + var(--edge)));
  font-size: var(--t-meta);
  color: var(--ink-muted);
  background: linear-gradient(to top, var(--paper) 70%, transparent);
}

.stepnav svg {
  display: block;
  width: clamp(6rem, 26vw, 8rem);
  height: auto;
  overflow: visible;
  flex: none;
  touch-action: none; /* a drag along the dots scrubs sections, it doesn't scroll the page */
}

.stepnav .ribbon { fill: none; stroke: none; }

.stepnav a { cursor: pointer; }

.stepnav a circle {
  fill: var(--ink);
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0.5);
  transition: transform 160ms;
}

.stepnav a:hover circle { transform: scale(0.73); }

.stepnav a[aria-current] circle { transform: scale(1); }

/* the hit circle: unpainted but hit-tested, three dots wide */
.stepnav a circle.hit { fill: transparent; transform: none; transition: none; }

.stepnav__label { white-space: nowrap; }

/* ---------- wide: the margin ---------- */

@media (min-width: 1100px) {
  .note,
  .fig--margin {
    float: right;
    clear: right;
    width: var(--note-w);
    margin: 0 calc(-1 * (var(--note-w) + var(--note-gap))) 0.9em 0;
  }

  .note { padding-left: 0; }

  .note .note__num {
    position: static;
    margin-right: 0.35em;
  }

  /* placed by the script: level with the number (a note) or with the
     paragraph before it (a figure), pushed down past whatever sits above */
  .essay.is-placed .note,
  .essay.is-placed .fig--margin {
    float: none;
    position: absolute;
    left: calc(100% + var(--note-gap));
    top: var(--top, 0px);
    margin: 0;
  }

  /* out of sight until notes.js has placed it once, with the text in its
     own font; then it fades in where it belongs, never seen jumping there */
  .essay.is-held .note,
  .essay.is-held .fig--margin { opacity: 0; }
}

/* ---------- before the script ---------- */
/* The holds above start with the first frame, before the script has the
   page (page.js sets is-mounted on the article), but only where scripting
   is on: an empty figure keeps its box, a picture keeps its pixels out of
   sight, and on a wide screen the margin waits to be placed. Each hold is an
   animation of 8 s that ends by itself, so if the script never comes the
   page is simply as it is without one. */

@media (scripting: enabled) {
  .essay:not(.is-mounted) figure[data-fig]:not(:has(> :not(figcaption, noscript)))::before {
    content: "";
    display: block;
    width: 0;
    aspect-ratio: var(--fig-ratio);
    animation: article-hold-box 8s;
  }

  .essay:not(.is-mounted) .fig img { animation: article-hold-picture 8s; }
}

@media (scripting: enabled) and (min-width: 1100px) {
  .essay:not(.is-mounted) .note,
  .essay:not(.is-mounted) .fig--margin { animation: article-hold-margin 8s; }
}

/* on a narrow screen the notes are folded from the first frame, as the
   script will fold them, so the text doesn't close up under the reader */
@media (scripting: enabled) and (width < 1100px) {
  .essay:not(.is-mounted) .note { animation: article-hold-fold 8s; }
}

@keyframes article-hold-fold {
  from, to { display: none; }
}

@keyframes article-hold-box {
  from, to { width: 100%; background-color: var(--wash); }
}

@keyframes article-hold-picture {
  from, to { object-position: -200vw 0; background-color: var(--wash); border-color: transparent; }
}

@keyframes article-hold-margin {
  from, to { opacity: 0; }
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .note::before,
  .essay__section::before,
  .fig figcaption { transition: none; }
  .stepnav a circle { transition: none; }
  .essay .fig .is-arriving,
  .essay.is-revealing .note,
  .essay.is-revealing .fig--margin { animation: none; }
}

/* ---------- the og picture (?view=step&og): the head alone, 1200 x 630 ---------- */
/* a card, not a reading viewport: the root is zoomed so the scale's top
   steps land at card size (the way tools/og.html sets its own sizes) */

html.og { font-size: 125%; }

html.og body {
  position: relative; /* the head is placed against the card, not the article */
  width: 1200px;
  height: 630px;
  overflow: hidden;
}

html.og .guide--text { padding: 0; max-width: none; }
html.og .essay { position: static; }

html.og .essay__section,
html.og .essay__end,
html.og .essay__lang,
html.og .stepnav,
html.og .langtoggle { display: none; }

html.og .home {
  position: absolute;
  top: 72px;
  left: 80px;
  box-shadow: none;
}

html.og .home svg { width: 190px; }

html.og .essay__head {
  position: absolute;
  left: 80px;
  right: 80px;
  top: 54%;
  margin: 0;
  max-width: none;
  transform: translateY(-50%);
}

html.og .essay__standfirst { display: none; }
