/* violenceofintimacy.com — overrides on top of the cloned bundle.
   main.css is left byte-identical so it stays usable as a reference. Everything
   that makes this site this site lives here. */

/* The page colour lives on <body> so nothing else has to carry it. */
body {
  background: #000;
}
body:has(.context-shell) {
  background: #f2eeee;
}
body:has(.article-shell) {
  background: #fff;
}
/* .home-frame still sets its own mint background directly (main.css) — the
   body rule alone isn't enough to override it. --mint stays untouched since
   the nav's sitewide active-chip default and other pages still use it. */
.home-frame {
  background: #000;
}

/* landing page gone dark — continuous with the black manifesto section
   below instead of a colour break. main.css hardcodes #000/ink on all of
   these assuming a light hero, so every one needs a light-on-dark flip. */
body:has(.home-shell) {
  color: #b3ffd6;
}
.logo-time,
.logo-capsule {
  color: #b3ffd6;
}
.meta-date,
.intro-arrow,
.intro-copy,
.location-meta {
  color: #b3ffd6;
}
.hero-clock {
  color: #b3ffd6;
}
.hero-line {
  border-left-color: #b3ffd63d;
}
/* hero-line-center otherwise runs top:0/bottom:0 the full home-frame height,
   poking straight through .hero-bottom-line (sits at bottom:1.67%) instead
   of meeting it cleanly. Match its bottom offset so it stops right there. */
.hero-line-center {
  bottom: 1.67%;
}
.hero-bottom-line {
  border-top-color: #b3ffd63d;
}
.hero-left-main {
  border-bottom-color: #b3ffd63d;
}
/* --nav-border-color set here falls back to var(--ink) on .home-header's own
   dashed border — .nav-center-intersection is a child, not an ancestor, so
   setting it there doesn't cascade up to the header. */
.home-shell .home-header {
  border-color: #b3ffd63d;
}
.nav-center-intersection {
  --nav-border-color: #b3ffd63d;
}
.home-scan-box {
  stroke: #b3ffd6;
}
.home-scan-label-bg {
  fill: #b3ffd6;
}
.home-scan-label-text {
  fill: #101112;
}
/* home-mark.png is genuinely near-black (avg RGB ~12,12,12) — invisible on
   a black page. Inverting the display, not the file: same asset, unmodified,
   only scoped to this one page where the background actually changed. */
body:has(.home-shell) .pixel-dust {
  filter: invert(1);
}

/* left/right hero grid lines continue down through the manifesto section —
   same left:var(--edge-x)/right:var(--edge-x) offsets as .hero-line-left/
   -right, so they read as one continuous line across the section boundary.
   .manifesto-section is full-width like .home-frame, so the edges line up
   without needing to match paddings. The center line stays hero-only. */
.manifesto-section {
  position: relative;
}
.hero-line-extend {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  border-left: 1px dashed #b3ffd63d;
  pointer-events: none;
  z-index: 3;
}
.hero-line-extend-left {
  left: var(--edge-x);
}
.hero-line-extend-right {
  right: var(--edge-x);
}

/* ------------------------------------------------------------------ context anatomy
   The figure lives in the right column, driven by links in the left column.
   The wrapper just scopes the hero JS without imposing the hero layout. */
.context-hero-wrapper.record-hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: calc(100vh - var(--nav-top) - var(--nav-height) + 16px);
  max-width: none;
  padding: 0;
  margin: 0;
}
.context-grid {
  /* main.css's 1fr/1fr tracks only resolve against a definite container width —
     outside the flex layout .record-hero normally provides, width:auto here
     shrinks to the columns' content instead of filling .context-hero-wrapper. */
  width: 100%;
  /* Leaving align-items at its stretch default (not overriding it) on
     purpose: stretching .context-col to match the taller text column is
     what keeps both column heads aligned at the top and closes the dead
     space below the shorter one. The aspect-ratio warp that caused lives
     one level down — .context-anatomy-figure's own align-self:center below
     stops the stretch at the figure specifically, instead of blocking it
     for the whole column here. */
}
.context-anatomy-figure {
  width: 100%;
  max-width: 280px;
  margin: 0 auto;
  /* .context-col-body defaults align-items to stretch — fine for width
     (margin:auto handles horizontal), but a fixed-aspect-ratio figure can't
     actually stretch to fill the row's height, so it just sits pinned to
     the top instead. align-self overrides to center it vertically too. */
  align-self: center;
  /* same padding-box asymmetry as .context-col-text: 20px top / 30px bottom
     on .context-col-body centers align-self within a content box that's
     shifted up 5px from the true visual center. Compensate directly. */
  transform: translateY(5px);
}
@media (max-width: 900px) {
  .context-hero-wrapper.record-hero {
    min-height: auto;
  }
  .context-anatomy-figure {
    max-width: 220px;
    margin-top: clamp(20px, 4vw, 36px);
  }
}
.context-col-text a[data-system] {
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition:
    color 0.18s ease,
    border-color 0.18s ease;
}
.context-col-text a[data-system="nerves"] {
  color: #2a4ec9;
}
.context-col-text a[data-system="vessels"] {
  color: #c92a3e;
}
/* main.css only centers .context-body on the mobile breakpoint — desktop
   was left-aligned. text-align alone just centers line-wrap inside an
   already-full-width block; .context-col-text flex-grows to fill the
   column, so there's no slack for it to actually sit centered as a unit. */
