/* ============================================================
   Mark Ulett — Personal site
   Sub-brand of BeargrassAI. Paper-primary; SOFT-axis Fraunces;
   saddle accent; editorial measure.
   ============================================================ */

@font-face {
  font-family: "Fraunces";
  src: url("https://media.beargrassai.com/markulett/fraunces-vf.ttf") format("truetype-variations"),
       url("https://media.beargrassai.com/markulett/fraunces-vf.ttf") format("truetype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Inherited BeargrassAI tokens */
  --ink:           #231f1a;
  --barn:          #a64b3b;
  --cream:         #f0e6cf;
  --warm-bright:   #f4c45a;
  --night:         #16212e;
  --paper:         #f4ebd7;

  /* Mark Ulett personal extension */
  --saddle:        #5d3220;          /* personal accent */
  --saddle-deep:   #3d1f10;          /* hover / press */
  --paper-warm:    #efe4c8;          /* one step deeper than paper */
  --paper-warmer:  #e8dcc0;          /* sunk well */
  --surface-card:  #f8f0dc;          /* card on paper */

  --fg:            var(--ink);
  --fg-muted:      #6b6359;
  --fg-subtle:     #8d8678;
  --fg-faint:      #a89e8a;

  --rule:          rgba(35, 31, 26, 0.16);
  --rule-strong:   rgba(35, 31, 26, 0.32);
  --rule-faint:    rgba(35, 31, 26, 0.08);

  /* Type */
  --font-serif:    "Fraunces", "Iowan Old Style", "Palatino", Georgia, serif;
  --font-mono:     ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  /* Editorial scale — slightly larger than BeargrassAI's website tokens
     because this is a reading surface, not a marketing surface */
  --t-xs:    11px;
  --t-sm:    14px;
  --t-base:  18px;
  --t-md:    21px;
  --t-lg:    26px;
  --t-xl:    34px;
  --t-2xl:   46px;
  --t-3xl:   64px;
  --t-4xl:   92px;

  --measure:       640px;     /* reading column */
  --measure-wide:  920px;     /* TOC / index pages */
  --gutter:        max(24px, 5vw);

  --s-1:  4px;  --s-2:  8px;  --s-3:  12px; --s-4:  16px;
  --s-5:  24px; --s-6:  32px; --s-7:  48px; --s-8:  64px;
  --s-9:  96px; --s-10: 128px;

  --r-sm: 2px; --r-md: 4px; --r-lg: 8px;

  --shadow-1: 0 1px 0 rgba(35, 31, 26, 0.06), 0 1px 2px rgba(35, 31, 26, 0.04);
  --shadow-2: 0 1px 0 rgba(35, 31, 26, 0.08), 0 4px 12px rgba(35, 31, 26, 0.06);

  --ease:        cubic-bezier(0.2, 0.7, 0.2, 1);
  --dur-fast:    120ms;
  --dur:         200ms;
  --dur-slow:    320ms;
}

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

html { font-size: 16px; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--fg);
  font-family: var(--font-serif);
  font-size: var(--t-base);
  line-height: 1.6;
  font-weight: 400;
  font-variation-settings: "opsz" 14, "SOFT" 30;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--warm-bright); color: var(--ink); }

/* ============================================================
   Type system
   ============================================================ */

h1, h2, h3, h4, p { margin: 0; }

.t-display {
  font-family: var(--font-serif);
  font-size: clamp(52px, 9vw, var(--t-4xl));
  line-height: 0.95;
  letter-spacing: -0.025em;
  font-weight: 600;
  font-variation-settings: "opsz" 120, "SOFT" 40;
  text-wrap: balance;
}

.t-h1 {
  font-family: var(--font-serif);
  font-size: clamp(36px, 5.2vw, var(--t-3xl));
  line-height: 1.02;
  letter-spacing: -0.018em;
  font-weight: 580;
  font-variation-settings: "opsz" 60, "SOFT" 35;
  text-wrap: balance;
}

.t-h2 {
  font-family: var(--font-serif);
  font-size: clamp(28px, 3.6vw, var(--t-2xl));
  line-height: 1.08;
  letter-spacing: -0.012em;
  font-weight: 560;
  font-variation-settings: "opsz" 40, "SOFT" 30;
  text-wrap: balance;
}

.t-h3 {
  font-family: var(--font-serif);
  font-size: var(--t-xl);
  line-height: 1.15;
  letter-spacing: -0.005em;
  font-weight: 580;
  font-variation-settings: "opsz" 30, "SOFT" 25;
}

.t-h4 {
  font-family: var(--font-serif);
  font-size: var(--t-lg);
  line-height: 1.25;
  font-weight: 600;
  font-variation-settings: "opsz" 24, "SOFT" 20;
}

.t-lede {
  font-family: var(--font-serif);
  font-size: clamp(20px, 2.4vw, var(--t-md));
  line-height: 1.45;
  font-weight: 400;
  font-style: italic;
  font-variation-settings: "opsz" 28, "SOFT" 55;
  color: var(--fg);
  text-wrap: pretty;
}

p {
  text-wrap: pretty;
  hanging-punctuation: first;
}

.t-caption {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
  font-feature-settings: "tnum";
}

.t-meta {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  font-feature-settings: "tnum";
}

.t-italic { font-style: italic; }

a {
  color: var(--saddle);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  text-decoration-color: rgba(93, 50, 32, 0.4);
  transition: text-decoration-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
a:hover { text-decoration-color: currentColor; color: var(--saddle-deep); }

/* ============================================================
   Wordmark — the brand's typographic moment.
   "Mark" SOFT 20 upright. "Ulett" SOFT 60 italic + 4° oblique.
   Doubled baseline rule beneath.
   ============================================================ */

.wm {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
}

.wm-row {
  display: inline-flex;
  align-items: baseline;
  gap: 0.18em;
}

.wm-mark {
  font-family: var(--font-serif);
  font-weight: 620;
  font-variation-settings: "opsz" 60, "SOFT" 20;
  letter-spacing: -0.018em;
}

.wm-ulett {
  font-family: var(--font-serif);
  font-weight: 460;
  font-style: italic;
  font-variation-settings: "opsz" 60, "SOFT" 60;
  letter-spacing: -0.005em;
  /* Brand's typographic move: 4° synthetic oblique on the soft segment
     (mirrors BeargrassAI's 4° oblique on "AI"). The font is already italic;
     the additional skew exaggerates the lean. */
  transform: skewX(-2.5deg);
  transform-origin: left bottom;
  color: var(--saddle);
}

/* Doubled baseline rule — 2 parallel 2px strokes with 2px gap */
.wm-rule {
  margin-top: 0.18em;
  height: 6px;
  width: 100%;
  background-image:
    linear-gradient(var(--ink), var(--ink)),
    linear-gradient(var(--saddle), var(--saddle));
  background-size: 100% 2px, 100% 2px;
  background-position: 0 0, 0 4px;
  background-repeat: no-repeat;
}

/* Small inline wordmark — for nav, footer */
.wm--sm .wm-mark { font-size: 22px; }
.wm--sm .wm-ulett { font-size: 22px; }
.wm--sm .wm-rule { height: 4px; background-size: 100% 1px, 100% 1px; background-position: 0 0, 0 3px; }

.wm--md .wm-mark { font-size: 36px; }
.wm--md .wm-ulett { font-size: 36px; }

.wm--xl .wm-mark { font-size: clamp(64px, 11vw, 140px); }
.wm--xl .wm-ulett { font-size: clamp(64px, 11vw, 140px); }
.wm--xl .wm-rule { height: 10px; background-size: 100% 3px, 100% 3px; background-position: 0 0, 0 7px; }

/* ============================================================
   Page chrome — nav + footer
   ============================================================ */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in oklab, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}

.site-nav-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 18px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
}

.site-nav-links {
  display: flex;
  align-items: center;
  gap: var(--s-6);
  list-style: none;
  padding: 0;
  margin: 0;
}

.site-nav-links a {
  font-family: var(--font-serif);
  font-size: 15px;
  font-weight: 500;
  font-variation-settings: "opsz" 14, "SOFT" 25;
  color: var(--fg-muted);
  text-decoration: none;
  letter-spacing: 0.01em;
  position: relative;
  padding: 4px 0;
  transition: color var(--dur) var(--ease);
}
.site-nav-links a:hover { color: var(--ink); }
.site-nav-links a[aria-current="page"] {
  color: var(--ink);
}
.site-nav-links a[aria-current="page"]::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 2px;
  background: var(--saddle);
}

/* CTA-styled nav item (Contact). Contained button look, stands apart from
   the underline/text nav items. */
.site-nav-links a.nav-cta {
  color: var(--ink);
  background: var(--warm-bright);
  padding: 7px 14px;
  border-radius: var(--r-md);
  font-weight: 560;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.site-nav-links a.nav-cta:hover {
  background: var(--saddle);
  color: var(--cream);
}
.site-nav-links a.nav-cta[aria-current="page"] {
  background: var(--saddle);
  color: var(--cream);
}
.site-nav-links a.nav-cta[aria-current="page"]::after {
  display: none;  /* no underline marker — the contained background is the cue */
}

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  padding: 8px 12px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);
}


/* ── Nav dropdown ──────────────────────────────────────────────
   The parent both navigates and discloses, so it stays a real <a> to its own hub
   page with an ADJACENT caret button beside it. Hover is a pointer-only
   convenience and deliberately does not move aria-expanded, because hovering has
   disclosed nothing to a screen reader. The caret button is the touch and
   keyboard path and owns the state. */
.nav-has-sub {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
}
.nav-caret {
  appearance: none;
  background: none;
  border: 0;
  padding: 4px 2px;
  cursor: pointer;
  line-height: 1;
  color: var(--fg-subtle);
  transition: color var(--dur) var(--ease);
}
.nav-caret::before {
  content: '\25BE';
  display: block;
  font-size: 10px;
  transition: transform var(--dur) var(--ease);
}
.nav-caret:hover { color: var(--ink); }
.nav-has-sub.is-open > .nav-caret::before { transform: rotate(180deg); }

.subnav {
  position: absolute;
  top: calc(100% + 12px);
  left: -12px;
  z-index: 30;
  min-width: 196px;
  margin: 0;
  padding: var(--s-3) 0;
  list-style: none;
  background: var(--surface-card);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
}
.nav-has-sub.is-open > .subnav {
  opacity: 1;
  visibility: visible;
  transform: none;
}
/* pointer devices only: on touch, :hover sticks after a tap and the menu will not
   dismiss, which is why this is gated rather than applied to everything */
@media (hover: hover) and (pointer: fine) {
  .nav-has-sub:hover > .subnav {
    opacity: 1;
    visibility: visible;
    transform: none;
  }
}
.subnav a {
  display: block;
  padding: 7px var(--s-4);
  font-size: var(--t-sm);
  white-space: nowrap;
}

@media (max-width: 720px) {
  .site-nav-links { display: none; }
  .nav-toggle { display: block; }
  .site-nav.is-open { padding-bottom: 8px; }
  .site-nav.is-open .site-nav-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-3);
    flex-basis: 100%;
    padding: var(--s-4) var(--gutter) var(--s-3);
    margin-top: var(--s-3);
    border-top: 1px solid var(--rule);
  }
  .site-nav.is-open .site-nav-inner { flex-wrap: wrap; }
  /* submenu goes static inside the open burger; the caret has no job here
     because there is no hover to disclose against */
  .nav-has-sub { flex-wrap: wrap; }
  .nav-caret { display: none; }
  .subnav {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    min-width: 0;
    width: 100%;
    padding: var(--s-2) 0 0 var(--s-4);
    background: none;
    border: 0;
    box-shadow: none;
  }
  .subnav a { padding: 5px 0; }

}

