/* ============================================================
   BLOG POST LAYOUT

   Loaded after main.css, which supplies the tokens, @font-face,
   reset, .grain and the masthead. Only what the post adds lives
   here.

   Three columns on the shared 1440u canvas:
     contents 0-300u | prose 300-1050u | margin 1050-1200u
   The margin column is deliberately narrow -- it parks figures and
   holds footnotes; figures are read in the prose, not in it. The
   block still ends at 1200u so it matches the home grid's right
   margin instead of stranding bare page beside the column.
   Geometry is held in custom properties on .article so the
   collapse can move all four edges at once. Properties that
   READ those vars still transition when the vars change, which
   is what animates the collapse.
   ============================================================ */



/* ----------------------------------------------------------
   POST HEADER
   ---------------------------------------------------------- */
.post-head{
  padding: calc(56 * var(--u)) calc(56 * var(--u)) calc(48 * var(--u));
  max-width: calc(1200 * var(--u));
}

.post-title{
  font-size: calc(66 * var(--u));
  line-height: 1.05;
  font-weight: 400;
  margin: 0 0 calc(28 * var(--u));
}

.post-standfirst{
  font-size: calc(26 * var(--u));
  line-height: 1.45;
  margin: 0 0 calc(36 * var(--u));
  max-width: calc(820 * var(--u));
}

/* Placeholder copy reads as provisional rather than as content */
.post-standfirst--placeholder{
  opacity: .45;
  font-style: italic;
}

.post-byline,
.post-date{
  font-size: calc(19 * var(--u));
  line-height: 1.5;
  margin: 0;
}
.post-date{ color: var(--ink-soft); }

/* Acknowledgements: credit rather than copy, so it sits under the byline at a
   smaller size in secondary ink instead of opening the article. */
.post-ack{
  font-size: calc(14 * var(--u));
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: calc(1120 * var(--u));
  margin: calc(34 * var(--u)) 0 0;
}

/* ----------------------------------------------------------
   ARTICLE SHELL
   ---------------------------------------------------------- */
.article{
  position: relative;
  width: calc(1200 * var(--u));

  /* expanded geometry */
  --toc-w:   calc(300 * var(--u));
  --prose-l: calc(300 * var(--u));
  --prose-w: calc(750 * var(--u));
  --marg-l:  calc(1050 * var(--u));
  --marg-w:  calc(150 * var(--u));
}

/* Collapsed: the contents narrows to fit its section names, and
   the prose slides left into the space, gaining a little measure.
   The margin column keeps its width in both states so a landed
   figure's reserved slot can never change height. */
/* The measure is deliberately identical to the expanded state: only the
   left edge moves. Widening it on collapse reflowed every line mid-scroll,
   which moved whatever you had just jumped to and jittered the text as the
   contents opened and closed. */
/* No figures and no footnotes: nothing to put in the margin, so the column
   goes rather than sitting there labelled and empty. The measure is unchanged,
   so the reading experience matches the other posts; the freed width simply
   becomes page margin until figures arrive. */
.article--no-margin{
  width: calc(1050 * var(--u));
}

.article.toc-collapsed{
  --toc-w:   calc(176 * var(--u));
  --prose-l: calc(176 * var(--u));
  --prose-w: calc(750 * var(--u));
  --marg-l:  calc(926 * var(--u));
  --marg-w:  calc(150 * var(--u));
}

/* Section rule spans the viewport, matching the home page rather
   than stopping at the 1200u column block. */
.article::before{
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100vw;
  height: calc(1.5 * var(--u));
  background: var(--line);
  opacity: .82;
  z-index: 2;
}

/* Column dividers, echoing the home grid */
.article__rule{
  position: absolute;
  top: 0;
  bottom: 0;
  width: calc(1.5 * var(--u));
  background: var(--line);
  opacity: .82;
  z-index: 2;
  transition: left .45s ease;
}
.article__rule--1{ left: var(--toc-w); }
.article__rule--2{ left: var(--marg-l); }