.context-body {
  text-align: center;
}
.context-col-text {
  flex: 0 1 380px;
  margin: 0 auto;
  /* .context-col-body's padding is 20px right / 30px left (shared with the
     figure column, so not safe to touch here) — auto-margins center within
     that asymmetric box, landing 5px right of .context-col-head's true
     center. Correct for it directly instead. */
  transform: translateX(-5px);
}
body:has(.fragments-shell) {
  background: var(--paper);
}
body:has(.record-shell) {
  background: #fff;
}
/* nothing's tree went warm (amber/navy dapple) — match the active nav
   chip to the trunk instead of the sitewide mint default. */
body:has(.record-shell) .nav-chip-active {
  background: #233452;
  color: #f8f8f4;
}

.home-shell,
.logs-shell,
.record-shell,
.fragments-shell,
.context-shell,
.article-shell {
  background: transparent;
}

/* --------------------------------------------------------------- home mark
   main.css draws this as a box-shadow dot grid spelling the original's
   initials. Swapped for the fig — same slot, same href="/", same aria-label,
   just a different mark. Sized to the nav row rather than the old dot grid's
   own (much smaller, very wide) footprint.

   home-mark.png is the original file, unmodified — no crop, no alpha matte. */
.pixel-dust {
  /* Sized to fill the 32px row exactly, not overflow past it. .home-frame has
     overflow:hidden, so an oversized box here doesn't render as a bigger icon
     — it renders as a fragment of one, clipped at the frame edge. Filling the
     row via contain is the only sizing that's guaranteed not to get cut. */
  width: var(--nav-height);
  height: var(--nav-height);
  background-image: url(/assets/images/home-mark.png);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.pixel-dust::before {
  content: none;
}

:root {
  --iov-rule: #10111226;
  --iov-dim: #10111294;
  --iov-faint: #1011125c;
  --paper: #f8f8f4;
}

/* ------------------------------------------------------------------- wordmark
   The original's rules are left to do the work: .logo-wrap absolute at 31.55%
   with width:max-content, .logo-time absolute at top:3px / left:calc(17% - 4px),
   .logo-capsule in flow with margin-top:.66em so the two boxes overlap by ~30px.
   All of that already lives in main.css and none of it is touched here.

   Only the type scale changes, because TIME and Capsule are 4 and 7 characters
   and these words are 8. Each line is scaled to occupy the width its
   counterpart did, which reproduces the original geometry exactly rather than
   approximating it:

     line 1  "VIOLENCE of"  4.35em   x  78px  = 340px   (TIME was 340px)
     line 2  "INTIMACY"     4.239em  x 131px  = 557px   (Capsule was 557px)

   giving back the original's 0.61 width ratio, its leftward lean and its
   overlap, with the faces still alternating Bitbybit over Mondwest. */

/* Measured off the live original at 1280px:

     TIME      156.544px, 1.733em tracked -> 271.3px wide, absolute top:3px left:70px
     Capsule   153.856px, 2.870em tracked -> 435.3px wide, margin-top .66em
     ratio     0.623 — and crucially, at ESSENTIALLY EQUAL TYPE SIZE.

   That last part is the whole thing. The original does not shrink one word to
   get its proportion; both are ~155px and the 0.623 falls out of 4 characters
   sitting over 7. Reproducing the ratio by scaling one line down instead gives
   the number and none of the look.

   So the words carry it, not the type scale:
     line 1  VIOLENCE      Bitbybit  3.853em
     line 2  of INTIMACY   Mondwest  5.129em
     ratio                           0.751  at one size

   And "of" is deliberately lowercase. Capsule's ascenders (C 0.640em, l
   0.760em) climb past TIME's baseline through the gaps in T-I-M-E, and TIME's
   caps have no descenders coming down to meet them — that interlock is why the
   overlap reads as one mass. Mondwest's lowercase f reaches 0.760em too, so it
   does the same job at the left edge, exactly where the original's does.

   Both lines share one size, so the inherited .66em margin lands the overlap at
   0.194 of the type size against the original's 0.190 — no override needed. */

/* Extracted from the live original at 1280x1000 — every value below is theirs,
   read off computed style, not guessed:

     .logo-wrap     absolute, left:302.703 + translateX(-50%), max-content 435.3px
     .logo-time     absolute, top:3px left:70px, Bitbybit 700
                    156.544px / lh 128.366 (.82) / tracking -7.8272 (-.05em)
     .logo-capsule  relative, margin-top:101.545px (.66em), padding-bottom:30px
                    PP Mondwest 400, 153.856px / lh 126.162 / tracking -7.6928
     widths         TIME 271.3  over  Capsule 435.3

   All of that already lives in main.css and is inherited untouched. Only two
   things have to move, and both for the same reason:

   TIME is 1.733em tracked against Capsule's 2.870em — a 1.66x spread that comes
   free from 4 characters over 7. VIOLENCE (3.853em) and "of intimacy" (3.970em)
   are within 3% of each other, so there is no spread to inherit. Matching their
   0.62 ratio would mean shrinking line one to 60% of line two, which produces
   the number and loses the look — the original's two words are the SAME size.

   So: keep them the same size, size them so the wider line fills the same
   435.3px measure Capsule did, and drop the 70px inset that a 1.66x spread was
   what paid for. */

/* The original's mark is 435px inside a 605px column. These words are longer,
   so filling more of that column is what makes them read at the same weight:
   10.7vw puts the wider line on ~544px at 1280, leaving ~30px each side.
   Capped there because .intro-arrow sits at 557px and the block bottoms out
   around 499px — any larger and the mark runs into it. */
.logo-time,
.logo-capsule {
  font-size: clamp(85px, 10.7vw, 154px);
}

/* flush, because the lines are now within 3% of the same width */
.logo-time {
  left: 0;
}

/* The original pins each hero element at its own percentage — meta-date 27.2%,
   the mark 31.55%, intro-copy 63.2% — which centres a two-line block of THEIR
   size and leaves this one sitting high. Centring the column directly is both
   simpler and correct at any mark size.

   The mark's geometry is untouched by this: it lives inside .logo-wrap, which
   stays a containing block, so .logo-time still resolves its top/left against
   it exactly as before. Only the wrap's placement in the column changes. */
@media (min-width: 901px) {
  .hero-left-main {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: clamp(10px, 1.4vw, 22px);
  }

  .logo-wrap,
  .meta-date,
  .intro-arrow,
  .intro-copy {
    position: relative;
    inset: auto;
    transform: none;
  }

  .logo-wrap {
    height: auto;
  }

  /* .hero-logo-block is display:contents, so .logo-wrap and .meta-date are
     siblings in source order and the date has to be pulled above the mark */
  .meta-date {
    order: -1;
    text-align: center;
  }
  .intro-arrow {
    order: 1;
  }
  .intro-copy {
    order: 2;
    max-width: 46ch;
    text-align: center;
  }
}

/* the original reserves this for Capsule's p; nothing here descends */
.logo-capsule {
  padding-bottom: 0;
  /* .66em inherited puts the f/t/i ascenders 25.8px above VIOLENCE's baseline,
     which reads as touching. +0.12em drops that to ~9px — still interlocked,
     but with air in the seam. */
  margin-top: 0.78em;
}

/* "of" now sits inside .logo-capsule, so it already has Mondwest at full size —
   it only needs to stay lowercase, which is what puts its f-ascender up into
   VIOLENCE. Nothing to override. */

/* ----------------------------------------------------------------- hero ascii
   Pure black glyphs on mint, at the contrast of white-on-OLED: two tones only,
   no grey wash and no colour cast.

     grayscale   drops the dye colour the fluid carries
     invert      pale-glyphs-on-dark becomes dark-glyphs-on-pale
     contrast    crushes the midtones so the ground goes to white and the
                 glyphs go to black — this is the step that kills the wash
     multiply    white x mint = mint, black x mint = black */

.hero-ascii {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--mint);
  isolation: isolate;
}

