/* ===========================================================================
   SITE — structure only.
   ---------------------------------------------------------------------------
   This file declares no colour, font family, or size of its own. Every visual
   value is a token from theme.css. If you want to change how the site looks,
   edit theme.css instead; this file decides where things sit.
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--weight-body);
  line-height: var(--leading-body);
  font-feature-settings: 'kern' 1, 'liga' 1, 'onum' 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--selection); }

img { max-width: 100%; height: auto; display: block; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--space-2) var(--space-3);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-util);
  font-size: var(--step--1);
  border: 1px solid var(--rule);
}
.skip:focus { left: var(--space-3); top: var(--space-3); }


/* ---------------------------------------------------------------------------
   Column grid
   Five tracks. Prose sits in `text`; quotes and comparisons widen to `wide`;
   openers and the masthead run `full`. Nothing needs a wrapper div.
   ------------------------------------------------------------------------ */

.masthead,
main > section,
.colophon {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [wide-start]  minmax(0, calc((var(--measure-wide) - var(--measure)) / 2))
    [text-start]  min(var(--measure), 100% - (var(--gutter) * 2))
    [text-end]    minmax(0, calc((var(--measure-wide) - var(--measure)) / 2))
    [wide-end]    minmax(var(--gutter), 1fr)
    [full-end];
}

main > section > *          { grid-column: text; }
main > section > .opener    { grid-column: full; }
main > section > .pull,
main > section > .triptych,
main > section > .comparison,
main > section > .figure    { grid-column: wide; }

main > section {
  background: var(--bg);
  color: var(--fg);
  padding-bottom: var(--section-gap);
  row-gap: 0;
  transition: background-color var(--dur-calm) var(--ease);
}


/* ---------------------------------------------------------------------------
   Masthead
   ------------------------------------------------------------------------ */

/* Two behaviours. With a hero image the title sits on it, bottom-aligned and
   full height. With a placeholder the two stack, because overlaying a title on
   a labelled frame makes both unreadable. */
.masthead {
  position: relative;
  align-content: start;
  padding-bottom: var(--space-6);
  isolation: isolate;
  overflow: hidden;
}

.masthead:has(.masthead-art img) {
  min-height: min(88vh, 46rem);
  align-content: end;
}

.masthead-art {
  grid-column: full;
  grid-row: 1;
  align-self: stretch;
  position: relative;
  z-index: 0;
}

.masthead-body {
  grid-row: 2;
}

.masthead-art:has(img) ~ .masthead-body {
  grid-row: 1;
  align-self: end;
}

.masthead-art img,
.opener-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--img-treatment);
}

.masthead-art::after,
.opener-art::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgb(0 0 0 / calc(var(--opener-scrim) + 0.22)) 0%,
    rgb(0 0 0 / var(--opener-scrim)) 45%,
    rgb(0 0 0 / calc(var(--opener-scrim) * 0.35)) 100%);
  pointer-events: none;
}

/* No scrim while the slot is still a placeholder — it needs to stay readable. */
.masthead-art:has(.slot)::after,
.opener-art:has(.slot)::after { display: none; }

.masthead-body {
  grid-column: text;
  z-index: 1;
  padding-top: var(--space-5);
}

/* When the hero image is present the title sits on it and needs light text. */
.masthead-art:has(img) ~ .masthead-body { --fg: var(--chalk); color: var(--chalk); }
.masthead-art:has(img) ~ .masthead-body .byline { color: var(--chalk); opacity: 0.72; }

.masthead h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: var(--weight-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--track-tight);
  text-wrap: balance;
}

.byline {
  margin: var(--space-3) 0 0;
  font-family: var(--font-util);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--fg-faint);
}


/* ---------------------------------------------------------------------------
   The vantage rail — signature element.

   The essay's argument is about scale of view: zoomed in is nail guns and
   Hardie board, zoomed out is shaping the face of a planet. The rail keeps the
   reader's current vantage visible, and its labels come from what each section
   is actually looking at — Planet, Stroad, Town, Market, Child, Work.
   ------------------------------------------------------------------------ */