/* ----------------------------------------------------------
   PROSE
   Stays in normal flow: it is what gives .article its height,
   so the absolutely positioned columns have something to span.
   ---------------------------------------------------------- */
.prose{
  margin-left: var(--prose-l);
  width: var(--prose-w);
  padding: calc(30 * var(--u)) calc(24 * var(--u)) calc(140 * var(--u));
  font-size: calc(20 * var(--u));
  line-height: 1.6;
  transition: margin-left .45s ease, width .45s ease;
}

.prose h2{
  font-size: calc(30 * var(--u));
  line-height: 1.25;
  font-weight: 400;
  margin: calc(56 * var(--u)) 0 calc(20 * var(--u));
}

/* Contents links target the section, not the heading, so the offset
   has to live here -- otherwise the jump puts the section's top edge
   at the viewport top and the sticky header hides the heading. */
.prose section[id]{
  scroll-margin-top: calc(130 * var(--u));
}
.prose section:first-child h2{ margin-top: 0; }

/* Subheads inside a section, for posts whose contents sits at h2 */
.prose h3{
  font-size: calc(22 * var(--u));
  line-height: 1.3;
  font-weight: 400;
  font-style: italic;
  margin: calc(34 * var(--u)) 0 calc(14 * var(--u));
}

.prose p{ margin: 0 0 calc(20 * var(--u)); }

.prose blockquote{
  margin: 0 0 calc(22 * var(--u));
  padding-left: calc(18 * var(--u));
  border-left: calc(1.5 * var(--u)) solid var(--line);
  color: var(--ink-soft);
}

/* Tables are white cards like every other panel. Wrapper scrolls rather than
   letting a wide table push the page sideways. */
.table-wrap{
  overflow-x: auto;
  margin: 0 0 calc(26 * var(--u));
}
.prose table{
  border-collapse: collapse;
  width: 100%;
  background: var(--card);
  border: calc(1.5 * var(--u)) solid var(--line);
  font-size: calc(15 * var(--u));
  line-height: 1.4;
}
.prose th,
.prose td{
  border: calc(1 * var(--u)) solid rgba(28, 26, 22, .28);
  padding: calc(8 * var(--u)) calc(10 * var(--u));
  text-align: left;
  vertical-align: top;
}
.prose th{ font-weight: 700; }
.prose td{ color: var(--ink-soft); }
.prose ul,
.prose ol{ margin: 0 0 calc(22 * var(--u)); padding-left: calc(26 * var(--u)); }
.prose li{ margin-bottom: calc(12 * var(--u)); }
.prose li > ul{ margin-top: calc(12 * var(--u)); }

.prose a{
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: calc(1 * var(--u));
  text-underline-offset: calc(3 * var(--u));
}
.prose a:hover{ color: var(--green); }

.prose strong{ font-weight: 700; }

/* Two lists read as a pair rather than one after the other. Falls
   back to a single column when the measure gets too narrow to split. */
.two-col{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(34 * var(--u));
  margin-bottom: calc(24 * var(--u));
  /* A step down from body size: these are two lists side by side in
     roughly half the measure, so they read better slightly smaller. */
  font-size: calc(18 * var(--u));
}
.two-col ol{
  padding-left: calc(22 * var(--u));
  margin-bottom: 0;
}
.two-col__head{
  margin-bottom: calc(12 * var(--u));
}
@media (max-width: 900px){
  .two-col{ grid-template-columns: 1fr; }
}

/* ----------------------------------------------------------
   TABLE OF CONTENTS
   ---------------------------------------------------------- */
.toc{
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--toc-w);
  z-index: 3;
  transition: width .45s ease;
}

.toc__inner{
  position: sticky;
  top: calc(122 * var(--u));
  padding: calc(30 * var(--u)) calc(16 * var(--u)) 0 calc(13 * var(--u));
}