.hero-ascii canvas {
  display: block;
  width: 100%;
  height: 100%;
  filter: grayscale(1) invert(1) contrast(3.6) brightness(1.06);
  mix-blend-mode: multiply;
}

.hero-ascii .fallback {
  display: grid;
  place-items: center;
  height: 100%;
  padding: 24px;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--iov-dim);
  text-align: center;
}

/* when the engine takes over, the WebGL metaball stands down */
.home-animation.is-ascii .home-animation-stage {
  display: none;
}

/* ------------------------------------------------------------------ hero map
   hero-map.png is a rendering of Manhattan — it is referenced only from CSS,
   never from markup, which is why it survived the asset sweep. It is someone
   else's city and there is no location feed here to replace it with (places.json
   carries 119 cities and no timestamps), so the panel keeps its rule and drops
   the picture. */

.hero-map-shell,
.hero-map {
  background-image: none;
}

/* --------------------------------------------------------------- fourth chip
   .haiku-nav-chip ships fully styled in the bundle and was never switched on.
   It only lacked an active state. */

.nav-chip.haiku-nav-chip.nav-chip-active,
.nav-chip.haiku-nav-active {
  background: var(--mint);
  color: var(--ink);
  border-color: var(--ink);
}

/* ------------------------------------------------------------ shared section
   One rule set for every archive block on the index. Monospace metadata, serif
   body, hairline rules, no cards. */