/* Footer */
.site-foot {
  margin-top: var(--s-10);
  padding: var(--s-8) 0 var(--s-7);
  border-top: 1px solid var(--rule);
  background: var(--paper-warm);
}

.site-foot-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr 1fr;
  gap: var(--s-7);
  align-items: start;
}
@media (max-width: 760px) {
  .site-foot-inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
  .site-foot-inner { grid-template-columns: 1fr; }
}

.site-foot h4 {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--fg-subtle);
  margin-bottom: var(--s-4);
}

.site-foot ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.site-foot a { font-size: 16px; color: var(--ink); text-decoration: none; }
.site-foot a:hover { color: var(--saddle); }

.foot-brand-note {
  font-size: 14px;
  color: var(--fg-muted);
  line-height: 1.55;
  margin-top: var(--s-3);
  max-width: 32ch;
}

.foot-bg-mark {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding: 6px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-muted);
  background: var(--paper);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.foot-bg-mark:hover { border-color: var(--saddle); color: var(--ink); }
.foot-bg-mark svg { color: var(--saddle); }

.site-foot-base {
  max-width: 1200px;
  margin: var(--s-8) auto 0;
  padding: var(--s-5) var(--gutter) 0;
  border-top: 1px solid var(--rule-faint);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

/* ============================================================
   Layout primitives
   ============================================================ */

.page {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--s-9) var(--gutter) 0;
}

.reading {
  max-width: var(--measure);
  margin: 0 auto;
}

.wide {
  max-width: var(--measure-wide);
  margin: 0 auto;
}

.stack > * + * { margin-top: var(--s-5); }
.stack-tight > * + * { margin-top: var(--s-3); }
.stack-wide > * + * { margin-top: var(--s-7); }

.prose p { font-size: var(--t-base); line-height: 1.7; color: var(--fg); }
.prose p + p { margin-top: var(--s-4); }
.prose strong { font-weight: 580; color: var(--ink); }
.prose em { font-style: italic; }

/* Section header pattern — caption + h2, with thin saddle rule above */
.section-head {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule-strong);
  margin-bottom: var(--s-6);
}
.section-head .t-caption { color: var(--saddle); }

/* Doubled-rule structural divider — used once per page max */
.divider-doubled {
  height: 10px;
  margin: var(--s-8) 0;
  background-image:
    linear-gradient(var(--ink), var(--ink)),
    linear-gradient(var(--saddle), var(--saddle));
  background-size: 100% 1px, 100% 1px;
  background-position: 0 0, 0 4px;
  background-repeat: no-repeat;
}

/* Hairline divider */
hr {
  border: none;
  height: 1px;
  background: var(--rule);
  margin: var(--s-7) 0;
}

/* Pullquote */
.pullquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(24px, 3.2vw, 32px);
  line-height: 1.35;
  font-variation-settings: "opsz" 40, "SOFT" 55;
  color: var(--ink);
  margin: var(--s-8) 0;
  padding: 0;
  text-align: left;
  border: none;
  position: relative;
  padding-left: var(--s-5);
  border-left: 2px solid var(--saddle);
}

/* Closing call to action. Deliberately NOT a quote.
   This was being drawn with .pullquote plus three inline overrides cancelling
   that component's own rule, border, padding and alignment. If a component needs
   three overrides to do a job, the job needs its own component. Upright rather
   than italic, because italic display serif is the thing that made a direct
   address to the reader read as somebody being quoted. Sits on the reading rail
   like the prose above it, and sizes off the type scale rather than a raw clamp. */
.page-cta {
  font-family: var(--font-serif);
  font-size: var(--t-lg);
  line-height: 1.4;
  font-variation-settings: "opsz" 32, "SOFT" 55;
  color: var(--ink);
  max-width: var(--measure);
  margin: 0;
}
.page-cta a {
  color: var(--saddle);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  transition: color var(--dur) var(--ease);
}
.page-cta a:hover { color: var(--saddle-deep); }

/* Heading rhythm inside .prose. Scoped to `* + h2` on purpose: on /about/ every
   h2 is the FIRST child of its own .prose block, so a blanket margin-top would
   shift that page. This only fires when a heading actually follows something,
   which is the generated-page case where the two were touching at 0px. */
.prose > * + h2 { margin-top: var(--s-8); }
.prose > * + h3 { margin-top: var(--s-7); }

/* Essay section bands.
   Full-bleed so the tone change reads across the whole window rather than as a
   tinted column. The inner div holds the reading measure, so the text column is
   unchanged and only the ground under it alternates. */
.essay-band {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: var(--s-8) var(--gutter);
}
.essay-band-inner {
  max-width: var(--measure);
  margin: 0 auto;
}
/* adjacent bands must touch: a margin between them shows body colour through and
   reads as a stripe rather than a seam */
.essay > .essay-band + .essay-band { margin-top: 0; }
/* the first heading in a band already has the band's own top padding */
.essay-band-inner > h2:first-child { margin-top: 0; }

/* Essay byline and dek.
   The dek is a full sentence carrying the essay's argument, and it is marked
   rather than boxed: .dek-mark is inline, so the highlight wraps with the text
   the way a highlighter would, and box-decoration-break keeps the padding on
   every line instead of only the first and last. */
.essay-byline {
  margin: var(--s-3) 0 0;
  font-family: var(--font-serif);
  font-size: var(--t-sm);
  font-style: italic;
  color: var(--fg-muted);
}
.essay-dek {
  margin: var(--s-6) 0 0;
  max-width: var(--measure);
}
.dek-mark {
  display: inline;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--t-md);
  line-height: 1.55;
  color: var(--ink);
  background: var(--warm-bright);
  padding: 2px 6px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* Card grid. The hand-written pages draw this shape with an inline grid each
   time; generated sections use the class so the column rules live in one place. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: var(--s-6);
}
.card-grid .card h3 {
  margin: 0 0 var(--s-3);
  font-size: var(--t-lg);
}
.card-grid .card p:last-child { margin-bottom: 0; }

/* Callout. For limits and caveats: the material this section carries is only
   honest if what it does NOT prove is set out as plainly as what it does. */
.callout {
  border-left: 2px solid var(--saddle);
  padding: var(--s-2) 0 var(--s-2) var(--s-5);
  margin: var(--s-7) 0;
  color: var(--fg-muted);
}
.callout p { margin-bottom: var(--s-4); }
.callout p:last-child { margin-bottom: 0; }
.callout strong { color: var(--ink); }

/* In-essay figure. These essays run very long in one narrow column with no
   visual rest, which is what this is for. width/height are stamped on the img
   so the box is reserved before the image loads and the text below does not
   jump. */
.essay .essay-figure,
.essay > .essay-figure + *,
.essay-band-inner > .essay-figure + * {
  margin-top: var(--s-8);
}
.essay-figure {
  margin: var(--s-8) 0;
}
.essay-figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-sm);
}
.essay-figure figcaption {
  margin-top: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
  color: var(--fg-subtle);
}

/* Caption block — date/location stamp */
.dateline {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
}
.dateline .dot {
  display: inline-block;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--saddle);
}

/* ============================================================
   Buttons
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 12px 22px;
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 540;
  font-variation-settings: "opsz" 14, "SOFT" 25;
  border-radius: var(--r-md);
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease), background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.btn-primary {
  background: var(--saddle);
  color: var(--paper);
  border-color: var(--saddle);
}
.btn-primary:hover {
  background: var(--saddle-deep);
  border-color: var(--saddle-deep);
  transform: translateY(-1px);
}
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule-strong);
}
.btn-ghost:hover {
  border-color: var(--ink);
  transform: translateY(-1px);
}
.btn-arrow::after {
  content: '→';
  margin-left: 4px;
  transition: transform var(--dur) var(--ease);
}
.btn:hover .btn-arrow::after,
.btn-arrow:hover::after { transform: translateX(3px); }

/* ============================================================
   Card recipes
   ============================================================ */

.card {
  background: var(--surface-card);
  border-radius: var(--r-md);
  padding: var(--s-5) var(--s-6);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
a.card { color: inherit; text-decoration: none; display: block; }
a.card:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); }

/* ============================================================
   Photography — full-bleed treated images
   ============================================================ */

.photo-bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: var(--ink);
}
.photo-bleed img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 80vh;
  object-fit: cover;
}

.photo-frame {
  position: relative;
  background: var(--paper-warmer);
  padding: 0;
  border-radius: 0;
  overflow: hidden;
}
.photo-frame img {
  display: block;
  width: 100%;
  height: auto;
}
.photo-frame .photo-caption {
  padding: 12px 16px 16px;
}
.photo-caption {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  margin-top: var(--s-3);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.photo-caption .figno {
  color: var(--saddle);
}

/* ============================================================
   TOC (Home) — almanac-style index of pages
   ============================================================ */

.toc {
  border-top: 1px solid var(--rule-strong);
}
.toc-row {
  display: grid;
  grid-template-columns: 60px 1.6fr 2.4fr auto;
  align-items: baseline;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: background var(--dur) var(--ease);
  margin: 0 calc(-1 * var(--s-3));
  padding-left: var(--s-3);
  padding-right: var(--s-3);
}
.toc-row:hover {
  background: var(--paper-warm);
}
.toc-row:hover .toc-arrow { transform: translateX(4px); color: var(--saddle); }

.toc-num {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--fg-subtle);
}
.toc-title {
  font-family: var(--font-serif);
  font-size: 26px;
  font-weight: 560;
  font-variation-settings: "opsz" 28, "SOFT" 25;
  letter-spacing: -0.012em;
  color: var(--ink);
}
.toc-desc {
  font-family: var(--font-serif);
  font-size: 16px;
  font-style: italic;
  font-variation-settings: "opsz" 14, "SOFT" 50;
  color: var(--fg-muted);
  line-height: 1.45;
}
.toc-arrow {
  font-family: var(--font-serif);
  font-size: 22px;
  color: var(--fg-subtle);
  transition: transform var(--dur) var(--ease), color var(--dur) var(--ease);
}
@media (max-width: 720px) {
  .toc-row {
    grid-template-columns: 36px 1fr auto;
    gap: var(--s-4);
  }
  .toc-desc { display: none; }
  .toc-title { font-size: 22px; }
}

/* ============================================================
   Numbers (almanac)
   ============================================================ */

.numbers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s-6) var(--s-7);
}
.number {
  border-top: 1px solid var(--rule-strong);
  padding-top: var(--s-3);
}
.number-figure {
  font-family: var(--font-serif);
  font-size: clamp(48px, 6vw, 76px);
  font-weight: 500;
  font-variation-settings: "opsz" 96, "SOFT" 45;
  line-height: 1;
  letter-spacing: -0.025em;
  color: var(--saddle);
  display: block;
}
.number-figure sup {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  color: var(--fg-subtle);
  letter-spacing: 0.1em;
  vertical-align: top;
  margin-left: 6px;
  position: relative;
  top: 0.4em;
}
.number-label {
  font-size: 15px;
  color: var(--fg-muted);
  line-height: 1.5;
  margin-top: var(--s-2);
  max-width: 28ch;
}

/* ============================================================
   Page header (sub-pages)
   ============================================================ */

.page-head {
  max-width: var(--measure);
  margin: 0 auto;
  padding-bottom: var(--s-7);
}
.page-head-eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--saddle);
  margin-bottom: var(--s-4);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.page-head-eyebrow::before {
  content: '';
  width: 36px;
  height: 6px;
  background-image:
    linear-gradient(var(--saddle), var(--saddle)),
    linear-gradient(var(--saddle), var(--saddle));
  background-size: 100% 1px, 100% 1px;
  background-position: 0 1px, 0 4px;
  background-repeat: no-repeat;
}