.toc__label{
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.toc__label:hover{
  background: var(--green);
  color: #f4f4f0;
  border-color: var(--green);
}

.toc__list{
  list-style: none;
  margin: calc(26 * var(--u)) 0 0;
  padding: 0;
}
.toc__list li{
  margin-bottom: calc(16 * var(--u));
}
.toc__list a{
  display: block;
  font-size: calc(18 * var(--u));
  line-height: 1.35;
  color: var(--ink);
  text-decoration: none;
  opacity: .62;
  transition: opacity .2s ease, color .2s ease;
}
.toc__list a:hover{ opacity: 1; }

/* Nested headings sit indented under their parent section */
.toc__list li.is-sub a{
  padding-left: calc(13 * var(--u));
  font-size: calc(16.5 * var(--u));
}

/* The "little highlight" marking where you are */
.toc__list li.is-active a{
  opacity: 1;
  color: var(--green);
}

/* Collapsing narrows the column to fit the section names and keeps
   the heading, which stays the control for reopening. "Contents" is
   short enough to fit the collapsed width, so nothing has to swap. */

/* ----------------------------------------------------------
   MARGIN COLUMN - where figures wait and footnotes live
   ---------------------------------------------------------- */
.margin-col{
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--marg-l);
  width: var(--marg-w);
  z-index: 3;
  transition: left .45s ease, width .45s ease;
}
.margin-col__label{
  position: sticky;
  top: calc(122 * var(--u));
  margin: calc(30 * var(--u)) 0 0 calc(16 * var(--u));
}

/* ----------------------------------------------------------
   FIGURE PREVIEW
   A sneak peek at the top of the column. Aspect ratios are left
   alone -- nothing is cropped -- and the sizes are solved so the
   arrangement reads as intended: two stacked ~2:1 thumbnails at
   width W come to roughly W tall, so a thumbnail column of
   hero/2.69 stands the same height as the hero beside it.
   225u + 83u + 10u gap = the 318u band.
   Not sticky: it scrolls away on its own, leaving the column to
   the parking behaviour.
   ---------------------------------------------------------- */
.fig-preview{
  width: calc(318 * var(--u));
  margin: calc(16 * var(--u)) 0 0 calc(16 * var(--u));
  /* Three rows deep, with a long dissolve rather than a short one: the
     fade begins just past the hero row and takes ~134u to reach clear,
     so the lower rows recede instead of being abruptly cut. */
  max-height: calc(252 * var(--u));
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(118 * var(--u)), transparent calc(252 * var(--u)));
  mask-image: linear-gradient(to bottom, #000 calc(118 * var(--u)), transparent calc(252 * var(--u)));
}