/* These sit inside .manifesto-section, which is solid black with mint type.
   Everything below inverts against that slab — using --ink here renders
   near-black on black. The palette is scoped so the same markup could be
   dropped on paper later by overriding four values. */

.iov-section {
  --fg: var(--mint);
  --fg-dim: #b3ffd6a6;
  --fg-faint: #b3ffd657;
  --rule: #b3ffd629;

  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  /* .manifesto-inner is a column flex with a large gap; it already owns the
     vertical rhythm between blocks, so this only sets the side gutters. */
  padding: 0 var(--page-pad-x);
  color: var(--fg);
}

.iov-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--fg);
}

.iov-section-title {
  margin: 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-metadata);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg);
}

.iov-section-count {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* ------------------------------------------------------------------ currently
   A definition list that reads as a status readout. Values are pulled live
   where a feed exists and fall back to the markup where one does not. */

.iov-currently {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0;
  margin-top: 4px;
}

.iov-currently dt,
.iov-currently dd {
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
  margin: 0;
  min-width: 0;
}

.iov-currently dt {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-dim);
  padding-right: clamp(20px, 4vw, 56px);
}

.iov-currently dd {
  font-family: Alegreya, serif;
  font-size: 18px;
  line-height: 1.4;
  color: var(--fg);
  overflow-wrap: anywhere;
}

.iov-currently dd em {
  font-style: italic;
  color: var(--fg-dim);
}

/* ---------------------------------------------------------------------- films
   268 one-line reviews are autobiography that never says so. The strip is a
   horizontal scroll of years; the counts are the point, not the posters. */

.iov-films {
  margin-top: 4px;
}

.iov-films-years {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--rule);
}

.iov-film-year {
  flex: 1 1 0;
  min-width: 0;
  padding: 14px 8px 13px 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--fg);
  transition: opacity 0.2s;
}

.iov-film-year:hover {
  opacity: 0.55;
}

.iov-film-year-label {
  display: block;
  font-size: var(--mono-micro);
  letter-spacing: 0.1em;
  color: var(--fg-dim);
}

.iov-film-year-count {
  display: block;
  font-size: clamp(20px, 2.4vw, 34px);
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin-top: 3px;
}

.iov-film-year[aria-selected="true"] .iov-film-year-count {
  color: var(--fg);
}
.iov-film-year[aria-selected="false"] .iov-film-year-count {
  color: var(--fg-faint);
}

.iov-film-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.iov-film {
  display: grid;
  grid-template-columns: max-content 1fr max-content;
  gap: 14px;
  align-items: baseline;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-metadata);
}

.iov-film-date {
  color: var(--fg-faint);
  letter-spacing: 0.02em;
}
.iov-film-title {
  color: var(--fg);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  overflow-wrap: anywhere;
}
.iov-film-rating {
  color: var(--fg-dim);
  white-space: nowrap;
  letter-spacing: 0.1em;
}
.iov-film[data-rewatch="true"] .iov-film-date::after {
  content: " ↺";
  color: var(--fg-dim);
}

/* ------------------------------------------------------------------ fragments
   One line at a time, filling the page. The concepts under it are the exits:
   press one and the pool narrows to the lines that share it, so you leave a
   fragment along a thread rather than scrolling past it. */

.fragments-shell {
  min-height: 100vh;
}

.fragments-frame {
  max-width: 1180px;
  margin: 0 auto;
  padding: calc(var(--nav-top) + var(--nav-height) + clamp(28px, 4vw, 56px)) var(--page-pad-x)
    clamp(56px, 7vw, 96px);
}

.frag-stage {
  /* Fixed to exactly fill what's left of the viewport below the nav and
     .fragments-frame's own padding, so the page never needs a scroll and
     the line row (1fr) is a genuinely fixed size — see fitLine() in main.js,
     which shrinks font-size per-fragment to fit that fixed row instead of
     letting long fragments grow the row and push everything below it. */
  height: calc(
    100vh - var(--nav-top) - var(--nav-height) - clamp(28px, 4vw, 56px) - clamp(56px, 7vw, 96px)
  );
  min-height: 420px;
  display: grid;
  grid-template-rows: max-content 1fr max-content max-content;
  gap: clamp(20px, 3vw, 40px);
  cursor: pointer;
}

.frag-thread {
  margin: 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--iov-dim);
}