/* ============================================================
   Marginalia (long-form pages) — Tufte-style side note
   ============================================================ */

.with-margin {
  display: grid;
  grid-template-columns: 1fr min(var(--measure), 100%) 1fr;
  column-gap: var(--s-5);
}
.with-margin > * { grid-column: 2; }
.with-margin > .margin-note {
  grid-column: 3;
  align-self: start;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--t-sm);
  line-height: 1.45;
  font-variation-settings: "opsz" 12, "SOFT" 55;
  color: var(--fg-muted);
  max-width: 24ch;
  padding-left: var(--s-4);
  border-left: 1px solid var(--saddle);
  margin-top: 6px;
}
@media (max-width: 960px) {
  .with-margin { grid-template-columns: 1fr; }
  .with-margin > * { grid-column: 1; }
  .with-margin > .margin-note {
    grid-column: 1;
    max-width: 36ch;
    margin-top: var(--s-3);
  }
}

/* ============================================================
   Resume-style entries
   ============================================================ */

.entries { list-style: none; padding: 0; margin: 0; }
.entry {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--rule);
}
.entry:first-child { border-top: 1px solid var(--rule-strong); }
.entry-date {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--fg-subtle);
  padding-top: 5px;
}
.entry-title {
  font-family: var(--font-serif);
  font-size: 20px;
  font-weight: 600;
  font-variation-settings: "opsz" 20, "SOFT" 25;
  color: var(--ink);
  margin: 0;
  line-height: 1.25;
}
.entry-role {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 15px;
  color: var(--fg-muted);
  margin: 2px 0 6px;
  font-variation-settings: "opsz" 14, "SOFT" 55;
}
.entry-desc {
  font-size: 16px;
  color: var(--fg);
  line-height: 1.55;
}
@media (max-width: 600px) {
  .entry { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* ============================================================
   Now page — log book
   ============================================================ */

.logbook { list-style: none; padding: 0; margin: 0; }
.logbook li {
  display: grid;
  grid-template-columns: 14px 1fr;
  gap: var(--s-4);
  padding: var(--s-3) 0;
  align-items: baseline;
}
.logbook li::before {
  content: '';
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--saddle);
  margin-top: 8px;
}
.logbook li.muted::before { background: var(--rule-strong); }
.logbook strong { font-weight: 580; color: var(--ink); display: inline-block; margin-right: 4px; }

/* ============================================================
   Forms
   ============================================================ */

.field { margin-bottom: var(--s-4); }
.field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: var(--s-2);
}
.field input,
.field textarea {
  width: 100%;
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 17px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  outline: none;
  resize: vertical;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.field input:focus,
.field textarea:focus {
  border-color: var(--saddle);
  box-shadow: 0 0 0 3px rgba(166, 75, 59, 0.15);
}

.ask-form {
  margin-top: var(--s-5);
}
.ask-form .field { margin-bottom: var(--s-4); }
.ask-form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: var(--s-4);
}
.ask-form input,
.ask-form textarea {
  width: 100%;
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 17px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  outline: none;
  resize: vertical;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.ask-form input:focus,
.ask-form textarea:focus {
  border-color: var(--saddle);
  box-shadow: 0 0 0 3px rgba(166, 75, 59, 0.15);
}

.entry-read {
  margin-top: 12px;
}

.entries > article.entry {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  border-top: 1px solid var(--rule);
}
.entries > article.entry:first-child { border-top: none; }

.card.card-vibe h3.entry-title {
  font-size: var(--t-h3-size, 22px);
  font-family: var(--font-serif);
  font-weight: 560;
}

.contact-ways-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 900px) {
  .contact-ways-grid { grid-template-columns: 1fr; }
}
.contact-ways-grid .card-vibe h3 {
  font-size: var(--t-h4-size, 20px);
  margin-bottom: 16px;
}

/* ============================================================
   Utility
   ============================================================ */

.text-saddle { color: var(--saddle); }
.text-muted { color: var(--fg-muted); }
.text-ink { color: var(--ink); }
.italic { font-style: italic; }
.center { text-align: center; }

.subtle-bg { background: var(--paper-warm); }
.deeper-bg { background: var(--paper-warmer); }

.hide-on-mobile { }
@media (max-width: 720px) { .hide-on-mobile { display: none !important; } }

/* ============================================================
   V2 — vibe pass
   ============================================================ */

/* Paper grain — very subtle SVG noise overlay on body */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.4;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.55 0 0 0 0 0.45 0 0 0 0 0.30 0 0 0 0.06 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}
body > * { position: relative; z-index: 1; }

/* Section bands — full-width regardless of parent */
.band {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: var(--s-10) var(--gutter);
}
@media (max-width: 720px) { .band { padding: var(--s-8) var(--gutter); } }

/* Background-change boundaries need their own space.
   .page carries no bottom padding on purpose: the next section's padding-top
   supplies the gap, and that works while both sections sit on one background.
   It breaks the moment a .page is followed by a full-bleed .band, because the
   band paints its background at the exact boundary — so the last element in the
   .page lands flush on a colour change with nothing under it. A button as the
   last element is the worst case: it is a heavy object and reads as if it fell
   off the edge. Fire on the structural condition rather than patching the two
   pages that show it today, so a new page cannot reintroduce it. */
.page:has(+ .band) { padding-bottom: var(--s-9); }
@media (max-width: 720px) { .page:has(+ .band) { padding-bottom: var(--s-8); } }

.band-paper { background: var(--paper); color: var(--ink); }
.band-paper-warm { background: var(--paper-warm); color: var(--ink); }
.band-paper-deep { background: var(--paper-warmer); color: var(--ink); }

.band-night {
  background: var(--night);
  color: var(--cream);
  position: relative;
  overflow: hidden;
}
.band-night a { color: var(--warm-bright); text-decoration-color: rgba(244,196,90,0.4); }
.band-night a:hover { color: var(--warm-bright); text-decoration-color: currentColor; }
.band-night .t-caption,
.band-night .t-meta { color: rgba(240, 230, 207, 0.55); }
.band-night .section-head { border-top-color: rgba(240, 230, 207, 0.3); }
.band-night .section-head .t-caption { color: var(--warm-bright); }

/* ============================================================
   SCENE — Glacier ridge at sunrise (SVG illustration)
   Layered: sky gradient → sun disc → far ridge → mid ridge → near ridge → fg
   ============================================================ */

.scene-glacier {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: linear-gradient(180deg, #0a1024 0%, #16212e 35%, #2a2433 70%, #4a2c1f 100%);
  overflow: hidden;
  isolation: isolate;
}
.scene-glacier .scene-svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Slow sun-rise on load */
@keyframes sun-rise {
  from { transform: translateY(40px); }
  to { transform: translateY(0); }
}
.scene-sun {
  animation: sun-rise 2.4s var(--ease) both;
  transform-origin: center;
}

/* Stars twinkle, then settle. BOUNDED — see THE SAFARI LAW note at .coord-badge
   .pulse and at the depth-and-motion block at the foot of this file. This rule
   ran unbounded until 2026-08-24 and rendered on ten pages, which is the exact
   ingredient that pairs with a fixed background-size:cover layer to trip the
   WebKit compositor. Six iterations is ~22s of sky, then the stars hold at the
   opacity each one carries in its own markup. */
@keyframes twinkle {
  0%, 100% { opacity: 0.25; }
  50% { opacity: 0.95; }
}
.scene-star {
  animation: twinkle 3.6s ease-in-out 6;
}
.scene-star:nth-child(2n) { animation-duration: 4.2s; animation-delay: 1.1s; }
.scene-star:nth-child(3n) { animation-duration: 5s; animation-delay: 2.2s; }

/* ============================================================
   Wordmark draw-in animation
   ============================================================ */

@keyframes mark-fade-in {
  from { transform: translateY(12px); }
  to { transform: translateY(0); }
}
@keyframes rule-draw {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.wm-animated .wm-mark { animation: mark-fade-in 700ms var(--ease) both; }
.wm-animated .wm-ulett { animation: mark-fade-in 700ms 180ms var(--ease) both; }
/* Rule does not animate — keeps it visible in static captures and reduced-motion users. */

/* ============================================================
   Scroll-revealed motion (IntersectionObserver applies .is-visible)
   ============================================================ */

.reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.reveal:nth-child(2) { transition-delay: 80ms; }
.reveal:nth-child(3) { transition-delay: 160ms; }
.reveal:nth-child(4) { transition-delay: 240ms; }
.reveal:nth-child(5) { transition-delay: 320ms; }
.reveal:nth-child(6) { transition-delay: 400ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-visible { opacity: 1; transform: none; transition: none; }
  .scene-sun, .scene-star, .wm-animated * { animation: none !important; }
}

/* ============================================================
   Poster moments — giant typography
   ============================================================ */

.poster-quote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(36px, 6vw, 86px);
  line-height: 1.05;
  font-weight: 400;
  font-variation-settings: "opsz" 120, "SOFT" 60;
  letter-spacing: -0.015em;
  color: var(--cream);
  text-wrap: balance;
}
.poster-quote .accent { color: var(--warm-bright); }

.poster-attribution {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(240, 230, 207, 0.55);
  margin-top: var(--s-5);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.poster-attribution::before {
  content: '';
  width: 32px;
  height: 1px;
  background: var(--warm-bright);
}

/* ============================================================
   Stat poster — for night band
   ============================================================ */

.stat-poster {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-7);
}
@media (max-width: 900px) { .stat-poster { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .stat-poster { grid-template-columns: 1fr; } }

.stat-poster .stat {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-4);
  border-top: 1px solid rgba(240, 230, 207, 0.3);
}
.stat-fig {
  font-family: var(--font-serif);
  font-size: clamp(56px, 7vw, 96px);
  font-weight: 500;
  font-variation-settings: "opsz" 144, "SOFT" 45;
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: var(--warm-bright);
}
.stat-label {
  font-family: var(--font-serif);
  font-size: 15px;
  font-style: italic;
  font-variation-settings: "opsz" 14, "SOFT" 55;
  color: rgba(240, 230, 207, 0.75);
  line-height: 1.45;
  max-width: 26ch;
}
.stat-year {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(240, 230, 207, 0.5);
}

/* ============================================================
   Topo motif — a topographic ridge line drawn as inline SVG
   used in section dividers and page-head eyebrows.
   ============================================================ */

.topo-divider {
  width: 100%;
  height: 28px;
  display: block;
  color: var(--saddle);
  opacity: 0.7;
}
.band-night .topo-divider { color: var(--warm-bright); opacity: 0.5; }

/* ============================================================
   Sinopah SVG cameo
   ============================================================ */

.sinopah-peek {
  position: absolute;
  bottom: 0;
  right: var(--gutter);
  width: 90px;
  height: 90px;
  pointer-events: none;
  opacity: 0.95;
  color: var(--saddle);
  transform: translateY(8px);
  transition: transform 400ms var(--ease);
}
.sinopah-peek:hover { transform: translateY(0); }

/* ============================================================
   Hero CTAs — beefier
   ============================================================ */

.hero-cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

.btn-warm {
  background: var(--warm-bright);
  color: var(--night);
  border-color: var(--warm-bright);
}
.btn-warm:hover {
  background: #f7d175;
  border-color: #f7d175;
  transform: translateY(-1px);
}

.btn-night-ghost {
  background: transparent;
  color: var(--cream);
  border-color: rgba(240,230,207,0.4);
}
.btn-night-ghost:hover {
  border-color: var(--cream);
  background: rgba(240,230,207,0.06);
  transform: translateY(-1px);
}

/* TOC enhancement — give rows more personality */
.toc-row {
  position: relative;
}
.toc-row::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--saddle);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--dur-slow) var(--ease);
}
.toc-row:hover::before { transform: scaleY(1); }