.fig-preview__row{
  display: flex;
  gap: calc(10 * var(--u));
  align-items: flex-start;
}
.fig-preview__hero{ flex: 0 0 calc(225 * var(--u)); }
.fig-preview__stack{
  flex: 0 0 calc(83 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(10 * var(--u));
}
/* Lower rows are pairs of equal halves */
.fig-preview__pair{
  display: flex;
  gap: calc(10 * var(--u));
  align-items: flex-start;
  margin-top: calc(10 * var(--u));
}
.fig-preview__pair .fig-preview__item{ flex: 1 1 0; min-width: 0; }

/* Each preview is a white card like every other figure, with the
   padding dialled back since some are only 83u wide. */
.fig-preview__item{
  display: block;
  width: 100%;
  padding: calc(4 * var(--u));
  background: var(--card);
  border: calc(1.5 * var(--u)) solid var(--line);
  cursor: pointer;
  font: inherit;
  transition: border-color .18s ease;
}
.fig-preview__item:hover{ border-color: var(--green); }
.fig-preview__item img{
  display: block;
  width: 100%;
  height: auto;
}

/* Footnotes rendered as sidenotes, positioned against their
   reference by JS. */
/* Notes overhang the narrow figures column into the page's right
   margin, out to the 1384u line the masthead and title block use.
   At the column's own 150u a note is a 124px ribbon of about fifteen
   characters a line, which is unreadable; parked figures stay narrow
   because they are only a cue, but prose has to be legible. */
.sidenote{
  position: absolute;
  left: calc(16 * var(--u));
  width: calc(318 * var(--u));
  padding: calc(12 * var(--u)) calc(12 * var(--u)) calc(13 * var(--u));
  background: var(--card);
  border: calc(1.5 * var(--u)) solid var(--line);
  font-size: calc(15 * var(--u));
  line-height: 1.5;
  color: var(--ink-soft);
  transition: top .3s ease;
}
/* Number sits as a superscript, matching its marker in the prose */
.sidenote__num{
  font-size: .78em;
  vertical-align: super;
  line-height: 0;
  color: var(--ink);
  margin-right: calc(4 * var(--u));
}

/* Reference marker in the prose. Not a link: the note it refers to is
   already visible in the margin, so there is nowhere to jump to and
   nothing to tap. Ink-soft rather than accent, since the guide reserves
   the green for hover, active and decorative use. */
.fnref{
  font-size: .72em;
  vertical-align: super;
  line-height: 0;
  color: var(--ink-soft);
  padding: 0 calc(1 * var(--u));
}

/* ----------------------------------------------------------
   FIGURES
   The slot is a permanent hole in the prose, sized by the
   image's aspect ratio at a FIXED width, so its height never
   changes -- not even when the collapse widens the measure.
   The figure flies into that hole; no line of text ever moves.
   ---------------------------------------------------------- */
.fig-slot{
  width: calc(700 * var(--u));
  /* card chrome is 12u padding + 1.5u border each side = 27u total,
     so the image inside is 673u wide and the card stands that much
     taller than the bare image would. */
  height: calc((700 * var(--u) - 27 * var(--u)) / var(--ar) + 27 * var(--u));
  margin: calc(30 * var(--u)) 0 calc(14 * var(--u));
}

/* Captions are secondary text in the style guide's terms, set apart
   from body prose by a tracked uppercase label -- the same device the
   guide uses for the hero eyebrow -- and a slightly smaller size. */
.fig-caption{
  font-size: calc(15.5 * var(--u));
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0 0 calc(38 * var(--u));
  padding-left: calc(12 * var(--u));
  border-left: calc(1.5 * var(--u)) solid var(--line);
}
.fig-caption__label{
  color: var(--ink);
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: .84em;
  margin-right: calc(9 * var(--u));
  white-space: nowrap;
}
.fig-caption__lead{
  color: var(--ink);
  font-style: italic;
}

.fig{
  position: absolute;
  z-index: 6;
  padding: calc(12 * var(--u));
  background: var(--card);
  border: calc(1.5 * var(--u)) solid var(--line);
  /* parked: waiting in the margin, overhanging into the page's right
     margin exactly as the notes do, out to the same 1384u line the
     masthead and title block use. Confined to the column's own 150u
     the waiting figure was too small to read as a preview. */
  left: calc(var(--marg-l) + 16 * var(--u));
  width: calc(318 * var(--u));
  cursor: zoom-in;
  transition: left .55s cubic-bezier(.4, 0, .2, 1),
              top .55s cubic-bezier(.4, 0, .2, 1),
              width .55s cubic-bezier(.4, 0, .2, 1),
              opacity .35s ease;
}

/* landed: filling its reserved slot in the prose */
.fig.is-landed{
  left: calc(var(--prose-l) + 24 * var(--u));
  width: calc(700 * var(--u));
}

.fig img{
  display: block;
  width: 100%;
  height: auto;
}

/* The measuring essay keeps its screenshot while parked in the figures rail,
   then swaps to the existing React instrument when the figure lands. The live
   host is rendered at its eventual width while hidden so its slot can reserve
   the correct height before the reader reaches it. */
.fig--interactive{
  cursor: default;
}
.fig--interactive .interactive-figure{
  position: absolute;
  top: calc(12 * var(--u));
  left: calc(12 * var(--u));
  width: calc(673 * var(--u));
  visibility: hidden;
  pointer-events: none;
}
.fig--interactive.is-landed.is-interactive-ready > img{
  display: none;
}
.fig--interactive.is-landed.is-interactive-ready .interactive-figure{
  position: static;
  width: 100%;
  visibility: visible;
  pointer-events: auto;
}

/* The static site's narrow layout scales the desktop composition as a whole.
   The legacy instruments use real-size controls, so the screenshot is the
   more legible fallback below their responsive breakpoint. */
@media (max-width: 720px){
  .fig--interactive .interactive-figure,
  .fig--interactive.is-landed.is-interactive-ready .interactive-figure{
    display: none;
  }
  .fig--interactive.is-landed.is-interactive-ready > img{
    display: block;
  }
}

/* A video figure shows its poster while parked and becomes the player once
   it lands. The iframe's src is only set on landing, so no video loads --
   and none autoplays -- until the reader actually reaches it. */
.fig--video iframe{
  display: none;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}
.fig--video.is-landed img{ display: none; }
.fig--video.is-landed iframe{ display: block; }
/* The player handles its own clicks; enlarging it makes no sense. */
.fig--video{ cursor: default; }

/* ----------------------------------------------------------
   LIGHTBOX
   ---------------------------------------------------------- */
.lightbox{
  position: fixed;
  inset: 0;
  z-index: 9500;
  background: rgba(28, 26, 22, .88);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(40 * var(--u));
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
  cursor: zoom-out;
}
.lightbox.is-open{
  opacity: 1;
  pointer-events: auto;
}
/* display:table so the frame shrinks to the image's rendered width and
   the caption, as a table-caption, inherits exactly that width instead
   of running wider or narrower than the picture it describes. */
.lightbox__frame{
  display: table;
  max-width: 100%;
}
.lightbox img{
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 210 * var(--u));
  width: auto;
  background: var(--card);
  border: calc(1.5 * var(--u)) solid var(--line);
}