.frag-line {
  margin: 0;
  align-self: center;
  font-family: Alegreya, serif;
  font-size: clamp(28px, 4.6vw, 62px);
  line-height: 1.18;
  letter-spacing: -0.005em;
  color: var(--ink);
  max-width: 18ch;
  text-wrap: balance;
}

.frag-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px 32px;
  padding-top: 16px;
  border-top: 1px solid var(--ink);
}

.frag-meta {
  display: flex;
  align-items: baseline;
  gap: 18px;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.frag-count {
  color: var(--iov-faint);
  font-variant-numeric: tabular-nums;
}

.frag-src {
  color: var(--iov-dim);
  text-decoration: none;
  border-bottom: 1px solid var(--iov-rule);
  transition:
    color 0.2s,
    border-color 0.2s;
}

.frag-src:hover {
  color: var(--ink);
  border-color: var(--ink);
}

.frag-keys {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
}

.frag-key {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  background: none;
  border: 1px solid var(--iov-rule);
  padding: 4px 9px;
  cursor: pointer;
  transition:
    background 0.2s,
    border-color 0.2s,
    color 0.2s;
}

.frag-key::before {
  content: "\2192 ";
  color: var(--iov-faint);
}
.frag-key:hover {
  border-color: var(--ink);
}
.frag-key[aria-pressed="true"] {
  background: var(--ink);
  color: var(--mint);
  border-color: var(--ink);
}
.frag-key[aria-pressed="true"]::before {
  color: var(--mint);
}

.frag-next {
  justify-self: start;
  font-family: "PP Mondwest", sans-serif;
  font-size: 18px;
  color: var(--ink);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.2s;
}

.frag-next:hover {
  opacity: 1;
}

.frag-hint {
  margin: 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--iov-faint);
}

.frag-live {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* landing reveal — rides the existing hidden->visible toggle in main.js
   (fragStage.hidden = false), staggered top to bottom in reading order. */
.frag-thread,
.frag-line,
.frag-foot,
.frag-next,
.frag-hint {
  animation: frag-arrive 700ms ease-out both;
}
.frag-thread {
  animation-delay: 0ms;
}
.frag-line {
  animation-delay: 120ms;
}
.frag-foot {
  animation-delay: 320ms;
}
.frag-next {
  animation-delay: 320ms;
}
.frag-hint {
  animation-delay: 420ms;
}

@keyframes frag-arrive {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .frag-thread,
  .frag-line,
  .frag-foot,
  .frag-next,
  .frag-hint {
    animation: none;
  }
}

/* ------------------------------------------------------------------ relations
   Every object can point at another. Rendered as a plain list of arrows so the
   graph reads as a graph without needing to be drawn as one. */

.iov-relations {
  margin-top: clamp(32px, 4vw, 52px);
  padding-top: 16px;
  border-top: 1px solid var(--ink);
}

.iov-relations-label {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--iov-dim);
  margin: 0 0 12px;
}

.iov-relations-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}

.iov-relation {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-metadata);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  transition: opacity 0.2s;
}

.iov-relation::before {
  content: "→ ";
  color: var(--iov-dim);
}
.iov-relation:hover {
  opacity: 0.55;
}
.iov-relation[data-kind="concept"] {
  color: var(--iov-dim);
}

/* ------------------------------------------------------------ set-type covers
   The originals were twelve PNGs belonging to someone else. These never needed
   to be files: the cover is the title, set in the same two display faces the
   wordmark uses, on the same near-black the card already was. */

.article-cover-set {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: max-content 1fr max-content;
  gap: 10px;
  padding: clamp(14px, 1.5vw, 20px);
  color: var(--mint);
  text-align: left;
}

.article-cover-set::after {
  content: "";
  position: absolute;
  inset: clamp(7px, 0.8vw, 11px);
  border: 1px solid currentColor;
  opacity: 0.22;
  pointer-events: none;
}

.cover-num {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.22em;
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.cover-title {
  font-family: "PP Mondwest", sans-serif;
  font-size: clamp(21px, 2.1vw, 30px);
  line-height: 0.98;
  letter-spacing: -0.02em;
  align-self: center;
  text-wrap: balance;
}

.cover-sub {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  opacity: 0.62;
  line-height: 1.35;
}

/* ------------------------------------------------------------------ record
   A figure beside its index. Touch a row and the matching system lights.

   The canvas is 58x74 and blown up, so image-rendering:pixelated is doing the
   same job jzhao's does — rendering deliberately small and letting the grid
   crunch it, rather than drawing smooth and pretending. Nothing is smoothed
   anywhere in this block. */

.record-shell {
  min-height: 100vh;
}

.record-frame {
  width: 100%;
  max-width: 1920px;
  margin: 0 auto;
  padding: 0 var(--page-pad-x);
  position: relative;
}

.record-layout {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  gap: clamp(28px, 5vw, 80px);
  align-items: start;
  max-width: 1320px;
  margin: 0 auto;
  padding: calc(var(--nav-top) + var(--nav-height) + clamp(30px, 4vw, 64px)) 0
    clamp(72px, 9vw, 130px);
}

@media (max-width: 900px) {
  .record-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 36px;
  }
}