.rail {
  position: fixed;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 20;
  padding: var(--space-3) var(--space-3) var(--space-3) var(--gutter);
  font-family: var(--font-util);
  font-size: var(--step--1);
  pointer-events: none;
}

.rail ol {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-2);
}

.rail li {
  display: grid;
  grid-template-columns: 2.4rem auto;
  align-items: center;
  gap: var(--space-2);
  color: var(--fg-faint);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  opacity: 0.5;
  transition: opacity var(--dur-calm) var(--ease),
              color var(--dur-calm) var(--ease);
}

/* The tick. Grows and takes the accent when its section is in view. */
.rail .tick {
  height: 1px;
  width: 1.1rem;
  background: currentColor;
  transition: width var(--dur-calm) var(--ease),
              background-color var(--dur-calm) var(--ease);
  justify-self: end;
}

.rail .label {
  white-space: nowrap;
  opacity: 0;
  transform: translateX(-0.35rem);
  transition: opacity var(--dur-calm) var(--ease),
              transform var(--dur-calm) var(--ease);
  /* The rail is navigation, so its labels are anchors. They must not inherit
     the browser's default link styling. */
  color: inherit;
  text-decoration: none;
  pointer-events: auto;
}

.rail .label:hover { text-decoration: underline; text-underline-offset: 0.25em; }
.rail .label:focus-visible { outline-offset: 2px; }

.rail li[aria-current='true'] {
  opacity: 1;
  color: var(--accent);
}
.rail li[aria-current='true'] .tick { width: 2.4rem; }
.rail li[aria-current='true'] .label { opacity: 1; transform: none; }

/* Hovering anywhere near the rail reveals every label. */
.rail:hover li { opacity: 0.85; }
.rail:hover .label { opacity: 0.8; transform: none; }

/* Narrow screens: collapse to a single quiet marker, bottom left. */
@media (max-width: 71rem) {
  .rail {
    top: auto;
    bottom: 0;
    transform: none;
    padding: var(--space-2) var(--space-3);
    background: var(--bg);
    border-top: 1px solid var(--rule-hair);
    width: 100%;
  }
  .rail ol { grid-auto-flow: column; justify-content: start; gap: var(--space-3); }
  .rail li { grid-template-columns: auto; }
  .rail .tick { width: 0.9rem; justify-self: start; }
  .rail li[aria-current='true'] .tick { width: 1.6rem; }
  .rail .label { display: none; }
  .rail li[aria-current='true'] .label { display: block; opacity: 1; }
  main { padding-bottom: 3rem; }
}


/* ---------------------------------------------------------------------------
   Section openers
   ------------------------------------------------------------------------ */

.opener {
  position: relative;
  display: grid;
  min-height: var(--opener-height);
  align-content: end;
  isolation: isolate;
  overflow: hidden;
  margin-bottom: var(--space-6);
}

.opener-art {
  grid-area: 1 / 1;
  position: relative;
  width: 100%;
  height: 100%;
  min-height: var(--opener-height);
}

.opener-body {
  grid-area: 1 / 1;
  align-self: end;
  z-index: 1;
  width: min(var(--measure-wide), 100% - (var(--gutter) * 2));
  margin: 0 auto;
  padding: var(--space-6) 0 var(--space-5);
}

.opener-art:has(img) ~ .opener-body,
.opener-art:has(img) ~ .opener-body * { color: var(--chalk); }

/* A section with no image slot — the Action Plan is a list of actions, not a
   picture. Typographic opener, no reserved image height. */
.opener.no-art {
  min-height: 0;
  margin-bottom: var(--space-5);
}
.opener.no-art .opener-body {
  padding: var(--space-5) 0 0;
  border-top: 1px solid var(--rule);
}