/* Card vibe — make them feel less like brochure cards */
.card.card-vibe {
  position: relative;
  overflow: hidden;
}
.card.card-vibe::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--saddle);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-slow) var(--ease);
}
.card.card-vibe:hover::after { transform: scaleX(1); }

/* Coordinate badge for hero */
.coord-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: 8px 14px;
  border: 1px solid rgba(240,230,207,0.3);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(240,230,207,0.85);
  background: rgba(10,16,36,0.4);
  backdrop-filter: blur(6px);
}
/* Bounded on purpose. A continuous unbounded animation on this site is the pattern that
   produced a WebKit GPU runaway on another property in 2026-08. Not worth the risk for a
   decorative badge. */
.coord-badge .pulse {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--warm-bright);
  box-shadow: 0 0 0 0 rgba(244,196,90,0.6);
  animation: pulse 2.2s 6;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(244,196,90,0.55); }
  70% { box-shadow: 0 0 0 10px rgba(244,196,90,0); }
  100% { box-shadow: 0 0 0 0 rgba(244,196,90,0); }
}

/* ============================================================
   V3 — page heroes. Shared night-band hero pattern for every page.
   Each page provides its own SVG focal scene + chapter copy.
   ============================================================ */

.hero-night {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  min-height: 560px;
  background: linear-gradient(180deg, #0a1024 0%, #16212e 38%, #2a2433 70%, #4a2c1f 92%, #5d3220 100%);
  overflow: hidden;
  isolation: isolate;
  color: var(--cream);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.hero-night.hero-night-sm { min-height: 480px; }

.hero-night a { color: var(--warm-bright); text-decoration-color: rgba(244,196,90,0.4); }

/* Base sky layer — stars (rendered inline SVG inside) */
.hero-sky {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero-sky > svg { width: 100%; height: 100%; display: block; }

/* Mountain ridges — share the silhouette layered look */
.hero-ridges {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 1;
  pointer-events: none;
}
.hero-ridges > svg { width: 100%; height: auto; display: block; }

/* Scene focal element overlay (page-specific) */
.hero-scene {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

/* Content overlay */
.hero-content {
  position: relative;
  z-index: 5;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 80px var(--gutter) 28px;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}
.hero-content h1 {
  font-family: var(--font-serif);
  color: var(--cream);
  font-size: clamp(40px, 5.4vw, 76px);
  line-height: 1.02;
  letter-spacing: -0.022em;
  font-weight: 580;
  font-variation-settings: "opsz" 96, "SOFT" 35;
  text-wrap: balance;
  max-width: 22ch;
  margin: 0;
}
.hero-content .hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--warm-bright);
}
.hero-content .hero-eyebrow::before {
  content: '';
  display: inline-block;
  width: 36px;
  height: 6px;
  background-image:
    linear-gradient(var(--warm-bright), var(--warm-bright)),
    linear-gradient(var(--cream), var(--cream));
  background-size: 100% 1px, 100% 1px;
  background-position: 0 1px, 0 4px;
  background-repeat: no-repeat;
}
.hero-content .hero-lede {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(18px, 2vw, 22px);
  line-height: 1.5;
  font-weight: 400;
  font-variation-settings: "opsz" 24, "SOFT" 55;
  color: rgba(240, 230, 207, 0.88);
  max-width: 60ch;
  text-wrap: pretty;
}

/* Bottom meta row — coord badge, timestamp, page mark */
.hero-bottom {
  position: relative;
  z-index: 5;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--gutter) 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-5);
  flex-wrap: wrap;
}
.hero-bottom-mark {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(240, 230, 207, 0.5);
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
}
.hero-bottom-mark .ch-mark {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 14px;
  font-variation-settings: "opsz" 14, "SOFT" 55;
  color: var(--warm-bright);
  text-transform: none;
  letter-spacing: 0;
}

@media (max-width: 720px) {
  .hero-night { min-height: 480px; }
  .hero-content { padding: 60px var(--gutter) 20px; gap: var(--s-3); }
  .hero-bottom { padding-bottom: 20px; }
}

/* Page-specific scene helpers — small animations.

   ALL BOUNDED as of 2026-08-24. Every rule in this block ran unbounded and
   every one of them renders on a live page: glow-node on /about and /work,
   ember on /contact, signal-ring on /about, /contact and /work. A continuous
   compositor animation on the same page as a fixed background-size:cover layer
   is the pair that produced the WebKit rasterization runaway on another site in
   2026-07, where five fixes aimed at the element that was visibly breaking and
   the cause was a pulsing dot somewhere else. Since this pass adds exactly such
   a backdrop to four of these pages, the motion now ends.

   Where the natural resting state is "gone" — an ember, a signal ring — the
   animation is `forwards` so it holds the final keyframe instead of snapping
   back to a static dot. */
@keyframes glow-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}
.glow-node { animation: glow-pulse 3.4s ease-in-out 7; transform-origin: center; }
.glow-node:nth-child(2n) { animation-delay: 1.2s; animation-duration: 4.1s; }
.glow-node:nth-child(3n) { animation-delay: 2.4s; animation-duration: 5s; }

@keyframes ember-drift {
  0% { transform: translateY(0) translateX(0); opacity: 0; }
  10% { opacity: 0.8; }
  100% { transform: translateY(-200px) translateX(-30px); opacity: 0; }
}
.ember { animation: ember-drift 4.5s linear 6 forwards; transform-origin: center; }
.ember:nth-child(2n) { animation-delay: 1.5s; animation-duration: 5.4s; }
.ember:nth-child(3n) { animation-delay: 2.8s; animation-duration: 6s; }
.ember:nth-child(4n) { animation-delay: 0.8s; animation-duration: 4s; }

@keyframes signal-pulse {
  0% { transform: scale(0.9); opacity: 0; }
  30% { opacity: 0.9; }
  100% { transform: scale(2.2); opacity: 0; }
}
.signal-ring {
  transform-origin: center;
  animation: signal-pulse 3s ease-out 8 forwards;
}
.signal-ring:nth-child(2) { animation-delay: 1s; }
.signal-ring:nth-child(3) { animation-delay: 2s; }

/* `typewriter-key` / .tw-key removed 2026-08-24: an unbounded animation that
   rendered on no page. Measured before deleting — zero .tw-key elements across
   all sixteen built pages. */

@keyframes sun-track {
  from { stroke-dashoffset: 800; }
  to { stroke-dashoffset: 0; }
}
.sun-track-path {
  stroke-dasharray: 800;
  stroke-dashoffset: 800;
  animation: sun-track 3.6s var(--ease) forwards;
}

@media (prefers-reduced-motion: reduce) {
  .glow-node, .ember, .signal-ring { animation: none !important; }
  /* .ember and .signal-ring rest at opacity 0 via `forwards`, so with motion
     off they must be hidden outright or they freeze as static dots and rings. */
  .ember, .signal-ring { opacity: 0 !important; }
  /* were outside every reduced-motion block until 2026-08-21 */
  .coord-badge .pulse, .scene-star, .twinkle { animation: none !important; }
  .sun-track-path { stroke-dashoffset: 0 !important; animation: none !important; }
}

/* ============================================================
   Fabric dividers — reusable section breaks
   ============================================================ */

.fabric-horizon {
  width: 100%;
  height: 64px;
  display: block;
  color: var(--saddle);
  opacity: 0.6;
}
.band-night .fabric-horizon { color: var(--warm-bright); opacity: 0.5; }

.fabric-rain {
  width: 100%;
  height: 36px;
  display: block;
  color: var(--saddle);
  opacity: 0.5;
}

.fabric-plumes {
  width: 100%;
  height: 48px;
  display: block;
  color: var(--saddle);
  opacity: 0.7;
}

/* Inline beargrass plume — for inline use next to chapter labels */
.plume-inline {
  display: inline-block;
  width: 32px;
  height: 12px;
  vertical-align: middle;
  margin-right: 8px;
  color: var(--saddle);
}
.band-night .plume-inline { color: var(--warm-bright); }

/* Horizon transition strip — drawn under the hero, blends night → paper */
.horizon-transition {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  height: 64px;
  background: linear-gradient(180deg, #5d3220 0%, #efe4c8 100%);
  overflow: hidden;
  isolation: isolate;
}
.horizon-transition::before {
  content: '';
  position: absolute;
  inset: 0;
  /* Beargrass cluster silhouette */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 64' preserveAspectRatio='xMidYEnd slice'%3E%3Cg stroke='%230a0606' stroke-width='1.4' stroke-linecap='round' opacity='0.8'%3E%3Cline x1='80' y1='64' x2='80' y2='30'/%3E%3Cline x1='130' y1='64' x2='130' y2='40'/%3E%3Cline x1='180' y1='64' x2='180' y2='24'/%3E%3Cline x1='240' y1='64' x2='240' y2='38'/%3E%3Cline x1='300' y1='64' x2='300' y2='28'/%3E%3Cline x1='370' y1='64' x2='370' y2='42'/%3E%3Cline x1='440' y1='64' x2='440' y2='22'/%3E%3Cline x1='510' y1='64' x2='510' y2='36'/%3E%3Cline x1='580' y1='64' x2='580' y2='30'/%3E%3Cline x1='650' y1='64' x2='650' y2='40'/%3E%3Cline x1='720' y1='64' x2='720' y2='26'/%3E%3Cline x1='790' y1='64' x2='790' y2='36'/%3E%3Cline x1='860' y1='64' x2='860' y2='24'/%3E%3Cline x1='930' y1='64' x2='930' y2='40'/%3E%3Cline x1='1000' y1='64' x2='1000' y2='30'/%3E%3Cline x1='1070' y1='64' x2='1070' y2='42'/%3E%3Cline x1='1140' y1='64' x2='1140' y2='22'/%3E%3Cline x1='1210' y1='64' x2='1210' y2='36'/%3E%3Cline x1='1280' y1='64' x2='1280' y2='28'/%3E%3Cline x1='1350' y1='64' x2='1350' y2='40'/%3E%3Cline x1='1420' y1='64' x2='1420' y2='26'/%3E%3Cline x1='1490' y1='64' x2='1490' y2='36'/%3E%3Cline x1='1560' y1='64' x2='1560' y2='30'/%3E%3C/g%3E%3Cg fill='%23f0e6cf' opacity='0.65'%3E%3Ccircle cx='80' cy='28' r='2'/%3E%3Ccircle cx='180' cy='22' r='2.2'/%3E%3Ccircle cx='300' cy='26' r='2'/%3E%3Ccircle cx='440' cy='20' r='2.4'/%3E%3Ccircle cx='580' cy='28' r='2'/%3E%3Ccircle cx='720' cy='24' r='2.2'/%3E%3Ccircle cx='860' cy='22' r='2.4'/%3E%3Ccircle cx='1000' cy='28' r='2'/%3E%3Ccircle cx='1140' cy='20' r='2.4'/%3E%3Ccircle cx='1280' cy='26' r='2'/%3E%3Ccircle cx='1420' cy='24' r='2.2'/%3E%3Ccircle cx='1560' cy='28' r='2'/%3E%3C/g%3E%3C/svg%3E");
  background-size: cover;
  background-position: center bottom;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Beargrass plume divider — sits between paper sections */
.plume-band {
  width: 100%;
  height: 42px;
  display: block;
  margin: 32px auto;
  color: var(--saddle);
  opacity: 0.7;
}

/* ============================================================
   MOBILE FIXES (added 2026-05-19)
   Inline grid-template-columns on six page sections does not
   collapse on phones. These rules use !important to win over
   inline-style specificity. Also caps the hero wordmark so
   "MarkUlett" fits at ~390px without clipping.
   ============================================================ */
@media (max-width: 720px) {
  /* Every inline multi-column grid collapses to one column */
  [style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
    gap: var(--s-6) !important;
  }

  /* Hero wordmark floor: 64px was clipping at the right edge */
  .wm--xl .wm-mark,
  .wm--xl .wm-ulett {
    font-size: clamp(46px, 13vw, 96px);
  }
  .wm--xl .wm-rule {
    height: 6px;
    background-size: 100% 2px, 100% 2px;
    background-position: 0 0, 0 4px;
  }

  /* HOME HERO — break out of the SVG's 16:9 aspect ratio on phones.
     The default sizing makes .scene-glacier 219px tall at 390px wide;
     the overlay (wordmark + lede + CTAs + coord badge) needs ~450px,
     and the section's overflow:hidden was clipping it. Give the hero
     a real mobile height, stretch the SVG to cover, and let the
     overlay stack inside it without overflow. */
  .scene-glacier {
    min-height: 600px; /* fallback */
    min-height: 100svh; /* modern browsers override fallback */
  }
  .scene-glacier .scene-svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }
  .scene-glacier .scene-overlay > div[style*="padding-top: 80px"] {
    padding-top: 64px !important;
    justify-content: flex-start !important;
    gap: var(--s-4);
  }
  .scene-glacier .scene-overlay > div:last-child {
    justify-content: flex-start !important;
    gap: var(--s-3) !important;
    padding-bottom: 24px !important;
  }
  .scene-glacier .t-lede {
    font-size: clamp(15px, 4.4vw, 19px);
    margin-top: 20px !important;
  }
  .scene-glacier .hero-cta-row {
    margin-top: 24px !important;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-3);
  }
  .scene-glacier .hero-cta-row .btn { width: 100%; text-align: center; }

  /* Stat poster figures: cap so 100k+ and 1,150 do not overflow */
  .stat-fig { font-size: clamp(48px, 17vw, 88px); }
  .stat-poster { gap: var(--s-7); }

  /* Pull-quote on the night band */
  .poster-quote { font-size: clamp(22px, 6.4vw, 36px); }

  /* Sinopah cameo SVG: smaller corner placement */
  .sinopah-peek { width: 80px !important; }

  /* Campfire photo bleed: 4:3 reads better than 16:7 on phone */
  .photo-bleed img {
    aspect-ratio: 4 / 3 !important;
    object-position: 50% 40% !important;
  }

  /* Contact form: two-column name/email/topic row collapses cleanly */
  #contact-form .field { width: 100%; }

  /* Section heads: shrink the eyebrow gap so it does not eat
     the top of every collapsed section */
  .section-head { margin-bottom: var(--s-5); }
}