/* ----------------------------------------------------------------- the figure */

.record-figure {
  position: sticky;
  top: calc(var(--nav-top) + var(--nav-height) + 40px);
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.record-figure canvas {
  display: block;
  width: 100%;
  height: auto;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.record-figure-key {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--iov-faint);
}

.record-figure-key span {
  cursor: default;
  transition: color 0.18s;
}

.record-figure-key span:hover,
.record-figure-key span:focus-visible {
  color: var(--ink);
  outline: none;
}

/* ------------------------------------------------------------------ the index */

.record-index {
  min-width: 0;
}

.record-stream {
  margin-top: clamp(30px, 4vw, 52px);
}

.rec-row {
  display: grid;
  grid-template-columns: 92px 96px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--iov-rule);
  cursor: default;
  transition: background 0.15s;
}

.rec-row:hover,
.rec-row:focus-visible {
  background: #10111208;
  outline: none;
}

.rec-row time {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-metadata);
  letter-spacing: 0.02em;
  color: var(--iov-faint);
  font-variant-numeric: tabular-nums;
}

.rec-kind {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.14em;
  color: var(--iov-faint);
}

.rec-text {
  font-family: Alegreya, serif;
  font-size: 17px;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* the two systems, echoed in the row that drives them */
.rec-row[data-kind="BROADCAST"] .rec-kind {
  color: #2a4ec9;
}
.rec-row[data-kind="BROADCAST"]:hover .rec-text {
  color: #2a4ec9;
}
.rec-row[data-kind="FILM"]:hover .rec-kind {
  color: #c92a3e;
}

/* ------------------------------------------------------------ record epigraph
   Two lines said ninety seconds apart on 9 Aug 2026 — the archive as corpus
   against the archive as futile. Set as an exchange rather than a quotation:
   the second line answers the first, so it is indented off it. */

.record-epigraph {
  max-width: 520px;
  margin: 0 0 clamp(38px, 4.5vw, 64px);
  padding-bottom: 20px;
  border-bottom: 1px solid var(--ink);
}

.record-epigraph-line {
  margin: 0;
  font-family: Alegreya, serif;
  font-size: clamp(19px, 1.9vw, 25px);
  line-height: 1.32;
  color: var(--ink);
  text-wrap: balance;
  animation: epigraph-focus 900ms ease-out 100ms both;
}

.record-epigraph-line + .record-epigraph-line {
  margin-top: 0.2em;
  padding-left: 1.6em;
  color: var(--iov-dim);
  animation-delay: 500ms;
}

@keyframes epigraph-focus {
  from {
    opacity: 0;
    filter: blur(6px);
  }
  to {
    opacity: 1;
    filter: blur(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .record-epigraph-line {
    animation: none;
  }
}

.record-epigraph-meta {
  margin: 14px 0 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--iov-faint);
}

/* ---------------------------------------------------------------- record rows
   main.css spaces these for journal entries carrying photo stacks — 40 to 72px
   between them. Every row here is one line, so that reads as a broken list. */

.logs-entry {
  margin-bottom: 0;
  padding: 9px 0;
  border-bottom: 1px solid var(--iov-rule);
  align-items: baseline;
}

.logs-entry time {
  margin-bottom: 0;
}

.logs-entry p {
  font-size: 17px;
  line-height: 1.45;
}

/* --------------------------------------------------------------- record kinds */

.record-kind {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.14em;
  color: var(--iov-faint);
  margin-right: 8px;
}

.logs-entry[data-kind="BROADCAST"] .record-kind {
  color: var(--ink);
}

/* ------------------------------------------------------- the rotating epigraph
   The slab used to hold a borrowed Orwell quote. It holds one of the fragments
   now, re-rolled per load, so the loudest thing on the page is always something
   that already had to earn its place in an essay. */

.manifesto-fragment {
  margin: 0;
  font-family: Alegreya, serif;
  font-size: clamp(22px, 2.6vw, 34px);
  line-height: 1.3;
  color: var(--mint);
  text-align: center;
  text-wrap: balance;
  max-width: 24ch;
  margin-inline: auto;
  transition: opacity 0.5s;
}

.manifesto-attrib {
  margin: 18px 0 0;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mint);
  opacity: 0.5;
  text-align: center;
}

[data-fragment-rotator].is-swapping .manifesto-fragment {
  opacity: 0;
}

/* ------------------------------------------------------------ essay typography
   main.css styles `.article-content > p` and nothing else, because the original
   shipped placeholder prose that was only ever paragraphs. Real essays have
   sections, epigraphs and quoted film logs. Same 610px measure throughout so
   the column keeps one rhythm. */

.article-subtitle {
  margin: 14px 0 0;
  font-family: Alegreya, serif;
  font-style: italic;
  font-size: clamp(19px, 1.6vw, 23px);
  line-height: 1.3;
  color: var(--iov-dim);
  max-width: 34ch;
}

.article-epigraph {
  max-width: min(100%, 610px);
  margin: 0 0 2.4em;
  padding-bottom: 1.6em;
  border-bottom: 1px solid var(--iov-rule);
}

.article-epigraph p {
  margin: 0;
  font-family: Alegreya, serif;
  font-style: italic;
  font-size: var(--body-copy);
  line-height: var(--body-leading);
  letter-spacing: 0.01em;
  color: var(--ink);
  text-wrap: pretty;
}

.article-epigraph-attrib {
  margin-top: 0.7em !important;
  font-style: normal !important;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace !important;
  font-size: var(--mono-metadata) !important;
  letter-spacing: 0.1em !important;
  text-transform: uppercase;
  color: var(--iov-dim) !important;
}

.article-h2 {
  max-width: min(100%, 610px);
  margin: 2.4em 0 0.9em;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-metadata);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink);
  padding-top: 0.9em;
  border-top: 1px solid var(--iov-rule);
}