/* Caption travels with the enlarged figure when there is one. Every
   part of it goes light: on the dark backdrop the label and lead,
   which are --ink in the page, were all but invisible. */
.lightbox__caption{
  display: table-caption;
  caption-side: bottom;
  padding-top: calc(14 * var(--u));
  font-size: calc(15 * var(--u));
  line-height: 1.5;
  color: var(--paper);
  text-align: left;
}
.lightbox__caption:empty{ display: none; }
/* The label and lead carry the accent rather than turning white with
   everything else, so the caption keeps the hierarchy it has on the
   page. #628C69 is too dark to read on this backdrop, so it is
   lightened for use on the dark surface only -- about 8:1 against the
   overlay, where the guide's accent manages under 3:1. */
.lightbox{
  --accent-on-dark: #9CBFA2;
}
.lightbox__caption .fig-caption__label,
.lightbox__caption .fig-caption__lead{
  color: var(--accent-on-dark);
}
.lightbox__caption strong{
  color: var(--paper);
}
.lightbox__caption a{
  color: var(--accent-on-dark);
}
.lightbox__caption a{ text-decoration: underline; }
.lightbox__close{
  position: absolute;
  top: calc(24 * var(--u));
  right: calc(30 * var(--u));
  font-size: calc(34 * var(--u));
  line-height: 1;
  color: var(--paper);
  background: none;
  border: 0;
  cursor: pointer;
  font-family: var(--serif);
}

/* ----------------------------------------------------------
   MOTION
   ---------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .fig,
  .article__rule,
  .prose,
  .toc,
  .margin-col,
  .sidenote{
    transition: none;
  }
}