/* ==========================================================================
   Essay prose — /writing/<slug>. Added 2026-08-13 when the essays were brought
   onto this domain. Reusable for every future essay; no per-page styling.
   ========================================================================== */

.essay {
  max-width: var(--measure);
  margin: 0 auto;
}

/* Body rhythm. Both selectors are needed: the article's direct children are now
   .essay-band sections, so a `.essay > * + *` rule alone stops reaching the
   paragraphs entirely and the text collapses into one solid block. */
.essay > * + *,
.essay-band-inner > * + * { margin-top: var(--s-5); }

.essay p {
  font-size: var(--t-base);
  line-height: 1.68;
  color: var(--fg);
}

.essay h2 {
  font-family: var(--font-serif);
  font-size: var(--t-lg);
  line-height: 1.15;
  letter-spacing: -0.008em;
  font-weight: 560;
  font-variation-settings: "opsz" 36, "SOFT" 30;
  margin-top: var(--s-8);
  text-wrap: balance;
}

.essay h3 {
  font-family: var(--font-serif);
  font-size: var(--t-md);
  line-height: 1.22;
  font-weight: 580;
  margin-top: var(--s-7);
  text-wrap: balance;
}

.essay blockquote {
  margin-left: 0;
  margin-right: 0;
  padding-left: var(--s-5);
  border-left: 2px solid var(--warm-bright);
  font-family: var(--font-serif);
  font-size: var(--t-md);
  font-style: italic;
  line-height: 1.5;
  color: var(--fg-muted);
}

.essay ul, .essay ol { padding-left: var(--s-5); }
.essay li { font-size: var(--t-base); line-height: 1.68; }
.essay li + li { margin-top: var(--s-3); }
.essay strong { font-weight: 640; }
.essay hr { border: 0; border-top: 1px solid var(--rule-faint); margin: var(--s-8) auto; width: 40%; }

.essay-head { max-width: var(--measure); margin: 0 auto var(--s-8); }
.essay-head h1 { margin-top: var(--s-4); }
.essay-meta { display: flex; gap: var(--s-4); flex-wrap: wrap; margin-top: var(--s-5); }

.essay-foot {
  max-width: var(--measure);
  margin: var(--s-9) auto 0;
  padding-top: var(--s-6);
  border-top: 1px solid var(--rule);
}

.essay-cta {
  font-size: var(--t-base);
  line-height: 1.6;
  color: var(--fg-muted);
  margin-bottom: var(--s-5);
}

/* ==========================================================================
   Hero contrast scrim. Added 2026-08-14.

   The drifting page graphics in .hero-scene are cream, and so is the hero
   headline. Where they overlap, cream sits on cream and the text disappears
   regardless of stacking order: .hero-content is already above the art at
   z-index 5, so raising it further does nothing. What was missing was
   anything BETWEEN them.

   This sits at z-index 3 and darkens the region the text occupies, anchored
   to the bottom and the left, so the art stays visible where the text is not.
   Same anchored-scrim technique the social card compositor uses.
   ========================================================================== */

.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    linear-gradient(to top,
      rgba(10, 16, 36, 0.94) 0%,
      rgba(10, 16, 36, 0.82) 24%,
      rgba(10, 16, 36, 0.42) 52%,
      rgba(10, 16, 36, 0.00) 76%),
    linear-gradient(to right,
      rgba(10, 16, 36, 0.58) 0%,
      rgba(10, 16, 36, 0.22) 46%,
      rgba(10, 16, 36, 0.00) 72%);
}

/* ==========================================================================
   DEPTH AND MOTION — added 2026-08-24, pattern library BgAI-SKL-025.

   Four techniques, all browser-native, no library:
     1. a fixed photographic backdrop the page scrolls over
     2. one scroll listener that writes --scroll-y / --scroll-progress
     3. masks, so an edge fades over photography instead of being cut
     4. layered radial gradients, so a band has depth instead of a flat fill

   THE SAFARI LAW applies to everything below. Nothing here runs unbounded; every animation is bounded by an iteration count.
   The backdrop is a STILL layer: it carries no animation and no transform,
   because a fixed background-size:cover layer combined with continuous motion
   is the exact pair that produced the WebKit compositor runaway on another
   site in 2026-07.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. The fixed photographic backdrop
   --------------------------------------------------------------------------
   position:fixed, NOT background-attachment:fixed. The latter janks on iOS and
   repaints on every scroll frame. The image is set per page through custom
   properties on the element so this rule stays generic:

     <div class="site-backdrop site-backdrop--feature" aria-hidden="true"
          style="--bd-md:url('/assets/x-1600.jpg');--bd-lg:url('/assets/x-2400.jpg')"></div>

   The photograph is decoration, so it is a CSS background and the element is
   aria-hidden. The page's meaningful <img> with its alt text stays in the DOM
   for the mobile treatment and for anything reading the raw HTML.
   -------------------------------------------------------------------------- */

/* THE BACKDROP IS A CSS PROPERTY, NOT AN ELEMENT. [MARK] 2026-09-10: "Delete the element from
   markulett." It was a fixed, aria-hidden, pointer-events:none <div> that held no words and received
   no clicks — it existed only to paint, which is what CSS is for. NO OTHER TENANT HAS ONE: the Ranch
   puts a background on the element it sits behind (.cta-bg, .nav-guide__feat-bg--*) and v1 markulett
   had no such element at all, so this was one site's invention.
   IT ALSO COST A FALSE BAND. bands.mjs measures getBoundingClientRect(), so a fixed full-viewport
   layer reported as an 800px band on every page — a permanent +1 against the reference that no amount
   of site work could ever close.
   The photograph is body's own background (attachment:fixed reproduces position:fixed). The scrim is
   body::after; body::before is already the paper grain and is untouched. */
body {
  background-image: var(--bd-md);
  background-attachment: fixed;
  background-position: var(--bd-pos, center center);
  background-size: cover;
  background-repeat: no-repeat;
}
body.bd-feature {
  --bd-md: url('https://media.beargrassai.com/markulett/hero-truck-1600.jpg');
  --bd-lg: url('https://media.beargrassai.com/markulett/hero-truck-2400.jpg');
  --bd-pos: center 44%;
}

/* Inner-page atmosphere backdrops — parity with markulett-site v1, 2026-08-31 */
@media (min-width: 821px) {
  body.bd-inner[data-page="about"] {
    --bd-md: url('https://media.beargrassai.com/markulett/hero-about-1200.jpg');
    --bd-lg: url('https://media.beargrassai.com/markulett/hero-about-2000.jpg');
    --bd-pos: center 42%;
  }
  body.bd-inner[data-page="work"] {
    --bd-md: url('https://media.beargrassai.com/markulett/hero-work-1200.jpg');
    --bd-lg: url('https://media.beargrassai.com/markulett/hero-work-2000.jpg');
    --bd-pos: center 52%;
  }
  body.bd-inner[data-page="writing"] {
    --bd-md: url('https://media.beargrassai.com/markulett/hero-writing-1200.jpg');
    --bd-lg: url('https://media.beargrassai.com/markulett/hero-writing-2000.jpg');
    --bd-pos: center 46%;
  }
  /* contact has NO backdrop photograph. The reference hero is a drawn SVG night scene
     (section.hero-night with no has-backdrop); letting the fixed photo through made it a pale
     mountain where the reference is dark navy. about, work and writing DO carry one. 2026-09-10. */
}
@media (min-width: 1501px) {
  body { background-image: var(--bd-lg, var(--bd-md)); }
}

/* The scrim is the whole craft: one linear for top-to-bottom legibility, one
   radial to vignette the edges. Without it, text over photography is a coin
   toss. Two strengths, because the two jobs are different. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* FEATURE — the photograph is the subject (home). Light enough to still read
   as a photograph; the hero's own wedge does the heavy lifting under the type. */
body.bd-feature::after {
  background:
    linear-gradient(to bottom,
      rgba(6, 10, 24, 0.50) 0%,
      rgba(6, 10, 24, 0.16) 34%,
      rgba(6, 10, 24, 0.70) 100%),
    radial-gradient(120% 80% at 50% 0%,
      rgba(6, 10, 24, 0.00) 0%,
      rgba(6, 10, 24, 0.46) 100%);
}

/* ATMOSPHERE — the photograph is the room, not the subject (inner pages).
   Their heroes are CONTENT: a career map, a systems constellation, essay cards
   drawn in 9px mono. A photograph competes with fine linework, so it is pushed
   most of the way to black and reads as depth behind the diagram rather than
   as a picture. This is the difference between the treatment that worked and
   the one reverted on 2026-08-21. */
body.bd-atmosphere::after {
  background:
    linear-gradient(to bottom,
      rgba(10, 16, 36, 0.74) 0%,
      rgba(10, 16, 36, 0.60) 32%,
      rgba(10, 16, 36, 0.91) 100%),
    radial-gradient(130% 90% at 50% 6%,
      rgba(10, 16, 36, 0.22) 0%,
      rgba(10, 16, 36, 0.84) 100%);
}