.article-h2:first-child {
  margin-top: 0;
  border-top: 0;
  padding-top: 0;
}

.article-content blockquote {
  max-width: min(100%, 610px);
  margin: 0 0 1.5em;
  padding: 0 0 0 clamp(16px, 2vw, 26px);
  border-left: 1px solid var(--ink);
}

.article-content blockquote p {
  margin: 0 0 0.7em;
  font-family: Alegreya, serif;
  font-style: italic;
  font-size: calc(var(--body-copy) - 1px);
  line-height: 1.42;
  letter-spacing: 0.01em;
  color: var(--iov-dim);
  text-wrap: pretty;
}

.article-content blockquote p:last-child {
  margin-bottom: 0;
}

.article-rule {
  max-width: min(100%, 610px);
  border: 0;
  border-top: 1px solid var(--iov-rule);
  margin: 2.2em 0;
}

.article-content em {
  font-style: italic;
}
.article-content strong {
  font-weight: 500;
}

/* the page cover is the grid cover at a larger measure */
.article-cover-set--page {
  background: #050505;
  border-radius: inherit;
}

.article-cover-set--page .cover-title {
  font-size: clamp(26px, 2.8vw, 40px);
}

/* --------------------------------------------------------------- last altered
   The site as a live object rather than a static deploy. */

.iov-altered {
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: var(--mono-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--iov-faint);
}

/* --------------------------------------------------------------- record hero
   The anatomy figure now lives above the stream; the old two-column
   record-layout is just the index below it. */

.record-layout:not(:has(.record-figure)) {
  grid-template-columns: minmax(0, 1fr);
}

/* --------------------------------------------------------------- record hero
   Full-width light panel that matches the reference videos: figure on the
   left, copy on the right, pixel-art anatomy swapping on word hover. */

.record-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
  justify-items: center;
  min-height: calc(100vh - var(--nav-top) - var(--nav-height));
  max-width: 1320px;
  margin: 0 auto;
  padding: calc(var(--nav-top) + var(--nav-height) + clamp(30px, 4vw, 64px)) 0
    clamp(56px, 7vw, 96px);
}

@media (max-width: 900px) {
  .record-hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 42px;
    align-items: start;
    min-height: auto;
  }
}

/* ---------------------------------------------------------------- the figure */