.opener-vantage {
  display: block;
  font-family: var(--font-util);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--space-2);
}

.opener-num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--weight-body);
  font-variant-numeric: oldstyle-nums;
  line-height: 1;
  opacity: 0.55;
  margin-bottom: var(--space-1);
}

.opener h2,
h2.plain {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: var(--weight-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--track-tight);
  text-wrap: balance;
}

.opener-lede {
  margin: var(--space-3) 0 0;
  max-width: 44ch;
  font-size: var(--step-1);
  line-height: var(--leading-snug);
  font-style: italic;
  opacity: 0.9;
}


/* ---------------------------------------------------------------------------
   Prose
   ------------------------------------------------------------------------ */

main p {
  margin: 0 0 var(--para-gap);
  hanging-punctuation: first last;
}

main p:last-child { margin-bottom: 0; }

/* The document uses runs of literal spaces for emphasis — "think  deeply",
   "one message  |  or the other". Preserve them exactly as typed rather than
   substituting a guess at the intent. */
.as-typed { white-space: pre-wrap; }

h3 {
  margin: var(--space-5) 0 var(--space-3);
  font-family: var(--font-util);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
}

.aside {
  margin: var(--space-4) 0;
  padding-left: var(--space-4);
  border-left: 1px solid var(--rule);
  font-size: calc(var(--step-0) * 0.94);
  color: var(--fg-quiet);
}

/* Short-line blocks that read as verse in the original. */
.verse {
  display: grid;
  margin: var(--space-4) 0;
  line-height: var(--leading-verse);
}
.verse-line { display: block; }
.verse-line:empty { display: none; }

ol.enumerated {
  margin: var(--space-4) 0;
  padding: 0;
  list-style: none;
  counter-reset: item;
  display: grid;
  gap: var(--space-3);
}

ol.enumerated > li {
  counter-increment: item;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: var(--space-2);
}

ol.enumerated > li::before {
  content: counter(item);
  font-family: var(--font-util);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-label);
  color: var(--accent);
  padding-top: 0.35em;
}


/* ---------------------------------------------------------------------------
   Pull quotes
   ------------------------------------------------------------------------ */

.pull {
  margin: var(--space-6) 0;
  padding: 0;
  border: 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.pull p {
  margin: var(--space-4) 0;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--weight-body);
  font-style: italic;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-tight);
  text-wrap: balance;
}


/* ---------------------------------------------------------------------------
   The forme — the Genesis line at the bottom of the zoom.
   The one place Cardo appears, and the one place the page goes quiet.
   ------------------------------------------------------------------------ */

.forme {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-5) 0;
  padding: var(--space-5) var(--space-4);
  background: var(--bg-raised);
  border-top: 2px solid var(--fg);
  border-bottom: 2px solid var(--fg);
  text-align: center;
}

.forme-line {
  font-family: var(--font-forme);
  font-size: var(--step-1);
  line-height: var(--leading-snug);
  text-wrap: balance;
}

.forme-la { letter-spacing: 0.015em; }
.forme-en { font-style: italic; color: var(--fg-quiet); font-size: var(--step-0); }


/* ---------------------------------------------------------------------------
   Figures and image slots
   ------------------------------------------------------------------------ */

.inline-figure,
.figure {
  margin: var(--block-gap) 0;
}

.inline-figure img,
.figure img,
.cell img {
  width: 100%;
  filter: var(--img-treatment);
  border-radius: var(--img-radius);
}

figcaption {
  margin-top: var(--space-2);
  font-family: var(--font-util);
  font-size: var(--step--1);
  line-height: 1.45;
  color: var(--fg-faint);
}

.triptych,
.comparison {
  margin: var(--block-gap) 0;
  display: grid;
  gap: var(--space-3);
}
.triptych  { grid-template-columns: repeat(3, 1fr); }
.comparison { grid-template-columns: repeat(2, 1fr); }