/* Once the opaque content has covered the viewport the backdrop cannot be seen,
   so stop compositing it. Set by the IntersectionObserver in the site script;
   a hard flip, no transition, because it happens where nothing is visible.
   This is an optimisation and nothing may depend on it: the script does not run
   under reduced motion, so the rule below is what actually contains the photo. */
/* THE PARKING OPTIMISATION IS GONE with the element it hid, and its own comment said nothing may
   depend on it: the script does not run under reduced motion, so the rule was never what contained
   the photograph. site.js guards with `if (backdrop && zone && ...)`, so it now no-ops. */

/* A fixed backdrop shows through EVERY transparent box on the page, not only the
   hero. `.page` carries no background of its own — the bands do — and neither do
   the gaps between sections, so the photograph bleeds the whole length of the
   document. Measured 2026-08-24 before this existed: the /work prose below the
   hero rendered as dark text on the still-lake photograph.

   Painting the sections themselves does NOT fix it: `.page` is a 1200px centred
   box, so a background on it is a column with the photograph down both gutters.
   The fix has to be one full-width opaque wrapper around everything after the
   hero. That is `.page-body`, and it is the boundary of the backdrop: above it
   the photograph shows, below it nothing does. */
.page-body { background: var(--paper); }

/* Horizon strip when v2 generator omits .horizon-transition sibling (standard pages). */
.hero-night.has-backdrop + .page-body::before {
  content: '';
  display: block;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  height: 64px;
  background: linear-gradient(180deg, #5d3220 0%, #efe4c8 100%);
  overflow: hidden;
  isolation: isolate;
  background-image: linear-gradient(180deg, #5d3220 0%, #efe4c8 100%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 64' preserveAspectRatio='xMidYEnd slice'%3E%3Cg stroke='%230a0606' stroke-width='1.4' stroke-linecap='round' opacity='0.8'%3E%3Cline x1='80' y1='64' x2='80' y2='30'/%3E%3Cline x1='130' y1='64' x2='130' y2='40'/%3E%3Cline x1='180' y1='64' x2='180' y2='24'/%3E%3Cline x1='240' y1='64' x2='240' y2='38'/%3E%3Cline x1='300' y1='64' x2='300' y2='28'/%3E%3Cline x1='370' y1='64' x2='370' y2='42'/%3E%3Cline x1='440' y1='64' x2='440' y2='22'/%3E%3Cline x1='510' y1='64' x2='510' y2='36'/%3E%3Cline x1='580' y1='64' x2='580' y2='30'/%3E%3Cline x1='650' y1='64' x2='650' y2='40'/%3E%3Cline x1='720' y1='64' x2='720' y2='26'/%3E%3Cline x1='790' y1='64' x2='790' y2='36'/%3E%3Cline x1='860' y1='64' x2='860' y2='24'/%3E%3Cline x1='930' y1='64' x2='930' y2='40'/%3E%3Cline x1='1000' y1='64' x2='1000' y2='30'/%3E%3Cline x1='1070' y1='64' x2='1070' y2='42'/%3E%3Cline x1='1140' y1='64' x2='1140' y2='22'/%3E%3Cline x1='1210' y1='64' x2='1210' y2='36'/%3E%3Cline x1='1280' y1='64' x2='1280' y2='28'/%3E%3Cline x1='1350' y1='64' x2='1350' y2='40'/%3E%3Cline x1='1420' y1='64' x2='1420' y2='26'/%3E%3Cline x1='1490' y1='64' x2='1490' y2='36'/%3E%3Cline x1='1560' y1='64' x2='1560' y2='30'/%3E%3C/g%3E%3Cg fill='%23f0e6cf' opacity='0.65'%3E%3Ccircle cx='80' cy='28' r='2'/%3E%3Ccircle cx='180' cy='22' r='2.2'/%3E%3Ccircle cx='300' cy='26' r='2'/%3E%3Ccircle cx='440' cy='20' r='2.4'/%3E%3Ccircle cx='580' cy='28' r='2'/%3E%3Ccircle cx='720' cy='24' r='2.2'/%3E%3Ccircle cx='860' cy='22' r='2.4'/%3E%3Ccircle cx='1000' cy='28' r='2'/%3E%3Ccircle cx='1140' cy='20' r='2.4'/%3E%3Ccircle cx='1280' cy='26' r='2'/%3E%3Ccircle cx='1420' cy='24' r='2.2'/%3E%3Ccircle cx='1560' cy='28' r='2'/%3E%3C/g%3E%3C/svg%3E");
  background-size: auto, cover;
  background-position: center bottom;
  background-repeat: no-repeat;
}

/* Section headings on long-form pages — v1 uses t-h3 in prose blocks. */
.page-body .prose > h2.t-h2 {
  font-family: var(--font-serif);
  font-size: var(--t-xl);
  line-height: 1.15;
  letter-spacing: -0.005em;
  font-weight: 580;
  font-variation-settings: "opsz" 30, "SOFT" 25;
  margin-bottom: 16px;
}

.poster-quote .accent,
.poster-quote strong {
  color: var(--warm-bright);
  font-weight: 560;
}

/* HOME PHOTO HERO — truck backdrop. Calibrated 2026-08-30: mobile, tablet, desktop.
   Mark left and lit; type sits on the dark wedge over wheel and badge.

   DOM contract (matches markulett-site v1): <picture.hero-photo> is a DIRECT child of
   .scene-glacier, NOT inside .hero-inner. The generator puts the photo in the aside part
   so it nests under <section> before .scene-overlay. CSS that caps .hero-inner > * at
   640px will clip the photograph if the picture lands inside .hero-inner. */
.scene-glacier.has-backdrop { background: transparent; }

.scene-glacier:has(.hero-photo) {
  width: 100%;
  margin-left: 0;
  margin-right: 0;
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  min-height: 560px;
  max-height: 88svh;
  background: #060a18;
  isolation: isolate;
}

/* has-backdrop must win over :has(.hero-photo) — otherwise desktop paints solid navy
   over the fixed truck photograph. */
.scene-glacier.has-backdrop:has(.hero-photo) {
  background: transparent;
}

/* Desktop: fixed backdrop carries the truck (R2 1600/2400). Mobile band uses <img>. */
@media (min-width: 821px) {
  .scene-glacier.has-backdrop .hero-photo { display: none; }
}

.hero-photo {
  position: absolute;
  inset: 0;
  display: block;
  z-index: 0;
  line-height: 0;
  overflow: hidden;
}
.hero-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  display: block;
}

.scene-glacier:has(.hero-photo)::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: linear-gradient(100deg,
    rgba(6, 10, 24, 0) 0%, rgba(6, 10, 24, 0) 34%,
    rgba(6, 10, 24, .52) 46%, rgba(6, 10, 24, .74) 62%, rgba(6, 10, 24, .74) 100%);
}

.scene-glacier:has(.hero-photo) > *:not(.hero-photo) { position: relative; z-index: 2; }

/* Coords meta row is a section child after .scene-overlay (aside part). */
.scene-glacier:has(.hero-photo) > .hero-meta-row {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 2;
  padding: 0 var(--gutter) 28px;
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
  box-sizing: border-box;
}

.scene-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 0 var(--gutter);
}

.hero-inner {
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: flex-end;
  padding-bottom: 64px;
  padding-right: 4px;
  text-align: right;
}

.scene-glacier:has(.hero-photo) .hero-inner > *:not(.hero-photo) {
  max-width: min(640px, 100%);
  width: 100%;
}

.scene-glacier:has(.hero-photo) .wm-row { justify-content: flex-end; flex-wrap: wrap; row-gap: 0; }
.scene-glacier:has(.hero-photo) .hero-cta-row { justify-content: flex-end; }
.scene-glacier:has(.hero-photo) .t-lede {
  margin-top: 22px;
  margin-left: auto;
  max-width: 620px;
  color: rgba(240, 230, 207, 0.92);
}
.scene-glacier:has(.hero-photo) .coord-badge { margin-left: auto; }
.scene-glacier:has(.hero-photo) .wm--xl { font-size: clamp(26px, 3vw, 44px); }
.scene-glacier:has(.hero-photo) .wm--xl .wm-mark { color: var(--cream); }
.scene-glacier:has(.hero-photo) .wm--xl .wm-ulett { color: var(--warm-bright); }

.hero-meta-row {
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  padding: 0 0 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-4);
}

.scene-glacier:has(.hero-photo) .hero-cta-row a:nth-child(2) {
  background: transparent;
  color: var(--cream);
  border-color: rgba(240, 230, 207, 0.4);
}
.scene-glacier:has(.hero-photo) .hero-cta-row a:nth-child(2):hover {
  border-color: var(--cream);
  background: rgba(240, 230, 207, 0.06);
  transform: translateY(-1px);
}

.page-body > .band.band-paper:first-of-type { padding-top: var(--s-9); }

@media (min-width: 821px) and (max-width: 1280px) {
  .scene-glacier:has(.hero-photo) {
    min-height: 480px;
    max-height: 72svh;
  }
  body.bd-feature { background-position: 42% 44%; }
  .scene-glacier:has(.hero-photo) .wm--xl { font-size: clamp(24px, 2.6vw, 38px); }
  .photo-band img {
    aspect-ratio: 16 / 9;
    max-height: 50vh;
    object-position: 50% 38%;
  }
}

@media (max-width: 820px) {
  body { background-image: none; }
  body::after { display: none; }
  .scene-glacier:has(.hero-photo),
  .scene-glacier.has-backdrop {
    aspect-ratio: auto;
    min-height: 0;
    max-height: none;
    background: #060a18;
    display: block;
  }
  .scene-glacier.has-backdrop .hero-photo,
  .scene-glacier:has(.hero-photo) .hero-photo {
    position: relative !important;
    inset: auto !important;
    height: clamp(240px, 38vh, 340px);
    display: block;
  }
  .scene-glacier:has(.hero-photo) .hero-photo img {
    height: 100%;
    object-position: 38% 42%;
  }
  .scene-glacier:has(.hero-photo)::after { display: none; }
  .scene-glacier:has(.hero-photo) .scene-overlay {
    position: relative !important;
    inset: auto !important;
  }
  .scene-glacier:has(.hero-photo) .hero-inner {
    padding: 30px 0 40px !important;
    text-align: left;
    align-items: flex-start !important;
    flex: none;
    justify-content: flex-start;
  }
  .scene-glacier:has(.hero-photo) .wm-row,
  .scene-glacier:has(.hero-photo) .hero-cta-row { justify-content: flex-start; }
  .scene-glacier:has(.hero-photo) .hero-inner > * { max-width: none; }
  .scene-glacier:has(.hero-photo) .t-lede,
  .scene-glacier:has(.hero-photo) .coord-badge { margin-left: 0; }
  .scene-glacier:has(.hero-photo) .wm--xl { white-space: normal; }
  .hero-meta-row { padding-bottom: 20px; }
}

@media (min-width: 721px) and (max-width: 820px) {
  .scene-glacier:has(.hero-photo) .hero-photo {
    height: clamp(280px, 42vh, 400px);
  }
}

@media (min-width: 721px) and (max-width: 1280px) {
  .photo-band img {
    aspect-ratio: 16 / 9;
    max-height: 50vh;
    object-position: 50% 38%;
  }
}