.record-hero-figure {
  position: relative;
  width: min(100%, 420px);
  aspect-ratio: 67 / 88;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.record-hero-figure .anatomy-layer,
.record-hero-figure .anatomy-noise {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.record-hero-figure .anatomy-layer {
  opacity: 0;
  transform: scale(1);
  filter: blur(1px);
  transition:
    opacity 0.7s ease,
    filter 0.7s ease;
  pointer-events: none;
}

.record-hero-figure .anatomy-layer.is-active {
  opacity: 1;
  filter: blur(0px);
}

.record-hero-figure .anatomy-noise {
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: overlay;
}

.record-hero-figure .anatomy-intro {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  transition: opacity 0.4s ease;
}

.record-hero-figure.is-intro-done .anatomy-intro {
  opacity: 0;
}

.record-hero-figure .anatomy-transition {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  transition: opacity 0.12s ease;
}

.record-hero-figure .anatomy-transition.is-active {
  opacity: 1;
}

.record-hero-figure.is-transitioning .anatomy-layer {
  transition: none;
}

/* intro build: brain icon grows into the full nervous system */
.record-hero-figure .anatomy-layer[data-layer="brain"] {
  transform: scale(0.16);
  transform-origin: 52% 17%;
  transition:
    transform 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.5s ease;
}

.record-hero-figure .anatomy-layer[data-layer="brain"].is-grown {
  transform: scale(1);
}

/* ----------------------------------------------------------------- the copy */

.record-hero-copy {
  min-width: 0;
  max-width: 46ch;
  justify-self: start;
}

.record-hero-line {
  margin: 0;
  font-family: Alegreya, serif;
  font-size: clamp(20px, 2.2vw, 30px);
  line-height: 1.38;
  color: var(--ink);
  text-wrap: balance;
}

.record-hero-line .record-hero-lead {
  display: block;
  font-size: 1.15em;
  margin-bottom: 0.35em;
}

.record-hero-line .record-hero-body {
  display: block;
  opacity: 0;
  transform: translateY(5px);
  transition:
    opacity 0.28s ease,
    transform 0.28s ease;
}

.record-hero-line .record-hero-body.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

.record-hero-line a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--iov-rule);
  transition:
    color 0.18s ease,
    border-color 0.18s ease;
}

.record-hero-line a[data-system="nerves"]:hover,
.record-hero-line a[data-system="nerves"]:focus-visible,
.record-hero-line a[data-system="nerves"].is-hovered {
  color: #2a4ec9;
  border-color: #2a4ec9;
  outline: none;
}

.record-hero-line a[data-system="vessels"]:hover,
.record-hero-line a[data-system="vessels"]:focus-visible,
.record-hero-line a[data-system="vessels"].is-hovered {
  color: #c92a3e;
  border-color: #c92a3e;
  outline: none;
}

/* ------------------------------------------------------------------ cursors */

.cursor-flower {
  cursor:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjYzkyYTNlIiBkPSJNMTIgMkw5IDdINUM1IDcgMiA5IDIgMTJDNiAxMiA5IDE0IDkgMTRINUM1IDE0IDIgMTYgMiAxOUM1IDE5IDggMTcgOCAxN0w5IDIxSDE1TDE2IDE3QzE2IDE3IDE5IDE5IDIyIDE5QzIyIDE2IDE5IDE0IDE5IDE0SDE1QzE1IDE0IDE4IDEyIDIyIDEyQzIyIDkgMTkgNyAxOSA3SDE1TDEyIDJaIi8+PC9zdmc+"),
    auto;
}

.cursor-eye {
  cursor:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiMyYTRlYzkiIHN0cm9rZS13aWR0aD0iMi41IiBkPSJNMiAxMiBRMTIgMiAyMiAxMiBRMTEgMjIgMiAxMloiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSI0IiBmaWxsPSIjMmE0ZWM5Ii8+PC9zdmc+"),
    auto;
}

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

@media (prefers-reduced-motion: reduce) {
  .record-hero-figure .anatomy-layer[data-layer="skeleton"] {
    opacity: 1;
  }
  .record-hero-figure .anatomy-layer[data-layer="brain"],
  .record-hero-figure .anatomy-layer[data-layer="neural"],
  .record-hero-figure .anatomy-layer[data-layer="circulatory"] {
    opacity: 0;
  }
  .record-hero-line .record-hero-body {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------------ nothing tree
   Stage 6 dappled-light tree from jzhao research, stripped of border,
   placed below the anatomy hero with the epigraph above it. */

.nothing-tree {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - var(--nav-top) - var(--nav-height));
  max-width: 900px;
  margin: 0 auto;
  padding: calc(var(--nav-top) + var(--nav-height) + 24px) var(--page-pad-x) 48px;
  box-sizing: border-box;
}

.nothing-tree .record-epigraph {
  margin-bottom: clamp(32px, 4vw, 52px);
  text-align: center;
}

.nothing-tree .record-epigraph-line + .record-epigraph-line {
  padding-left: 0;
}

.dappled-wrap {
  width: 100%;
  height: clamp(180px, 28vw, 280px);
  overflow: hidden;
  background: #fff;
  animation: dappled-arrive 900ms ease-out 200ms both;
}

@keyframes dappled-arrive {
  from {
    opacity: 0;
    transform: scale(0.97);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .dappled-wrap {
    animation: none;
  }
}

.dappled-wrap canvas {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.dappled-controls {
  display: flex;
  justify-content: flex-start;
  margin-top: 16px;
  font-family: var(--font-ibm-plex), "IBM Plex Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.04em;
}

.dappled-controls button {
  font-family: inherit;
  font-size: inherit;
  padding: 7px 14px;
  border: 1px solid var(--iov-rule);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}

.dappled-controls button:hover,
.dappled-controls button:focus-visible {
  background: var(--ink);
  color: var(--paper);
  outline: none;
}