.cell { margin: 0; }

@media (max-width: 44rem) {
  .triptych, .comparison { grid-template-columns: 1fr; }
}

/* Placeholder frames. Self-documenting: an empty site is still presentable,
   and it says exactly what belongs where. */
/* A placeholder has to read as a placeholder. Dashed, tinted, and centred so
   it never gets mistaken for finished design or collides with the rail. */
.slot {
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: clamp(var(--space-2), 3vw, var(--space-4));
  aspect-ratio: 21 / 9;
  background: var(--bg-raised);
  border: 1px dashed var(--rule);
  color: var(--fg-quiet);
  /* A grid item must be allowed to shrink below its content width, or a long
     subject line forces the whole document wider than the viewport. */
  min-width: 0;
  overflow-wrap: break-word;
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 14px,
    var(--rule-hair) 14px 15px);
}

.slot[data-ratio='3x2'] { aspect-ratio: 3 / 2; }
.slot[data-ratio='4x3'] { aspect-ratio: 4 / 3; }
.slot[data-ratio='3x4'] { aspect-ratio: 3 / 4; }

.slot-name {
  font-family: var(--font-util);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
}

.slot-subject {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-snug);
  max-width: min(40ch, 100%);
}

.slot-hint {
  font-family: var(--font-util);
  font-size: var(--step--2);
  color: var(--fg-faint);
  letter-spacing: 0.02em;
}

.slot code {
  font-family: var(--font-util);
  font-size: inherit;
  padding: 0.1em 0.3em;
  background: var(--bg);
  border: 1px solid var(--rule-hair);
}

/* An opener whose image has not landed yet still needs to hold its height. */
.opener-art .slot,
.masthead-art .slot {
  aspect-ratio: auto;
  height: 100%;
  min-height: var(--opener-height);
  border-left: 0;
  border-right: 0;
}
.opener-art:has(.slot) ~ .opener-body { padding-top: var(--space-4); }

/* Keep the hero placeholder's label clear of the reading column and the rail. */
.masthead-art .slot { min-height: 0; }
.masthead-art .slot .slot-subject { max-width: min(34ch, 100%); }

/* The slot hint names a filename and can't wrap mid-token; let it shrink. */
.slot-hint { max-width: 100%; overflow-wrap: break-word; }


/* ---------------------------------------------------------------------------
   Colophon
   ------------------------------------------------------------------------ */

.colophon {
  padding: var(--space-5) 0 var(--space-6);
  border-top: 1px solid var(--rule-hair);
  font-family: var(--font-util);
  font-size: var(--step--1);
  color: var(--fg-faint);
}
.colophon > * { grid-column: text; margin: 0 0 var(--space-1); }
.colophon-note { opacity: 0.75; }


/* ---------------------------------------------------------------------------
   Motion — one scroll reveal for openers, nothing else.
   ------------------------------------------------------------------------ */

.opener-body > * {
  opacity: 0;
  transform: translateY(0.6rem);
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease);
}
.opener.seen .opener-body > * { opacity: 1; transform: none; }
.opener.seen .opener-body > *:nth-child(2) { transition-delay: 70ms; }
.opener.seen .opener-body > *:nth-child(3) { transition-delay: 140ms; }
.opener.seen .opener-body > *:nth-child(4) { transition-delay: 210ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  .opener-body > * { opacity: 1; transform: none; }
}


/* ---------------------------------------------------------------------------
   Print — someone will want this on paper.
   ------------------------------------------------------------------------ */

@media print {
  .rail, .skip { display: none; }
  body { background: var(--print-bg); color: var(--print-fg); }
  main > section { padding-bottom: var(--space-5); }
  .opener { min-height: 0; page-break-after: avoid; }
  .opener-art { display: none; }
  .opener-body > * { opacity: 1; transform: none; }
  .pull, .forme, .figure, .triptych, .comparison { page-break-inside: avoid; }
}