.hero-night.has-backdrop {
  background: linear-gradient(180deg,
    rgba(10, 16, 36, 0.30) 0%,
    rgba(22, 33, 46, 0.18) 38%,
    rgba(42, 36, 51, 0.30) 70%,
    rgba(74, 44, 31, 0.52) 92%,
    rgba(93, 50, 32, 0.70) 100%);
}
/* Below 821px the backdrop is off, so a see-through hero would show the paper
   canvas. Measured 2026-08-24: the /about eyebrow dropped to 6.5:1 at 390px
   before this rule. Put the original opaque sky back. */
@media (max-width: 820px) {
  .hero-night.has-backdrop {
    background: linear-gradient(180deg, #0a1024 0%, #16212e 38%, #2a2433 70%, #4a2c1f 92%, #5d3220 100%);
  }
}

/* --------------------------------------------------------------------------
   2. Scroll-linked motion. The listener lives in templates/script.html and
   writes two variables; everything from here down is pure CSS and costs
   nothing per frame. Chrome and photography only — never body text.
   -------------------------------------------------------------------------- */

.parallax-slow   { transform: translate3d(0, calc(var(--scroll-y, 0px) *  0.12), 0); }
.parallax-slower { transform: translate3d(0, calc(var(--scroll-y, 0px) *  0.06), 0); }
.parallax-rise   { transform: translate3d(0, calc(var(--scroll-y, 0px) * -0.05), 0); }

/* Reading-progress rail. Created by the site script, so no page markup changes
   and nothing that carries meaning depends on JS. */
.scroll-rail {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 90;
  pointer-events: none;
  transform-origin: 0 50%;
  transform: scaleX(var(--scroll-progress, 0));
  background: linear-gradient(to right, var(--saddle), var(--barn) 55%, var(--warm-bright));
  -webkit-mask-image: linear-gradient(to right, #000 0%, #000 88%, transparent 100%);
          mask-image: linear-gradient(to right, #000 0%, #000 88%, transparent 100%);
}

/* --------------------------------------------------------------------------
   3. Masks. A mask fades an edge over ANY backdrop, including photography,
   which a gradient overlay cannot do. Used where an edge was previously cut.
   -------------------------------------------------------------------------- */

/* Stars dissolve before they reach the ridge line instead of stopping at it. */
.hero-sky {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 44%, rgba(0,0,0,0.35) 68%, transparent 84%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 44%, rgba(0,0,0,0.35) 68%, transparent 84%);
}

/* Ridge silhouettes emerge out of the photograph rather than being pasted on. */
.hero-night.has-backdrop .hero-ridges {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.55) 14%, #000 38%);
          mask-image: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.55) 14%, #000 38%);
}

/* Repeating rules ran to a hard stop at the gutter. Fade both ends instead. */
.topo-divider,
.fabric-horizon {
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
}

/* --------------------------------------------------------------------------
   4. Photo bands between sections. Full-bleed, masked into the paper at both
   edges so the photograph dissolves into the page instead of being a rectangle
   dropped on it. This is where the photographs live on the inner pages: their
   heroes are content, and a photograph needs room to be a photograph.
   -------------------------------------------------------------------------- */

.photo-band {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  overflow: hidden;
  /* Opaque, and the mask goes on the IMAGE rather than on this box. Masking the
     box would clip its background too, and the faded edge would then reveal
     whatever sits behind the page — on a backdrop page, the fixed photograph. */
  background-color: var(--paper);
}
.photo-band img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 7;
  object-fit: cover;
  max-height: 62vh;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 9%, #000 91%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 9%, #000 91%, transparent 100%);
}
/* A band that follows a night section fades UP into the night and DOWN into the
   paper, so neither boundary is a cut. The middle of the ramp is hidden behind
   the opaque part of the photograph. */
.photo-band--on-night {
  background: linear-gradient(to bottom,
    var(--night) 0%, var(--night) 9%, var(--paper) 26%, var(--paper) 100%);
}
@media (max-width: 720px) {
  .photo-band img { aspect-ratio: 4 / 3; max-height: none; }
}

/* Two photographs side by side, square so they hold at any column width. */
.photo-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-5);
}
.photo-pair figure { margin: 0; }
.photo-pair img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--r-sm);
}
@media (max-width: 620px) { .photo-pair { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------------------
   5. Depth: layered radial gradients over the base colour, not a flat fill.
   The felt difference between the benchmark site and this one was mostly this
   ratio — eighteen gradients against three — not any animation.
   -------------------------------------------------------------------------- */

.band-paper {
  background:
    radial-gradient(90% 60% at 14% 0%,  rgba(93, 50, 32, 0.055), transparent 62%),
    radial-gradient(70% 55% at 92% 22%, rgba(166, 75, 59, 0.045), transparent 60%),
    var(--paper);
}
.band-paper-warm {
  background:
    radial-gradient(95% 65% at 82% 0%,  rgba(244, 196, 90, 0.16), transparent 60%),
    radial-gradient(75% 55% at 8% 40%,  rgba(93, 50, 32, 0.07),   transparent 62%),
    var(--paper-warm);
}
.band-paper-deep {
  background:
    radial-gradient(85% 60% at 50% 0%, rgba(93, 50, 32, 0.08), transparent 66%),
    var(--paper-warmer);
}
.band-night {
  background:
    radial-gradient(90% 60% at 18% 0%,  rgba(244, 196, 90, 0.10), transparent 60%),
    radial-gradient(70% 50% at 88% 18%, rgba(166, 75, 59, 0.13),  transparent 60%),
    var(--night);
}

/* --------------------------------------------------------------------------
   6. Reduced motion. Everything above must be complete and legible with all
   motion off. The backdrop is still by design, so it stays; only the
   scroll-driven transforms and the rail are neutralised.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .parallax-slow, .parallax-slower, .parallax-rise { transform: none !important; }
  .scroll-rail { display: none; }
}

/* ============================================================
   v2 bridge. [MARK] 2026-08-27.
   The config emits ONE band container and marks a record that carries a `stage` field as `.entry`.
   Everything else above is markulett's own stylesheet, carried over unchanged.
   ============================================================ */

/* One container, two presentations, decided by what is inside it rather than by a second part name. */
/* The container IS .card-grid, which live already styles. Naming it `band` meant every
   `.card-grid .card h3` rule missed these cards entirely. Adopt the vocabulary, do not invent one. */
.card-grid:has(.entry) { display: block; }

/* A card is what .card already was. An entry keeps the resume row: label column, hairline, serif title. */
.card-grid > .entry { display: grid; grid-template-columns: 130px 1fr; gap: var(--s-5);
                 padding: var(--s-5) 0; border-bottom: 1px solid var(--rule); background: none; border-radius: 0; }
.card-grid > .entry:first-child { border-top: 1px solid var(--rule-strong); }
/* The stage label and the title/description share a row: the label is column 1, the rest stacks in column 2. */
.card-grid > .entry > .entry-date { grid-row: 1; grid-column: 1; }
.card-grid > .entry > .entry-title { grid-row: 1; grid-column: 2; }
.card-grid > .entry > .entry-desc { grid-row: 2; grid-column: 2; margin: 0; }

/* The eyebrow is the heading's LABEL, so it is drawn inside the h1 and lifted above it here rather than
   existing as a second piece an owner has to keep in sync with the title. */
.hero-content h1 { display: flex; flex-direction: column; }
.hero-content .hero-eyebrow { order: -1; }

/* The badge is a list of three, and the separator is presentation. */
.coord-badge { list-style: none; display: inline-flex; gap: 0; padding: 6px 14px; margin: 0; width: auto; }
.coord-badge li + li::before { content: " · "; opacity: 0.55; }

/* NO JAVASCRIPT IN THE NAV. [MARK] 2026-08-27: remove the dead buttons rather than widen the fleet script for
   one site. Their behaviour lived in markulett's own JS, which v2 does not ship, so JS-20 refused them as dead
   controls. Both affordances are replaced here in CSS, which is this site's own and uncapped.
   Nothing is lost: on a phone the links wrap instead of collapsing behind a toggle, and the five AIPassWeb
   sections sit inline instead of behind a caret. */
@media (max-width: 860px) {
  .site-nav-links { display: flex; flex-wrap: wrap; gap: 10px 18px; max-height: none; visibility: visible; opacity: 1; }
  .nav-has-sub > .subnav { position: static; display: flex; flex-wrap: wrap; gap: 8px 14px;
                           box-shadow: none; border: 0; background: none; padding: 4px 0 0; min-width: 0; }
  .nav-has-sub { display: flex; flex-wrap: wrap; }
}

/* THREE FIXES FROM CYCLE 1'S SIDEBYSIDE. Each one closed a delta the composite showed and the eye did not.

   1. THE BADGE stretched to full width. `.coord-badge` is already inline-flex, but it is a direct child of
      .hero-content here where live nests it in .hero-bottom, and a stretched flex child ignores inline-flex. */
.hero-content > .coord-badge { align-self: start; width: fit-content; }

/*  2. THE FOOTER HEADINGS. h4 became h3 because live's own footer jumps h2 to h4, which H-4 refuses as a
      two-level skip. h3 inherits serif display sizing, so live's `.site-foot h4` rules are restated for h3. */
.site-foot h3 { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--fg-subtle); margin-bottom: var(--s-4); }

/*  3. THE CONSTELLATION, CARRIED. [MARK] ruled 2026-08-27, superseding cycle 1's starfield stand-in.
      Live draws it as three sibling divs inside section.hero-night: a ten-star sky, the five-node scene, and a
      scrim over the gradient's warm bottom. The engine wraps, and a wrap nests rather than making siblings, so
      decoration cannot be an element here. It is presentation, and presentation is CSS.
      MEASURED IDENTICAL on /aipassweb/ and /aipassweb/how/ (sha 90b47436386a, 1,736 bytes), which is what makes
      it SITE decoration rather than page content and settles the question of where it belongs.
      Layers read top-first: scrim, scene, sky, then live's own base gradient restored unchanged. */
.hero-night { background-image:
  linear-gradient(to top, rgba(10,16,36,0.94) 0%, rgba(10,16,36,0.82) 24%, rgba(10,16,36,0.42) 52%, rgba(10,16,36,0) 78%),
  url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%201600%20600%22%20preserveAspectRatio=%22xMidYMid%20slice%22%20aria-hidden=%22true%22%3E%3Cg%20stroke=%22rgba%28244,196,90,0.30%29%22%20fill=%22none%22%20stroke-width=%221.2%22%3E%3Cpath%20d=%22M%20980%20210%20L%201150%20140%22/%3E%3Cpath%20d=%22M%20980%20210%20L%201180%20300%22%20stroke-dasharray=%224%206%22/%3E%3Cpath%20d=%22M%201150%20140%20L%201180%20300%22%20stroke-dasharray=%222%208%22%20opacity=%220.6%22/%3E%3Cpath%20d=%22M%201180%20300%20L%201360%20230%22/%3E%3Cpath%20d=%22M%201150%20140%20L%201360%20230%22%20stroke-dasharray=%224%206%22%20opacity=%220.5%22/%3E%3C/g%3E%3Cg%20fill=%22%23f4c45a%22%3E%3Ccircle%20cx=%22980%22%20cy=%22210%22%20r=%223.2%22/%3E%3Ccircle%20cx=%221150%22%20cy=%22140%22%20r=%222.6%22/%3E%3Ccircle%20cx=%221180%22%20cy=%22300%22%20r=%222.6%22/%3E%3Ccircle%20cx=%221360%22%20cy=%22230%22%20r=%223.2%22/%3E%3C/g%3E%3C/svg%3E"),
  url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%201600%20600%22%20preserveAspectRatio=%22xMidYMid%20slice%22%20aria-hidden=%22true%22%3E%3Cg%20fill=%22%23f0e6cf%22%3E%3Ccircle%20class=%22scene-star%22%20cx=%2280%22%20cy=%22100%22%20r=%221.2%22%20opacity=%220.55%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22200%22%20cy=%2260%22%20r=%221.0%22%20opacity=%220.5%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22340%22%20cy=%22140%22%20r=%220.9%22%20opacity=%220.55%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22480%22%20cy=%2280%22%20r=%221.3%22%20opacity=%220.65%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22640%22%20cy=%22160%22%20r=%220.8%22%20opacity=%220.4%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22820%22%20cy=%2250%22%20r=%221.2%22%20opacity=%220.65%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%22980%22%20cy=%22120%22%20r=%221.0%22%20opacity=%220.55%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%221160%22%20cy=%2240%22%20r=%221.4%22%20opacity=%220.7%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%221320%22%20cy=%22120%22%20r=%221.0%22%20opacity=%220.5%22/%3E%3Ccircle%20class=%22scene-star%22%20cx=%221480%22%20cy=%2260%22%20r=%221.2%22%20opacity=%220.6%22/%3E%3C/g%3E%3C/svg%3E"),
  linear-gradient(180deg, #0a1024 0%, #16212e 38%, #2a2433 70%, #4a2c1f 92%, #5d3220 100%);
  background-repeat: no-repeat; background-size: cover; background-position: center; }
/*  4. CARD HEADINGS. Found by cycle 2 and true of cycle 1 as well, so it is a correction, not a new delta.
      `record.name` draws `h2.entry-title`, so live's `.card-grid .card h3` rule never matched a generated card
      and `.entry-title` applied instead: 20px serif where live sets 26px. Same class as the `band` mistake —
      a selector locked to a tag the config does not emit. An ENTRY keeps the serif 20px resume row; a plain
      CARD takes live's card-heading size. */
.card-grid .card:not(.entry) > .entry-title { margin: 0 0 var(--s-3); font-size: var(--t-lg); line-height: 1.6; }

/*  5. CARD BODY, same cause one element down and found by Pass C, not by eye. `record.body` draws
      `p.entry-desc`, which is the RESUME ROW's paragraph: 16px/1.55. Live's card paragraph is the card's own
      18px/1.6. Measured on /aipassweb/: the three-node band came back 70px short and the six-card band 146px
      short, both of them text set two points too small. A card takes the card's type. */
.card-grid .card:not(.entry) > .entry-desc { font-size: inherit; line-height: inherit; }

/* ============================================================
   Parity layout grids — v1 hand-page structure, 2026-08-31
   ============================================================ */

.page .wide > .card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
@media (max-width: 900px) {
  .page .wide > .card-grid { grid-template-columns: 1fr; }
}

.sinopah-grid {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 64px;
  align-items: start;
}
.sinopah-grid > .section-head {
  grid-column: 1 / -1;
}
.sinopah-grid > .photo-frame {
  grid-column: 1;
}
.sinopah-grid > p {
  grid-column: 2;
}
.sinopah-grid > p:first-of-type {
  margin-bottom: var(--s-4);
}
.sinopah-grid .photo-frame img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: center 30%;
}
@media (max-width: 720px) {
  .sinopah-grid { grid-template-columns: 1fr; gap: var(--s-6); }
}

.studio-grid,
.client-grid {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 64px;
  align-items: start;
}
.client-grid > p,
.client-grid > a.btn {
  grid-column: 1;
}
.client-grid > ul.logbook {
  grid-column: 2;
  grid-row: 1;
  align-self: start;
}
@media (max-width: 720px) {
  .studio-grid,
  .client-grid { grid-template-columns: 1fr; gap: var(--s-6); }
}

.capabilities-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}
@media (max-width: 720px) {
  .capabilities-grid { grid-template-columns: 1fr; }
}

