/* ============================================================
   CODEX — a manuscript under glass
   Two materials, strict roles:
     PAGE       the content. Book. Paper sheet, serif, ink. Always opaque.
     GLASS      the instrument. Chrome only. Never a reading surface.
     ATMOSPHERE what the glass refracts. Behind everything.
   Chapter Zero build — Dusk. The earlier Daybreak variant, and the Newsreader
   faces it set, were removed once Dusk shipped sitewide: nothing set
   data-variant to anything else, so both were unreachable.
   ============================================================ */

/* ---------- 1. Faces ------------------------------------------ */

/* size-adjust:124% dates from the Daybreak pairing, where EB Garamond's
   x-height measured 0.804 of Newsreader's at the same font-size — at 19px it
   read like 15px. Newsreader is gone; the correction stays, because the whole
   type scale is now built around the adjusted size rather than the raw one. */
@font-face { font-family:'EB Garamond'; src:url('assets/fonts/ebgaramond-latin.woff2') format('woff2-variations');
  font-weight:400 700; font-style:normal; font-display:swap; size-adjust:124%; }
@font-face { font-family:'EB Garamond'; src:url('assets/fonts/ebgaramond-latin-italic.woff2') format('woff2-variations');
  font-weight:400 700; font-style:italic; font-display:swap; size-adjust:124%; }
@font-face { font-family:'Cinzel'; src:url('assets/fonts/cinzel-latin.woff2') format('woff2-variations');
  font-weight:400 700; font-style:normal; font-display:swap; }
@font-face { font-family:'JetBrains Mono'; src:url('assets/fonts/jetbrainsmono-latin.woff2') format('woff2-variations');
  font-weight:400 600; font-style:normal; font-display:swap; }

/* ---------- 2. Shared tokens ---------------------------------- */

:root {
  --mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;

  --t-marginalia: 0.75rem;
  --t-small: 0.875rem;
  --t-body: 1.1875rem;
  --t-lead: clamp(1.25rem, 1.1rem + 0.65vw, 1.5rem);
  --t-h3: clamp(1.375rem, 1.15rem + 1vw, 2.125rem);
  --t-h2: clamp(1.875rem, 1.35rem + 2.3vw, 3rem);
  --t-h1: clamp(2.5rem, 1.6rem + 4.2vw, 4.25rem);
  --t-quest: clamp(1.75rem, 3.2vw, 3rem);

  --measure: 68ch;
  --leading: 1.66;
  --gutter: clamp(1.25rem, 0.6rem + 2.8vw, 3rem);
  --rail: 12.5rem;

  --sheet-radius: 18px;
  --glass-radius: 16px;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --reveal-dur: 500ms;
}

/* ---------- 4. Variant B — Dusk ------------------------------- */

[data-variant="dusk"] {
  --paper:    #F7F3E8;
  --ink:      #14121C;
  --graphite: #6A6579;
  --accent:   #5C46C8;                    /* on paper. 5.62:1 on the dusk sheet */
  --accent-air: #A192F5;                  /* on glass and atmosphere only. 5.02:1 on dusk glass */
  --accent-glow: color-mix(in oklab, var(--accent-air), #FFFFFF 30%);
  --rule:     color-mix(in srgb, var(--graphite) 26%, transparent);

  --serif: 'EB Garamond', Georgia, serif;
  --display: 'Cinzel', 'EB Garamond', Georgia, serif;
  --display-tracking: 0.01em;
  --display-transform: none;

  --atmos-base: #14121C;
  --atmos-1: rgba(120, 96, 220, 0.55);
  --atmos-2: rgba(58, 78, 190, 0.50);
  --atmos-3: rgba(196, 122, 190, 0.34);
  --atmos-4: rgba(40, 44, 96, 0.75);

  --sheet-bg:    color-mix(in srgb, var(--paper) 97%, transparent);
  --glass-bg:    color-mix(in srgb, #2A2740 52%, transparent);
  --nav-bg:      color-mix(in srgb, #24213A 90%, transparent);
  --glass-border: rgba(255,255,255,.20);
  --glass-shadow: 0 8px 34px rgba(0,0,0,.38), inset 0 1px 0 rgba(255,255,255,.16);
  --sheet-shadow: 0 2px 6px rgba(0,0,0,.28), 0 26px 70px rgba(0,0,0,.42);
}
/* On dusk the chrome sits on a dark ground, so its type inverts. */
[data-variant="dusk"] .glass,
[data-variant="dusk"] .nav-glass { color: #EDE9F5; }
[data-variant="dusk"] .glass .marginalia,
[data-variant="dusk"] .nav-glass .marginalia { color: #B9B2CE; }

/* ---------- 5. Reset & base ----------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--atmos-base);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t-body);
  line-height: var(--leading);
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
h1,h2,h3,h4,p,ul,ol,figure,blockquote { margin: 0; }
ul,ol { padding: 0; list-style: none; }
img { max-width: 100%; height: auto; display: block; }

/* ---------- 6. Atmosphere ------------------------------------- */

.atmos {
  position: fixed;
  inset: -12vmax;
  z-index: -2;
  background:
    radial-gradient(42vmax 38vmax at 14% 12%, var(--atmos-1), transparent 62%),
    radial-gradient(46vmax 40vmax at 84% 24%, var(--atmos-2), transparent 64%),
    radial-gradient(52vmax 46vmax at 68% 86%, var(--atmos-3), transparent 66%),
    radial-gradient(40vmax 36vmax at 22% 78%, var(--atmos-4), transparent 62%);
  background-color: var(--atmos-base);
  will-change: transform;
}
[data-motion="lively"] .atmos { animation: drift 110s ease-in-out infinite alternate; }
@keyframes drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(-2.5%, 1.5%, 0) scale(1.06); }
  100% { transform: translate3d(2%, -2%, 0) scale(1.03); }
}
/* a fine grain over the field so gradients never band */
.atmos::after {
  content: ''; position: absolute; inset: 0; opacity: .16; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* ---------- 7. Glass ------------------------------------------ */

.glass {
  background: var(--glass-bg);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  border-radius: var(--glass-radius);
  transition: transform 180ms var(--ease-out), border-color 180ms ease-out, background-color 180ms ease-out;
}
.glass:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--glass-border) 100%, white 30%); }
@supports not (backdrop-filter: blur(1px)) {
  .glass, .nav-glass { background: color-mix(in srgb, var(--paper) 88%, transparent); }
  [data-variant="dusk"] .glass, [data-variant="dusk"] .nav-glass { background: color-mix(in srgb, #2A2740 92%, transparent); }
}

/* ---------- 8. Nav — glass bar with running head -------------- */

.nav-wrap { position: sticky; top: 0; z-index: 40; padding: 0.75rem var(--gutter) 0; }
.nav-glass {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  max-width: 78rem; margin-inline: auto;
  padding: 0.7rem 1.15rem;
  border-radius: 999px;
  border: 1px solid transparent;
  background: transparent;
  box-shadow: none;
  transition: background-color 220ms ease-out, border-color 220ms ease-out,
              box-shadow 220ms ease-out, backdrop-filter 220ms ease-out;
}
/* The nav is the one glass surface that has to cross both grounds. At the
   shared 52% it composites to mid-grey over the cream sheet — which is most of
   every page's scroll — and takes its own links to 2.1:1. It gets its own,
   denser tint so the bar stays dark and legible on paper and on atmosphere
   alike. The blur still reads; only the certainty of the ground changes. */
.nav-glass.is-frosted {
  background: var(--nav-bg);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-color: var(--glass-border);
  box-shadow: var(--glass-shadow);
}
.nav-wordmark { font-family: var(--display); font-size: 1rem; letter-spacing: var(--display-tracking);
                color: inherit; text-decoration: none; white-space: nowrap; }
.running-head {
  flex: 1; text-align: center; min-width: 0;
  font-family: var(--mono); font-size: var(--t-marginalia); letter-spacing: .1em; text-transform: uppercase;
  color: var(--graphite);
  opacity: 0; transition: opacity 260ms ease-out;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.running-head.is-on { opacity: 1; }
[data-variant="dusk"] .running-head { color: #B9B2CE; }
.nav-links { display: flex; gap: 0; font-family: var(--mono); font-size: var(--t-marginalia);
             letter-spacing: .06em; text-transform: uppercase; }
.nav-links li + li::before { content: ', '; opacity: .5; white-space: pre; }
.nav-links a { color: inherit; opacity: .85; text-decoration: none; transition: opacity 140ms ease-out; }
.nav-links a:hover, .nav-links a[aria-current='page'] { opacity: 1; }
@media (max-width: 860px) { .running-head { display: none; } }

/* ---------- 9. The page sheet --------------------------------- */

.sheet {
  max-width: 78rem;
  margin: clamp(1rem, 0.5rem + 2vw, 2.5rem) auto clamp(3rem, 2rem + 4vw, 6rem);
  background: var(--sheet-bg);
  border-radius: var(--sheet-radius);
  box-shadow: var(--sheet-shadow);
  padding: clamp(2rem, 1.5rem + 4vw, 5rem) var(--gutter);
  position: relative;
}
[data-variant="dusk"] .sheet { color: var(--ink); }

/* ---------- 10. Type ------------------------------------------ */

h1, .h1 { font-family: var(--display); font-size: var(--t-h1); font-weight: 400; line-height: 1.05;
          letter-spacing: var(--display-tracking); text-transform: var(--display-transform); text-wrap: balance; }
h2 { font-family: var(--display); font-size: var(--t-h2); font-weight: 400; line-height: 1.12;
     letter-spacing: var(--display-tracking); text-wrap: balance; }
h3 { font-size: var(--t-h3); font-weight: 600; line-height: 1.2; }
h4 { font-size: var(--t-body); font-weight: 700; }
.lead { font-size: var(--t-lead); line-height: 1.44; text-wrap: pretty; }
.quiet { color: var(--graphite); }
em,i { font-style: italic; } strong,b { font-weight: 700; }

.marginalia { font-family: var(--mono); font-size: var(--t-marginalia); line-height: 1.5;
              letter-spacing: .06em; text-transform: uppercase; color: var(--graphite); }
.marginalia--plain { text-transform: none; letter-spacing: .02em; }

a { color: var(--accent); text-decoration: none;
    background-image: linear-gradient(var(--accent), var(--accent));
    background-repeat: no-repeat; background-position: 0 100%; background-size: 100% 1px;
    transition: background-size 180ms var(--ease-out), color 140ms ease-out; padding-bottom: .06em; }
a:hover { color: var(--accent-glow); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
::selection { background: var(--accent); color: var(--paper); }

.measure { max-width: var(--measure); }
.prose > * + *, .prose section > * + *, .prose .case-part > * + *, .prose .sub > * + * { margin-top: 1.35em; }
.prose p { text-wrap: pretty; }

.railed { display: grid; grid-template-columns: var(--rail) minmax(0, var(--measure)); gap: 0 var(--gutter); align-items: start; }
.railed > .rail-meta { text-align: right; padding-top: .45em; }
@media (max-width: 900px) {
  .railed { grid-template-columns: minmax(0,1fr); gap: .75rem; }
  .railed > .rail-meta { text-align: left; }
}

/* book details */
.dropcap::first-letter { float: left; font-size: 3.6em; line-height: .82; padding-right: .09em;
                         margin-top: .05em; color: var(--accent); font-family: var(--display); }
.scene { text-align: center; color: var(--graphite); margin-block: clamp(2.5rem,2rem + 2vw,4rem);
         font-size: 1.35rem; letter-spacing: .5em; text-indent: .5em; }
.numeral { display: block; font-family: var(--mono); font-size: var(--t-marginalia);
           letter-spacing: .2em; color: var(--graphite); margin-bottom: .85rem; }
.case-part { margin-top: clamp(2.5rem,1.8rem + 2vw,3.75rem); }
.case-part > h2 { font-family: var(--mono); font-size: var(--t-marginalia); font-weight: 500;
                  letter-spacing: .16em; text-transform: uppercase; color: var(--graphite); margin-bottom: .9rem; }
#question .case-statement { font-family: var(--display); font-size: var(--t-quest); line-height: 1.1;
                            letter-spacing: var(--display-tracking); max-width: 20ch; text-wrap: balance; }
.case-part .case-statement { font-size: var(--t-lead); line-height: 1.4; }
.verdict { font-size: var(--t-lead); line-height: 1.4; color: var(--accent); max-width: 34ch; margin-block: 2.5rem; }
.pull-quote { margin-block: 3.5rem; padding-left: 1.5rem; border-left: 2px solid var(--accent);
              font-size: var(--t-h3); line-height: 1.34; font-style: italic; }
.rule { border: 0; border-top: 1px solid var(--rule); margin-block: 3rem; }

/* decisions */
.decision { position: relative; margin-top: clamp(2.25rem,1.6rem + 2vw,3.25rem);
            padding-left: 1.5rem; border-left: 1px solid var(--rule); }
.decision > * + * { margin-top: 1.1em; }
.tradeoff, .rejected { font-size: var(--t-small); color: var(--graphite); max-width: 62ch; }
.tradeoff strong, .rejected strong { font-family: var(--mono); font-size: .82em; font-weight: 500;
                                     letter-spacing: .08em; text-transform: uppercase; }
.ghost-num { position: absolute; right: 100%; top: -.18em; margin-right: 1.25rem; font-family: var(--mono);
             font-size: clamp(4rem,10vw,11rem); line-height: .8; font-weight: 500;
             color: color-mix(in srgb, var(--ink) 6%, transparent); pointer-events: none; user-select: none; }
@media (max-width: 1240px) { .ghost-num { right: auto; left: 0; top: -.35em; font-size: clamp(3.5rem,12vw,7rem); } }

/* ---------- 11. Jump rail — glass with a ribbon bookmark ------ */

.rail-sticky { position: sticky; top: 5.5rem; }
.rail-card { padding: 1.1rem 1.15rem; }
.jump { margin-top: .85rem; display: grid; gap: .1rem; position: relative; }
.jump a { display: block; padding: .3rem .55rem; color: inherit; opacity: .6; background: none;
          border-radius: 6px; transition: opacity 140ms ease-out, color 140ms ease-out; }
.jump a:hover { opacity: 1; }
.jump a.is-active { opacity: 1; color: var(--accent); }
.ribbon { position: absolute; left: -1.15rem; width: 4px; border-radius: 0 3px 3px 0;
          background: var(--accent); box-shadow: 0 0 12px var(--accent-glow);
          transition: transform 320ms var(--ease-out), height 320ms var(--ease-out); }
@media (max-width: 900px) {
  .rail-sticky { position: static; }
  /* The rail becomes a masthead rather than a margin. It wraps instead of
     scrolling sideways: a contents list you have to drag to read is one most
     people will never reach the end of. */
  .jump { display: flex; flex-wrap: wrap; gap: .25rem .35rem; }
  .jump a { padding-inline: .5rem; }
  .ribbon { display: none; }
}

/* ---------- 12. Atmosphere window + glass metric cards -------- */
/* The sheet opens onto the sky. A child of the sheet cannot literally
   reveal what is behind its parent's background, so the window is built
   as a recess: the atmosphere's own colours painted into a band that
   runs to the sheet's edges, with an inset lip top and bottom. Glass
   cards then float on it exactly as they would on the real field. */

/* The window must reach the sheet's edges, but it is nested three levels
   inside the rail grid, so a gutter-sized negative margin only clears the
   prose column. It bleeds a full viewport either side instead and the
   sheet clips it. overflow: clip rather than hidden, because hidden would
   break the sticky rail. */
.sheet { overflow: clip; }
.window {
  position: relative;
  margin-inline: -50vw;
  padding-inline: 50vw;
  margin-block: clamp(3rem, 2rem + 3vw, 5rem);
  padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem);
  background-color: var(--atmos-base);
  background-image:
    radial-gradient(60% 120% at 12% 0%, var(--atmos-1), transparent 70%),
    radial-gradient(70% 130% at 88% 100%, var(--atmos-3), transparent 72%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), inset 0 -1px 0 rgba(0,0,0,.10);
}
[data-variant="dusk"] .window { color: #EDE9F5; }
[data-variant="dusk"] .window .marginalia,
[data-variant="dusk"] .window .quiet { color: #B9B2CE; }
[data-variant="dusk"] .window .case-part > h2 { color: #B9B2CE; }
[data-variant="dusk"] .window .receipt { color: #CFC8E0; background: rgba(255,255,255,.10); }
[data-variant="dusk"] .window a { color: var(--accent-glow); }
[data-variant="dusk"] .window .data-table th,
[data-variant="dusk"] .window .data-table td { border-bottom-color: rgba(255,255,255,.16); }

.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr)); gap: 1rem; margin-top: 1.75rem; }
.metric { padding: 1.3rem 1.2rem 1.15rem; }
.metric-figure { display: block; font-family: var(--display); font-size: clamp(2rem, 2.6vw, 2.6rem);
                 line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums lining-nums; }
[data-variant="dusk"] .metric-figure { font-family: var(--serif); }
.metric-label { display: block; margin-top: .65rem; }

/* ---------- 13. Plates ---------------------------------------- */

.plate { margin-top: 2.5rem; }
.plate img { border: 1px solid var(--rule); border-radius: 8px; }
.plate figcaption { margin-top: .75rem; }
.plate-caption .fig-num { color: var(--accent); }
.plate-row { margin-top: 2.5rem; display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem,1fr)); gap: var(--gutter); }
.plate-row .plate { margin-top: 0; }

/* ---------- 14. Tables, proof, receipts ----------------------- */

.data-table { width: 100%; border-collapse: collapse; margin-top: 1.5rem; font-size: var(--t-small); }
.data-table caption { text-align: left; margin-bottom: .75rem; }
.data-table th, .data-table td { text-align: left; padding: .6rem 1rem .6rem 0; border-bottom: 1px solid var(--rule); vertical-align: baseline; }
.data-table thead th { font-family: var(--mono); font-size: var(--t-marginalia); font-weight: 500;
                       letter-spacing: .1em; text-transform: uppercase; color: var(--graphite); }
.data-table .num { font-variant-numeric: tabular-nums lining-nums; text-align: right; white-space: nowrap; padding-right: 1.5rem; }
.table-scroll { overflow-x: auto; }
.proof { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem,1fr)); gap: 2rem var(--gutter);
         border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding-block: 2rem; }
.proof-figure { display: block; font-family: var(--display); font-size: clamp(2rem,2.4vw,2.5rem); line-height: 1;
                letter-spacing: -.03em; font-variant-numeric: tabular-nums lining-nums; }
.proof-label { display: block; margin-top: .7rem; }
/* A stated absence. Where a number does not exist, the page says so in its own
   voice rather than leaving a hole — set as an aside, not as a highlight, so it
   reads as part of the argument instead of an unfinished note. */
.gap { font-size: var(--t-small); color: var(--graphite); font-style: italic;
       border-left: 1px solid var(--rule); padding-left: 1.1rem; margin-top: 1.75rem;
       max-width: 58ch; }
[data-variant="dusk"] .window .gap { color: #C6BFD6; border-left-color: rgba(255,255,255,.22); }
.stack-footnote { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--rule); }
.sub { margin-top: 2.5rem; }
.cta { border-top: 1px solid var(--rule); padding-top: 2rem; }
.cta p { font-size: var(--t-lead); line-height: 1.35; max-width: 30ch; }

/* ---------- 15. Reading-mode toggle --------------------------- */

.mode-toggle { display: flex; gap: .2rem; align-items: center; padding: .25rem; border-radius: 999px; }
.mode-toggle button {
  font: inherit; font-family: var(--mono); font-size: 0.6875rem; letter-spacing: .08em; text-transform: uppercase;
  background: none; border: 0; color: inherit; opacity: .55; cursor: pointer;
  padding: .3rem .6rem; border-radius: 999px; transition: opacity 140ms ease-out, background-color 140ms ease-out;
}
.mode-toggle button:hover { opacity: .9; }
.mode-toggle button[aria-pressed="true"] { opacity: 1; background: color-mix(in srgb, var(--accent) 18%, transparent); }
/* The reader most likely to want a dark page is the one reading six thousand
   words on a phone at night, so the toggle stays on mobile. The bar has no
   room for it inline at 320px — wordmark plus four nav items already fills the
   line — so it takes its own row rather than compressing anything. */
@media (max-width: 700px) {
  .nav-glass { flex-wrap: wrap; row-gap: .35rem; column-gap: .75rem; }
  .mode-toggle { order: 3; flex-basis: 100%; justify-content: center; padding: 0 0 .1rem; }
  .mode-toggle button { font-size: 0.625rem; padding: .28rem .5rem; }
}

/* sepia reading mode — a page-only change, chrome untouched */
[data-reading="sepia"] .sheet { --paper: #F6EBD7; --ink: #23190E; background: color-mix(in srgb, #F6EBD7 97%, transparent); color: #23190E; }
[data-reading="dusk"]  .sheet { --paper: #211E2A; --ink: #E9E5F2; --graphite: #9C96AE; --rule: color-mix(in srgb, #9C96AE 26%, transparent);
                                background: color-mix(in srgb, #211E2A 96%, transparent); color: #E9E5F2; }
[data-reading="dusk"] .sheet .ghost-num { color: color-mix(in srgb, #E9E5F2 8%, transparent); }

/* ---------- 16. Footer ---------------------------------------- */

.footer-wrap { max-width: 78rem; margin: 0 auto clamp(1.5rem,1rem + 2vw,3rem); padding-inline: var(--gutter); }
.footer { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem 2rem; padding: 1.15rem 1.5rem; }
.footer-links { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.footer a { color: inherit; opacity: .85; background: none; }
.footer a:hover { opacity: 1; }

/* ---------- 17. Motion system --------------------------------- */

[data-motion="lively"] .reveal { opacity: 0; transform: translate3d(0, 16px, 0); }
[data-motion="lively"] .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--reveal-dur) var(--ease-out), transform var(--reveal-dur) var(--ease-out);
  transition-delay: var(--stagger, 0ms);
}
/* nothing above the fold waits on an animation */
[data-motion="lively"] .reveal--now { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .atmos { animation: none !important; }
  .reveal, .reveal.is-in { opacity: 1 !important; transform: none !important; transition: none !important; }
  .glass, .nav-glass, .jump a, a, .ribbon { transition: none !important; }
  .glass:hover { transform: none; }
}
[data-motion="calm"] .reveal { opacity: 1; transform: none; }
[data-motion="calm"] .atmos { animation: none; }

/* ---------- 18. Style tile ------------------------------------ */

.tile { max-width: 62rem; margin-inline: auto; padding: clamp(1.5rem,1rem + 3vw,3rem) var(--gutter) 4rem; }
.tile h1 { margin-bottom: .35rem; }
.tile-row { display: grid; gap: 1rem; margin-top: 1.25rem; }
.tile-sec { margin-top: 2.75rem; }
.tile-sec > .marginalia { margin-bottom: .9rem; }
.swatches { display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem,1fr)); gap: .75rem; }
.swatch { border-radius: 10px; padding: .75rem; min-height: 5.5rem; display: flex; align-items: flex-end;
          border: 1px solid var(--rule); }
.swatch span { font-family: var(--mono); font-size: .625rem; letter-spacing: .06em; }
.ramp > * { margin-top: .5rem; }

/* ---------- 19. Chrome corrections ---------------------------- */
/* The generic drawable underline is for prose links only. Chrome links
   opt out, or they render as underlined UI. */
.nav-wordmark, .nav-links a, .jump a, .footer a, .mode-toggle button,
.skip-link, .plate-caption a { background-image: none; padding-bottom: 0; }
.nav-wordmark:hover, .nav-links a:hover { color: inherit; }

/* Chrome links are 10–12px type, which is a 13px-tall tap target on a phone.
   The hit area is grown symmetrically and the growth is cancelled by an equal
   negative margin, so every one of these clears 44px without the bar, the rail
   or the footer moving by a pixel. Declared here because the reset above zeroes
   padding-bottom, and it has to lose that argument. */
.nav-wordmark, .nav-links a, .footer a {
  display: inline-block;
  padding-block: 0.9rem;
  margin-block: -0.9rem;
}
.jump a { display: inline-block; padding-block: 0.35rem; margin-block: -0.35rem; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper);
  padding: .75rem 1rem; font-family: var(--mono); font-size: var(--t-marginalia);
  border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* ---------- 20. Glass on paper vs glass on atmosphere --------- */
/* The rail sits ON the paper sheet, not on the atmosphere. Dark glass
   over a light sheet blurs to mud, so chrome that overlays the page uses
   a light glass in both variants. Only chrome over the atmosphere — nav,
   footer, the cards inside a window — takes the variant's own glass. */
.rail-card {
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  border-color: color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow: 0 4px 18px color-mix(in srgb, var(--ink) 8%, transparent),
              inset 0 1px 0 rgba(255,255,255,.5);
  color: var(--ink);
}
[data-variant="dusk"] .rail-card { color: var(--ink); }
[data-variant="dusk"] .rail-card .marginalia { color: var(--graphite); }
.rail-card:hover { transform: none; }

/* Cinzel is the ornament face — titles and kickers only. Question-length
   text is set in the body serif, or it stops being readable. */
[data-variant="dusk"] #question .case-statement { font-family: var(--serif); letter-spacing: 0; }

/* ---------- 21. Accent, split by ground ----------------------- */
/* Composite contrast caught this: dusk's lavender is 2.87:1 on the paper
   sheet and fails AA for body links. The glowing tone is kept, but only
   where it sits on glass or atmosphere; anything on paper uses the
   paper-safe accent. */
.window a, .window .verdict,
.nav-glass a, .footer a,
.metric-figure, .ribbon { --accent: var(--accent-air); }
.window a { color: var(--accent-air); background-image: linear-gradient(var(--accent-air), var(--accent-air)); }
.ribbon { background: var(--accent-air); box-shadow: 0 0 12px var(--accent-air); }
[data-variant="dusk"] .window .verdict { color: var(--accent-air); }

/* ---------- 22. Components the sample page did not exercise --- */

/* Home hero — poster scale */
/* The frontispiece is sized by the shorter axis as well as the wider one. On a
   900px-tall laptop an 8vw display face pushed the last two lines of the
   sentence below the fold — the poster was cropping its own argument. Binding
   it to vh keeps the whole sentence, the positioning line and the first proof
   card on the first screen at every size. */
.hero-poster h1 { font-size: clamp(2.5rem, min(7.4vw, 7vh), 7rem); line-height: 1.04; max-width: 16ch; }

/* The ladder, drawn on the atmosphere with glowing ticks */
.ladder { position: relative; padding-left: 2.9rem; }
.ladder::before { content:''; position:absolute; left:.3rem; top:.55em; bottom:.55em; width:2px;
                  background: currentColor; opacity:.25; transform-origin: top; }
[data-motion="lively"] .ladder--draw.is-drawn::before { animation: draw 900ms var(--ease-out) both; }
@keyframes draw { from { transform: scaleY(0);} to { transform: scaleY(1);} }
.rung { position: relative; padding-bottom: clamp(2.25rem,1.5rem + 2.5vw,3.5rem); }
.rung:last-child { padding-bottom: 0; }
.rung::before { content:''; position:absolute; left:-2.9rem; top:.62em; width:14px; height:2px;
                background: var(--accent); }
.rung.is-current::before { width:9px; height:9px; border-radius:50%; left:-3.05rem; top:calc(.62em - 3.5px);
                           box-shadow: 0 0 10px var(--accent); }
.window .rung::before, .window .rung.is-current::before { background: var(--accent-air); }
.window .rung.is-current::before { box-shadow: 0 0 14px var(--accent-air); }
.rung h3 { margin-top:.15rem; } .rung p { margin-top:.6rem; max-width:56ch; }
.rung-question { display:block; margin-top:.8rem; font-style:italic; color:var(--graphite); }
.window .rung-question { color: inherit; opacity:.72; }
@media (max-width:560px){ .ladder{padding-left:2rem} .rung::before{left:-2rem;width:11px}
                          .rung.is-current::before{left:-2.1rem} }

/* Work index rows */
.work-list { border-top:1px solid var(--rule); }
.work-row { border-bottom:1px solid var(--rule); padding-block: clamp(1.75rem,1rem + 2vw,2.75rem);
            transition: background-color 160ms ease-out; }
.work-row a.work-title { display:inline-block; font-family:var(--display); font-size:clamp(2rem,5vw,4rem);
                         line-height:1.04; letter-spacing:var(--display-tracking); color:var(--ink);
                         background:none; padding:0;
                         transition: transform 180ms var(--ease-out), color 140ms ease-out; }
.work-row--brief a.work-title { font-size:clamp(1.35rem,2.6vw,2rem); color:var(--graphite); }
.work-year { font-family:var(--mono); font-size:.26em; vertical-align:super; letter-spacing:.08em; color:var(--graphite); margin-left:.4em; }
.work-row--brief .work-year { font-size:.42em; }
.work-row p { margin-top:.5rem; max-width:62ch; } .work-row .marginalia { margin-top:.7rem; }
.work-row--brief p { color:var(--graphite); font-size:var(--t-small); }
.work-row a.work-title::after { content:' →'; opacity:0; margin-left:.15em; transition:opacity 180ms ease-out; }
.work-row:hover { background-color: color-mix(in srgb, var(--ink) 4%, transparent); }
.work-row:hover a.work-title { transform: translateX(6px); color: var(--accent); }
.work-row:hover a.work-title::after { opacity:1; }
.work-row--brief:hover a.work-title, .work-row--brief:hover p { color: var(--ink); }

/* Doors */
.doors { display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr)); gap:var(--gutter); }
.door { border-top:1px solid var(--rule); padding-top:1.15rem; }
.door h3 { margin-top:.5rem; } .door h3 a { color:var(--ink); background:none; padding:0; }
.door h3 a:hover { color:var(--accent); }
.door p { margin-top:.6rem; color:var(--graphite); font-size:var(--t-small); }

/* 404 — atmosphere with one glass card carrying the joke */
.error-wrap { min-height:64vh; display:grid; place-items:center; padding-inline:var(--gutter); }
/* place-items:center sizes the card to its content, so at 320px the display
   face's longest word set the card's width and pushed it past the viewport.
   The card is capped to the column and the headline scales from a lower floor,
   so the widest word always fits inside the padding box. */
.error { padding: clamp(1.25rem,1rem + 2.5vw,3.5rem); max-width:min(44rem,100%); min-width:0; border-left:0; }
.error h1 { max-width:18ch; font-size:clamp(1.75rem,1rem + 3.6vw,4.25rem); overflow-wrap:break-word; }
.error p { margin-top:1.5rem; }

/* /now readout as a glass terminal card */
.window .case-part > h2 { letter-spacing:.16em; }
main > section { padding-block: clamp(3rem,2rem + 5vw,6rem); }
.settle, .settle-2, .settle-3 { }

/* ---------- 23. Condition 2 — the glass rule, systematised ----- */
/* Chrome overlaying the page sheet uses LIGHT glass. Dusk's own glass
   belongs only to surfaces over the atmosphere. Expressed structurally:
   any .glass inside .sheet is light; .window re-darkens it, because a
   window IS the atmosphere showing through. Specificity does the work —
   `.sheet .window .glass` (3) beats `.sheet .glass` (2). */
.sheet .glass {
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  border-color: color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow: 0 4px 18px color-mix(in srgb, var(--ink) 8%, transparent),
              inset 0 1px 0 rgba(255,255,255,.5);
  color: var(--ink);
}
.sheet .glass .marginalia { color: var(--graphite); }
.sheet .glass a { color: var(--accent); }
.sheet .glass .metric-figure { color: var(--ink); }

.sheet .window .glass {
  background: var(--glass-bg);
  border-color: var(--glass-border);
  box-shadow: var(--glass-shadow);
  color: #EDE9F5;
}
.sheet .window .glass .marginalia { color: #B9B2CE; }
.sheet .window .glass a { color: var(--accent-air); }
.sheet .window .glass .metric-figure { color: #EDE9F5; }

/* 404 carries no sheet at all: one glass card on the open atmosphere (§4).
   .bare is the sheet's structural slot without the paper, so the card is
   genuinely over the atmosphere and keeps Dusk's own glass. */
.bare { max-width: 78rem; margin: clamp(1rem,.5rem + 2vw,2.5rem) auto clamp(3rem,2rem + 4vw,6rem);
        padding: clamp(2rem,1.5rem + 4vw,5rem) var(--gutter); }
.bare .error { max-width: 46rem; color: #EDE9F5; }
.bare .error .marginalia { color: #B9B2CE; }
.bare .error a { color: var(--accent-air); }

/* ---------- 24. Glass layer budget ---------------------------- */
/* The rule is at most three backdrop-filter surfaces in any viewport.
   Nav, rail and footer already spend that budget. Metric cards sit on a
   flat painted recess rather than on live content, so they gain nothing
   from a real blur — they take a slightly denser fill instead and drop
   the filter entirely. Keeps the budget and costs nothing visually. */
.metric { backdrop-filter: none; -webkit-backdrop-filter: none; }
.sheet .window .glass.metric { background: color-mix(in srgb, #2A2740 66%, transparent); }
.sheet .glass.metric { background: color-mix(in srgb, var(--paper) 72%, transparent); }

/* ---------- 25. Narrow-viewport nav --------------------------- */
/* Cinzel's wordmark plus four links overflows below ~420px. The nav
   tightens rather than wrapping, so the bar stays one line. */
@media (max-width: 460px) {
  .nav-wrap { padding-inline: 0.75rem; }
  .nav-glass { padding: 0.6rem 0.85rem; gap: 0.5rem; }
  .nav-wordmark { font-size: 0.8125rem; letter-spacing: 0; }
  .nav-links { font-size: 0.625rem; letter-spacing: 0.04em; }
}
@media (max-width: 360px) {
  .nav-wordmark { font-size: 0.75rem; }
  .nav-links { font-size: 0.5625rem; }
}

/* ---------- 26. View Transitions (progressive enhancement) ----- */
/* Cross-document cross-fade between pages. Browsers without support
   navigate instantly, exactly as before — nothing is required of them. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 250ms;
  animation-timing-function: var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* ---------- 27. The Frontispiece — Concept D, The Clean Sheet -- */

/* Deliberately tiny. D's first part is the sheet doing nothing, so nothing
   here has any resting effect: with JavaScript off, or under reduced motion,
   the hero is exactly the untouched typographic page. Everything below is
   either a transient state during the entrance, or a layer that lives
   strictly outside the paper. */

/* One block per line of the balanced wrap the browser already chose. nowrap
   makes the break points immovable while the mono frames change width; the
   clip is horizontal only, so descenders in the display face are untouched.
   Both wrappers are removed when the sentence settles. */
.hero-poster h1 .line {
  display: block;
  white-space: nowrap;
  overflow-x: clip;
  overflow-y: visible;
}

/* The words stay plain inline spans — an inline-block would take its
   baseline from its bottom edge and lift the whole line. */
.hero-poster h1 .word { display: inline; }

.hero-poster h1 .word.is-scrambling {
  font-family: var(--mono);
  font-size: 0.84em;
  letter-spacing: -0.02em;
  color: var(--graphite);   /* the machine's pass is not yet the author's ink */
}

/* Fixed, non-interactive, and sitting between the atmosphere (-2) and the
   sheet (auto, in flow) — which keeps it behind the paper in addition to the
   even-odd canvas clip. Two guards, not one. It adds no backdrop-filter, so
   the three-surface glass budget is untouched. */
canvas.constellation {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  contain: strict;
}

/* Both truths stated in CSS as well as in JS: if the script ever runs where
   motion is unwelcome, neither part appears. */
@media (prefers-reduced-motion: reduce) {
  canvas.constellation { display: none !important; }
  .hero-poster h1 .word.is-scrambling {
    font-family: inherit; font-size: inherit; letter-spacing: inherit; color: inherit;
  }
}

[data-motion="calm"] canvas.constellation { display: none !important; }

/* ---------- 28. The compression layer -------------------------
   The site's evidence was only ever legible to someone who read a
   five-thousand-word case study. These components carry the same evidence at
   thirty seconds and at ninety, using the page's own materials — hairlines,
   the mono label, the display face — and adding no new colour, no card
   chrome and no glass. Nothing here is decoration; every element holds a
   claim that appears in full further down. */

/* Standfirst above the frontispiece. States the role in words rather than
   leaving it to be inferred from an arrow four screens down. */
.identity { display: block; margin-bottom: clamp(1rem, 2.4vh, 2.5rem); color: var(--graphite); }
.identity strong { color: var(--ink); font-weight: 400; }

/* The positioning sentence. Serif, because it is prose and has to be read —
   the old subhead was 12px mono and carried the whole claim. */
.hero-lead { margin-top: clamp(1rem, 2.4vh, 2.5rem); max-width: 46ch;
             font-size: var(--t-lead); line-height: 1.42; text-wrap: pretty; }

/* Routes out. Text, ruled — not buttons; the site has never had a button. */
.hero-actions { display: flex; flex-wrap: wrap; gap: .9rem 1.75rem; align-items: baseline;
                margin-top: clamp(1rem, 2.4vh, 2.5rem); }
.hero-actions a { font-family: var(--mono); font-size: var(--t-marginalia); letter-spacing: .06em;
                  text-transform: uppercase; display: inline-block;
                  padding-block: .8rem; margin-block: -.8rem; }
/* One primary action. The other three stay exactly as available as they were
   and simply stop competing for the same weight. Colour and size only — no
   button, no fill, nothing this document would not otherwise contain. */
.hero-actions a:first-child { font-size: var(--t-small); letter-spacing: .04em;
                              color: var(--accent); font-weight: 500; }

/* Three figures set in the space the measure leaves empty on a wide screen.
   This is a frontispiece imprint, not a metrics widget: the same hairlines
   and marginalia voice as the rest of the page, and it falls back into normal
   flow below the width where the emptiness actually exists. */
/* Only shown where there is genuinely surplus width. Below that the Receipts
   section arrives immediately underneath and says the same thing at length,
   so this would be duplication and extra scrolling rather than evidence. */
.hero-proof { display: none; margin-top: clamp(1.75rem, 3.5vh, 2.75rem); }
.hero-proof ul { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.hero-proof li { display: flex; align-items: baseline; gap: .9rem;
                 padding-block: .8rem; border-bottom: 1px solid var(--rule); }
.hero-proof .marginalia { margin: 0; }
.hero-proof-fig { font-family: var(--serif); font-size: 1.6rem; line-height: 1;
                  letter-spacing: -.02em; font-variant-numeric: tabular-nums lining-nums;
                  min-width: 3ch; flex: 0 0 auto; }

@media (min-width: 80rem) {
  .hero-poster { display: grid; align-items: start;
                 grid-template-columns: minmax(0, 1fr) minmax(12rem, 17rem);
                 column-gap: clamp(2.5rem, 5vw, 5rem); }
  .hero-poster > .identity     { grid-area: 1 / 1 / 2 / 3; }
  .hero-poster > h1            { grid-area: 2 / 1 / 3 / 2; }
  .hero-poster > .hero-lead    { grid-area: 3 / 1 / 4 / 2; }
  .hero-poster > .hero-actions { grid-area: 4 / 1 / 5 / 2; }
  .hero-poster > .hero-proof   { display: block; grid-area: 3 / 2 / 5 / 3; margin-top: .4rem; }
}

/* Three decisions, on the homepage, with what each one cost. This is the
   thirty-second version of the thing the case studies do at length. */
.decisions { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
             gap: 0 var(--gutter); border-top: 1px solid var(--rule); }
.decision-card { border-bottom: 1px solid var(--rule); padding-block: 2rem; }
.decisions > .decision-card + .decision-card { border-top: 0; }
.decision-card h3 { font-size: clamp(1.25rem, 1.05rem + .55vw, 1.6rem); line-height: 1.22;
                    margin-top: .7rem; max-width: 24ch; }
.decision-card p { margin-top: .8rem; font-size: var(--t-small); line-height: 1.6; max-width: 34ch; }
.decision-card .cost { color: var(--graphite); }
.decision-card .cost strong { color: var(--ink); font-weight: 700; }
.decision-card .more { display: inline-block; margin-top: 1rem; font-family: var(--mono);
                       font-size: var(--t-marginalia); letter-spacing: .06em; text-transform: uppercase; }
@media (min-width: 52em) {
  .decisions { gap: 0 clamp(1.5rem, 1rem + 2vw, 3rem); }
  .decision-card { border-top: 0; }
}

/* An outcome, stated where the project is named rather than 2,400 words in. */
.outcome-line { display: flex; flex-wrap: wrap; gap: .4rem 1.5rem; margin-top: .9rem; }
.outcome-line span { font-family: var(--mono); font-size: var(--t-marginalia); letter-spacing: .05em;
                     text-transform: uppercase; color: var(--graphite); }
.outcome-line b { font-family: var(--display); font-size: 1.15em; font-weight: 400;
                  letter-spacing: -.01em; color: var(--ink); font-variant-numeric: tabular-nums lining-nums; }
.window .outcome-line b { color: inherit; }

/* The abstract that opens a long case study: the whole argument in six lines,
   so the depth below it is a choice rather than a toll. */
.abstract { border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
            padding-block: 1.75rem; margin-bottom: 2.5rem; }
.abstract dl { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .7rem 1.5rem; margin: 0; }
.abstract dt { font-family: var(--mono); font-size: var(--t-marginalia); letter-spacing: .06em;
               text-transform: uppercase; color: var(--graphite); padding-top: .28em; }
.abstract dd { margin: 0; font-size: var(--t-small); line-height: 1.6; }
.abstract dd b { font-weight: 700; }
@media (max-width: 34em) {
  .abstract dl { grid-template-columns: minmax(0, 1fr); gap: .2rem; }
  .abstract dt { padding-top: .9rem; }
}

/* ---------- 29. Figures — diagrams as plates ------------------
   The technically strongest projects had no visual evidence at all: the only
   images on the site belonged to three student projects, which is the wrong
   seniority signal by a decade. These figures are drawn in the page's own
   materials — hairline rules, the mono label, one accent stroke on the edge
   that carries the argument — so a diagram reads as a plate in a book rather
   than a slide pasted into one. Inline SVG: no request, no dependency, and it
   inherits the reading mode along with everything else. */

figure.fig { margin-top: 2.5rem; }
figure.fig svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Every stroke and label resolves against the page, so the figures follow the
   Paper / Sepia / Dusk toggle without a second set of assets. */
.fig .f-rule   { stroke: var(--rule); stroke-width: 1; fill: none; }
.fig .f-edge   { stroke: var(--graphite); stroke-width: 1; fill: none; }
.fig .f-key    { stroke: var(--accent); stroke-width: 1.5; fill: none; }
.fig .f-box    { stroke: var(--graphite); stroke-width: 1; fill: none; }
.fig .f-box-key{ stroke: var(--accent); stroke-width: 1.5; fill: none; }
.fig .f-fill   { fill: color-mix(in srgb, var(--graphite) 7%, transparent); stroke: none; }
.fig .f-head   { fill: var(--graphite); }
.fig .f-head-key { fill: var(--accent); }
.fig text      { font-family: var(--mono); fill: var(--ink); font-size: 11px; letter-spacing: .04em; }
.fig text.lbl  { text-transform: uppercase; font-size: 10px; letter-spacing: .07em; }
.fig text.dim  { fill: var(--graphite); text-transform: none; letter-spacing: .01em; font-size: 10.5px; }
.fig text.key  { fill: var(--accent); }
.fig .f-dash   { stroke-dasharray: 3 3; }

/* Inside a .window the figure sits on the atmosphere, so it inverts with it. */
.window .fig .f-rule   { stroke: rgba(255,255,255,.22); }
.window .fig .f-edge,
.window .fig .f-box    { stroke: rgba(255,255,255,.42); }
.window .fig .f-head   { fill: rgba(255,255,255,.42); }
.window .fig text      { fill: #EDE9F5; }
.window .fig text.dim  { fill: #C6BFD6; }
.window .fig .f-key,
.window .fig .f-box-key{ stroke: var(--accent-air); }
.window .fig .f-head-key { fill: var(--accent-air); }
.window .fig text.key  { fill: var(--accent-air); }
.window .fig .f-fill   { fill: rgba(255,255,255,.06); }

/* Wide figures scroll inside their own frame; the page never does. */
.fig-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.fig-scroll > svg { min-width: 34rem; }

/* ---------- 30. The founder pass ------------------------------
   The site was built to survive scrutiny and had stopped inviting any. These
   components move the weight from proving thoughtfulness to showing the work:
   the standfirst names what is being built before the argument starts, the
   stance list states a project's position without a paragraph of throat-
   clearing, and the fold lets a six-thousand-word record stay complete without
   charging every reader the toll. No new colour, no new material. */

/* The standfirst is now the first claim on the page rather than a caption to
   the headline, so it is set at reading size rather than at label size. */
.identity {
  font-family: var(--mono); font-size: var(--t-small); line-height: 1.5;
  letter-spacing: .06em; text-transform: uppercase; color: var(--graphite);
}
.identity a { color: inherit; background-image: linear-gradient(currentColor, currentColor); }
.identity a:hover { color: var(--accent); }

/* Four mono words at 12px were the whole navigation. 13px and a higher resting
   opacity cost nothing and stop the bar reading as a watermark. */
.nav-links { font-size: 0.8125rem; }
.nav-links a { opacity: .92; }

/* Where a project states its position: stage, what it is not, what it taught.
   Same grammar as the case-study abstract, without the enclosing rules — this
   sits inside prose rather than opening it. */
.stance { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .7rem 1.5rem;
          margin-top: 2rem; padding-left: 1.25rem; border-left: 1px solid var(--rule); }
.stance dt { font-family: var(--mono); font-size: var(--t-marginalia); letter-spacing: .06em;
             text-transform: uppercase; color: var(--graphite); padding-top: .28em; }
.stance dd { margin: 0; font-size: var(--t-small); line-height: 1.6; max-width: 56ch; }
@media (max-width: 34em) {
  .stance { grid-template-columns: minmax(0, 1fr); gap: .2rem; }
  .stance dt { padding-top: .9rem; }
}

/* Attribution, stated at the project rather than in a disclaimer at the bottom
   of the site. Set lower-case and at reading rhythm because it is a sentence,
   not a label — the mono voice would turn a genuine limit into decoration. */
.ownership { text-transform: none; letter-spacing: .01em; font-size: var(--t-small);
             line-height: 1.55; max-width: 62ch; margin-top: .9rem;
             padding-left: 1rem; border-left: 1px solid var(--rule); }
.ownership b { font-family: var(--mono); font-size: .8em; font-weight: 500;
               letter-spacing: .08em; text-transform: uppercase; color: var(--ink); }

/* The fold. Nothing is deleted to make a page shorter — the long record moves
   below a boundary the reader chooses to cross. Native <details>: no script, no
   dependency, keyboard-operable for free, and the content stays in the document
   for search and for anyone who prints it. */
.fold, .prose > .fold, .prose .case-part > .fold {
        margin-top: clamp(2.5rem, 1.8rem + 2vw, 3.75rem);
        border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
/* A hanging indent rather than a flex row: the label is a sentence that wraps,
   and a two-column row interleaved the second line of the title with the
   subtitle at every width narrow enough to wrap at all. */
.fold > summary {
  cursor: pointer; list-style: none; display: block; position: relative;
  padding: 1.15rem 0 1.15rem 1.6rem;
  font-family: var(--mono); font-size: var(--t-marginalia); line-height: 1.55;
  letter-spacing: .08em; text-transform: uppercase; color: var(--graphite);
  transition: color 140ms ease-out;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::marker { content: ''; }
.fold > summary::before {
  content: '+'; position: absolute; left: 0; top: 1.02rem;
  color: var(--accent); font-size: 1.15em; line-height: 1;
}
.fold[open] > summary::before { content: '−'; }
.fold > summary:hover { color: var(--ink); }
.fold > summary:hover::before { color: var(--accent); }
.fold-what { display: block; max-width: 58ch; }
/* No opacity here. Dimming graphite-on-paper a further 30% is how a label that
   passes contrast on its own turns into one that does not — axe caught exactly
   that, on twelve surfaces. The hierarchy is carried by position, not by tone. */
.fold-len { display: block; margin-top: .4rem; letter-spacing: .05em; }
.fold[open] > summary { border-bottom: 1px solid var(--rule); }
.fold > .fold-body { padding-top: .5rem; padding-bottom: 2rem; }
[data-variant="dusk"] .window .fold > summary { color: #B9B2CE; }
[data-variant="dusk"] .window .fold > summary::before { color: var(--accent-air); }

/* Six identical tiles stacked one-per-row was the second screen a phone got.
   Two columns from the narrowest viewport up: the figures are short, and a
   reader scanning evidence should be able to take it in without scrolling. */
@media (max-width: 40em) {
  .metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
  .metric { padding: 1rem .9rem .95rem; }
  .metric-figure { font-size: 1.75rem; }
}

/* The portrait was a hard black rectangle dropped onto cream paper — the one
   place on the site where an asset sat on the page instead of in it. The source
   photograph has a black studio ground and cannot be re-lit, so the ground is
   dissolved rather than kept: an elliptical mask fades the outer edge to
   nothing, and the greyscale is warmed a fraction so the plate belongs to the
   same paper as the type. No new asset, and it degrades to the plain photograph
   anywhere the mask is unsupported. */
.portrait { margin-top: 3rem; max-width: 24rem; }
.portrait img {
  display: block; width: 100%; border: 0;
  aspect-ratio: 5 / 6; object-fit: cover; object-position: 50% 14%;  /* trims dead ground */
  filter: grayscale(1) sepia(.16) contrast(1.06) brightness(1.02);
  -webkit-mask-image: radial-gradient(ellipse 66% 74% at 50% 42%, #000 34%, transparent 96%);
          mask-image: radial-gradient(ellipse 66% 74% at 50% 42%, #000 34%, transparent 96%);
}
.portrait figcaption { margin-top: .9rem; }

/* Every anchor on the site lands under the sticky bar — the jump rails on ten
   case studies, and the hero's own link down to the current work. One line,
   applied to the things that are actually targeted, rather than a scroll-padding
   on the root that would also shift keyboard focus scrolling. */
section[id], .case-part[id], details[id], figure[id] { scroll-margin-top: 6rem; }

/* The note under the receipts is a sentence explaining how to read numbers, not
   a label. Uppercase mono at full measure made the one paragraph on the page
   that most needs reading the hardest one to read. */
.reading-note { text-transform: none; letter-spacing: .015em; max-width: 78ch;
                line-height: 1.6; }