.card-vibe > ul {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 20px;
  list-style: none;
  padding: 0;
}
.card-vibe > ul > li {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  padding: 3px 8px;
  border: 1px solid var(--rule);
  border-radius: 2px;
}

.card-meta-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 18px;
}
.card-tagline {
  color: var(--fg-muted);
  margin-bottom: 16px;
  font-size: var(--t-sm);
}
.card-body {
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--fg);
}
.card-tagrow {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 20px;
}
.card-tag {
  padding: 3px 8px;
  border: 1px solid var(--rule);
  border-radius: 2px;
}
.photo-frame-caption {
  padding: 12px 16px 16px;
}
.page .wide > .card-vibe > .card-body {
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--fg);
}

.photo-pair-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-5);
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: var(--s-5) var(--gutter);
  box-sizing: border-box;
  background: var(--paper);
}
.photo-pair-row .photo-band {
  width: 100%;
  margin: 0;
}
.photo-pair-row .photo-band img {
  aspect-ratio: 1 / 1;
  max-height: none;
  border-radius: var(--r-sm);
  -webkit-mask-image: none;
  mask-image: none;
}
@media (max-width: 620px) {
  .photo-pair-row { grid-template-columns: 1fr; }
}

/* Photo-band portrait editorial crop — matches v1 object-position */
.page-body > .photo-band img[src*="mark-editorial"] {
  object-position: 30% 30%;
  filter: contrast(1.05) saturate(0.85);
}

/*  6. THE ENTRY ROW GAP. Live's entry is ONE grid row — a date column beside a div holding title and
      description — so `gap` only ever draws between the columns. The config emits three siblings, which makes
      a second row, and the same `gap` then draws between title and description as well: +24px on every entry,
      +96px across the four on /aipassweb/. The columns still need their gap, so only the row gap goes. */
.card-grid > .entry { row-gap: 0; }

/* AN ENTRY IN A CARD GRID IS A ROW, NOT A CARD. [MARK] 2026-08-29: "let's make it look so."
   The generator gives a staged record both `card` and `entry`, so `.card`'s background, radius, padding and
   shadow landed on top of `.entry`'s own `display:grid; grid-template-columns:130px 1fr`. The grid still
   applied — the height came from card chrome repeated eleven times plus the grid's gaps, which is why
   /aipassweb/demo/llm measured +112% taller than live with the SAME 688 words. Live has no `.card` on those
   at all. Stripping the chrome here rather than widening the engine: SOP-004, "change the site". */
.card-grid > .card.entry {
  grid-column: 1 / -1;
  background: none;
  box-shadow: none;
  border-radius: 0;
  padding: var(--s-5) 0;
}

/* Entry text is entry-sized. Live's is p.entry-desc at 16px/24.8; the migration modelled these as a record
   plus a `group`, so the words arrive as bare <p> inside .band-group and took the 18px body size. This closes
   the type gap. It does NOT close all of it: live carries one paragraph per entry where the clone carries two,
   and that is a content-modelling difference from the migration, not something a stylesheet can merge. */
.card-grid > .card.entry .band-group p { font-size: var(--t-sm); line-height: 1.55; }

/* ── HOME HERO PARITY WITH LIVE, measured 2026-09-09 ──────────────────────────
   Four deltas, each measured against markulett.com at 1280x800, not eyeballed:
     h1        live 296px tall, v2 280px  -> the doubled baseline rule was absent
     .t-lede   live x=592 w=620 mt=32px,  v2 x=572 w=640 mt=22px
     .hero-cta-row  live margin-top 40px, v2 0px  -> buttons sat against the lede
   The rule is drawn as a pseudo-element, not an emitted <div class="wm-rule">.
   Live emits one; this engine treats decoration as presentation and presentation
   as CSS, the same call already made for the constellation on .hero-night. */
.scene-glacier:has(.hero-photo) .wm-row::after {
  content: '';
  display: block;
  width: 100%;
  /* live declares .wm--xl .wm-rule twice; the 10px/3px pair is the one that wins.
     Measured: it makes the h1 296px tall, which the 6px version missed by 4px. */
  height: 10px;
  margin-top: 0.18em;
  background-image: linear-gradient(var(--cream), var(--cream)),
                    linear-gradient(var(--warm-bright), var(--warm-bright));
  background-size: 100% 3px, 100% 3px;
  background-position: 0 0, 0 7px;
  background-repeat: no-repeat;
}
/* Needs `.hero-inner >` to outrank `.hero-inner > *:not(.hero-photo)`, which
   forces every child to the full 640 and was flattening the lede's measure. */
.scene-glacier:has(.hero-photo) .hero-inner > .t-lede {
  max-width: 620px;
  margin-left: auto;
  margin-top: 32px;
}
.scene-glacier:has(.hero-photo) .hero-cta-row { margin-top: 40px; }

/* ── GATE 0: THE CONTENTS BAND WAS INSIDE THE HORIZON STRIP ───────────────────
   Measured 2026-09-09. Live emits `.horizon-transition` EMPTY, with `.page-body`
   as its SIBLING. This generator nested `.page-body` INSIDE it, and the strip is
   `height:64px; overflow:hidden` — so `section.band.band-paper` ("Five places to
   start", 956px) was clipped away and the page came out 1,082px short.

   Found by counting bands, not by measuring boxes: live paints 10, v2 painted 9.
   Four rounds of box measurement never saw it, because every box it measured was
   correct. The band that is missing has no box to measure.

   Held here in CSS because the emitted nesting is the core generator's to change,
   and one tenant's page is not the place to make that call. Flagged for a brief. */
.horizon-transition:has(.page-body) {
  height: auto;
  overflow: visible;
  background: none;
  isolation: auto;
}
.horizon-transition:has(.page-body)::before {
  content: '';
  position: static;
  display: block;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: 64px;
  background: linear-gradient(180deg, #5d3220 0%, #efe4c8 100%);
}

/* ── THE CAMPFIRE PHOTO IS A BLEED, NOT A BAND ────────────────────────────────
   Measured 2026-09-09. Live emits the second photograph as `section.photo-bleed`
   — 4:3, up to 80vh, no mask. This generator emits `section.photo-band` for both
   photographs, which is 16:7, capped at 62vh and masked top and bottom, so the
   campfire shot reads as a letterboxed strip instead of the full-height image
   live shows. The class is the generator's to choose; the treatment is CSS, so
   the second one is restored here by position rather than by renaming a section. */
.photo-band ~ .photo-band img {
  max-height: 80vh !important;         /* live measures 560px; v2's 62vh cap clipped it to 496 */
  object-position: 50% 40% !important;
  -webkit-mask-image: none !important; /* a bleed carries no top/bottom fade */
  mask-image: none !important;
}

/* THE FORM'S CAPTIONS. Added 2026-09-10. The generator draws a field as ONE element, so a caption
   and its control cannot be siblings inside a div the way the reference writes them; the label IS
   the field wrapper and holds its caption as text, which is a valid implicit association and does
   not depend on an id matching a `for`. `.field label` above styles the reference's shape and is
   kept for it; these two rules style ours. The control keeps its own font because `.ask-form input`
   sets family and size explicitly and wins over the caption's. */
label.field {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: var(--s-4);
}
label.field > input,
label.field > textarea { margin-top: var(--s-2); }

/* CONTACT'S HERO IS NOT BACKED BY A PHOTOGRAPH. Measured 2026-09-10 against the frozen reference:
   its hero is section.hero-night with NO has-backdrop, so the night gradient paints solid. The
   shell hardcodes has-backdrop for every standard page, which drops the gradient to 30% alpha to
   let a photo through - and with contact's photo correctly removed, the hero read pale paper
   instead of dark navy. The class cannot be removed per page from a single shell, so the solid
   gradient is restored by page here. about, work and writing keep the photo and the alpha. */
body[data-page="contact"] .hero-night.has-backdrop {
  background: linear-gradient(180deg, #0a1024 0%, #16212e 38%, #2a2433 70%, #4a2c1f 92%, #5d3220 100%);
}
