/* _ds/tokens/colors.css */
:root{
/* brand — from logo mark gradient. 700 and darker pass 4.5:1 on paper surfaces. */
--brand-900:#2a1d18;--brand-700:#42302a;--brand-600:#523c33;--brand-500:#6b4f43;--brand-400:#8c6a57;--brand-300:#b0917f;--brand-200:#d4bfb2;--brand-100:#ede2da;--brand-50:#f8f2ed;

/* pastel accents — tonal ramps; 700 steps are darkened to clear 4.5:1 on their own 100 tint */
--sage-100:#e4efe6;--sage-300:#b7d2ba;--sage-500:#5f8c68;--sage-700:#2f5a3c;
--sky-100:#e3edf4;--sky-300:#b3cee0;--sky-500:#4f86ad;--sky-700:#28536f;
--lavender-100:#ece6f4;--lavender-300:#cbb9de;--lavender-500:#7f66a5;--lavender-700:#4f3a75;
--butter-100:#f9f0da;--butter-300:#eed89f;--butter-500:#b08f2c;--butter-700:#6d5410;
--clay-100:#f6e7e1;--clay-300:#e6bcab;--clay-500:#b56347;--clay-700:#7f3f2b;

/* neutrals — warm paper, bear-notes inspired */
--paper-0:#fffdfb;--paper-50:#faf6f1;--paper-100:#f3ece4;--paper-200:#e7ddd2;--paper-300:#d6c9bb;
--ink-900:#241d1a;--ink-700:#3f342e;--ink-500:#5e5049;--ink-300:#7d6e65;--ink-100:#d8cfc5;

/* dark surface set */
--dark-900:#191412;--dark-800:#221b18;--dark-700:#2d2521;--dark-600:#3b312b;--dark-500:#4d413a;

/* semantic — light */
--surface-app:var(--paper-50);--surface-card:var(--paper-0);--surface-sunken:var(--paper-100);--surface-border:var(--paper-300);
--text-primary:var(--ink-900);--text-secondary:var(--ink-500);--text-tertiary:var(--ink-300);--text-inverse:var(--paper-0);
--accent:var(--brand-600);--accent-hover:var(--brand-700);--accent-soft:var(--brand-100);
--success:var(--sage-700);--success-soft:var(--sage-100);
--info:var(--sky-700);--info-soft:var(--sky-100);
--warning:var(--butter-700);--warning-soft:var(--butter-100);
--danger:var(--clay-700);--danger-soft:var(--clay-100);
--focus-ring:var(--lavender-700);
/* semantic — dark surfaces (text tokens meet 4.5:1 on --dark-800/900) */
--surface-app-dark:var(--dark-900);--surface-card-dark:var(--dark-800);--surface-border-dark:var(--dark-600);
--text-primary-dark:var(--paper-50);--text-secondary-dark:var(--paper-300);
}

/* _ds/tokens/typography.css */
:root{
/* Figtree — display/headings. Atkinson Hyperlegible — body/UI, designed for low-vision legibility. JetBrains Mono — code. */
--font-display:'Figtree',ui-sans-serif,system-ui,sans-serif;
--font-body:'Atkinson Hyperlegible','Figtree',ui-sans-serif,system-ui,sans-serif;
--font-mono:'JetBrains Mono',ui-monospace,'SFMono-Regular',monospace;
/* accessible scale: body never below 16px, captions never below 14px */
--text-xs:14px;--text-sm:15px;--text-base:16px;--text-md:18px;--text-lg:22px;--text-xl:26px;--text-2xl:32px;--text-3xl:40px;--text-4xl:52px;
--leading-tight:1.2;--leading-snug:1.4;--leading-normal:1.6;--leading-relaxed:1.75;
--tracking-tight:-0.015em;--tracking-normal:0;--tracking-wide:0.06em;
--weight-regular:400;--weight-medium:500;--weight-semibold:600;--weight-bold:700;--weight-extrabold:800;
--measure-prose:68ch;
}

/* _ds/tokens/spacing.css */
:root{
--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:20px;--space-6:24px;--space-8:32px;--space-10:40px;--space-12:48px;--space-16:64px;--space-20:80px;--space-24:96px;
--radius-sm:8px;--radius-md:12px;--radius-lg:16px;--radius-xl:24px;--radius-pill:999px;
/* accessibility: minimum interactive target, and a visible 2px focus outline offset from the control */
--target-min:44px;/* @kind spacing */
--focus-outline-width:3px;/* @kind spacing */
--focus-outline-offset:2px;/* @kind spacing */
--shadow-sm:0 1px 2px rgba(36,29,26,0.07),0 1px 1px rgba(36,29,26,0.05);
--shadow-md:0 4px 10px rgba(36,29,26,0.09),0 1px 3px rgba(36,29,26,0.06);
--shadow-lg:0 12px 28px rgba(36,29,26,0.13),0 3px 8px rgba(36,29,26,0.08);
--shadow-focus:0 0 0 3px var(--lavender-300),0 0 0 5px var(--lavender-700);
--border-hairline:1px solid var(--surface-border);
--ease-standard:cubic-bezier(0.2,0,0,1);/* @kind other */--ease-out:cubic-bezier(0.05,0.7,0.1,1);/* @kind other */
--duration-fast:120ms;/* @kind other */--duration-base:180ms;/* @kind other */--duration-slow:280ms;/* @kind other */
}
@media (prefers-reduced-motion:reduce){:root{--duration-fast:0ms;/* @kind other */--duration-base:0ms;/* @kind other */--duration-slow:0ms/* @kind other */}}

/* _ds/tokens/base.css */
/* Base element defaults so every consuming page inherits accessible type, links and focus rings. */
body{font-family:var(--font-body);font-size:var(--text-base);line-height:var(--leading-normal);color:var(--text-primary);background:var(--surface-app);-webkit-font-smoothing:antialiased}
h1,h2,h3,h4{font-family:var(--font-display);color:var(--text-primary);line-height:var(--leading-tight);letter-spacing:var(--tracking-tight);margin:0}
p{max-width:var(--measure-prose);text-wrap:pretty}
a{color:var(--brand-700);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
a:hover{color:var(--brand-900);text-decoration-thickness:2px}
:focus-visible{outline:var(--focus-outline-width) solid var(--focus-ring);outline-offset:var(--focus-outline-offset)}
button,input,select,textarea{font-family:inherit;font-size:var(--text-base)}
button,a[role="button"]{min-height:var(--target-min)}
code,pre{font-family:var(--font-mono)}
::selection{background:var(--brand-200)}

/* vendor/lenis.css */
html.lenis,
html.lenis body {
  height: auto;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch],
.lenis [data-lenis-prevent-vertical],
.lenis [data-lenis-prevent-horizontal] {
  overscroll-behavior: contain;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

.lenis.lenis-autoToggle {
  transition-property: overflow;
  transition-duration: 1ms;
  transition-behavior: allow-discrete;
}

/* components.css */
/* Design-system components, ported from the vendored React bundle to plain CSS.
   Values are copied verbatim from _ds/<version>/_ds_bundle.js so the rendered
   result is identical; hover states that were React state are now :hover. */

/* Badge — _ds components/feedback/Badge.jsx */
.badge {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 10px;
  border-radius: var(--radius-pill);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.badge-neutral { background: var(--surface-sunken); color: var(--text-secondary) }
.badge-brand   { background: var(--accent-soft);    color: var(--brand-700) }
.badge-success { background: var(--success-soft);   color: var(--success) }
.badge-info    { background: var(--info-soft);      color: var(--info) }
.badge-warning { background: var(--warning-soft);   color: var(--warning) }
.badge-danger  { background: var(--danger-soft);    color: var(--danger) }

/* Button — _ds components/primitives/Button.jsx.
   Rendered as an <a> because every button on this site navigates. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 44px;
  border: none;
  border-radius: var(--radius-md);
  font-family: var(--font-display);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--duration-base) var(--ease-standard),
              color var(--duration-base) var(--ease-standard),
              transform var(--duration-fast) var(--ease-standard);
}
.btn:active {
  transform: scale(0.98);
}
@media (prefers-reduced-motion: reduce) {
  .btn:active { transform: none; }
}
.btn-sm { height: 36px; padding: 0 14px; font-size: var(--text-sm) }
.btn-md { height: 44px; padding: 0 20px; font-size: var(--text-base) }
.btn-lg { height: 52px; padding: 0 26px; font-size: var(--text-md) }

.btn-primary        { background: var(--brand-600); color: var(--text-inverse) }
.btn-primary:hover  { background: var(--brand-700); color: var(--text-inverse) }
.btn-secondary      { background: var(--surface-sunken); color: var(--text-primary); border: 1px solid var(--surface-border) }
.btn-secondary:hover{ background: var(--paper-200); color: var(--text-primary) }
.btn-ghost          { background: transparent; color: var(--brand-700) }
.btn-ghost:hover    { background: var(--accent-soft); color: var(--brand-700) }

/* Card — _ds components/surfaces/Card.jsx */
.ds-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px;
  background: var(--surface-card);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-body);
}

/* Blog tag filter — replaces the React useState toggle. Server renders the
   pressed state; htmx swaps in a new fragment on click. */
.pill-filter {
  min-height: 44px;
  border: none;
  background: transparent;
  color: var(--ink-500);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard), color var(--duration-fast);
}
.pill-filter:hover { background: var(--brand-50); color: var(--brand-700) }
.pill-filter[aria-current] { background: var(--brand-100); color: var(--brand-700) }

/* htmx: fade the region while a fragment is in flight. The pills declare
   #blog-filter as their hx-indicator, so htmx adds .htmx-request to it. */
#blog-filter { transition: opacity var(--duration-fast) var(--ease-standard) }
#blog-filter.htmx-request { opacity: .55 }

/* Skip link — keyboard users land here first. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 20px;
  background: var(--brand-700);
  color: var(--paper-0);
  border-radius: 0 0 var(--radius-md) 0;
  font-family: var(--font-display);
  font-weight: 700;
}
.skip:focus { left: 0; color: var(--paper-0) }

/* Analytics consent notice. Fixed to the bottom, revealed by the client script
   only when no choice has been stored. Motion is opacity only, to stay inside
   the studio's stated motion budget. */
.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  padding: 16px 0;
  background: var(--paper-0);
  border-top: 1px solid var(--surface-border);
  box-shadow: var(--shadow-md);
  transition: opacity var(--duration-base) var(--ease-standard);
}
.consent[hidden] { display: none }

.consent-in {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}
.consent-text { max-width: 62ch }
.consent-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-left: auto }

/* Stack the buttons under the text where a single row will not fit. */
@media (max-width: 640px) {
  .consent-in { flex-direction: column; align-items: stretch }
  .consent-actions { margin-left: 0 }
  .consent-actions .btn { flex: 1 }
}

/* Withdrawal control in the footer — a button, styled as the footer's own text. */
.consent-reopen {
  margin-left: 12px;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.consent-reopen:hover { color: var(--paper-0) }

/* Mobile navigation drawer.
   A native <dialog>, so the platform supplies focus trapping, Escape, and
   inerting the page behind it. Slides in from the right over a dimmed scrim.

   `transform` is a third animated property, beyond the studio's stated budget
   of opacity and background colour — but it is compositor-only, so it costs no
   layout or paint, and a drawer that does not move is not a drawer. Duration
   stays inside the 280ms ceiling, and the slide is dropped entirely under
   prefers-reduced-motion. */
.drawer {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(64vw, 300px);
  max-width: none;
  max-height: none;
  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
  background: var(--paper-0);
  box-shadow: var(--shadow-lg);
  color: var(--ink-700);
  opacity: 0;
  transform: translateX(100%);
  transition:
    transform 220ms var(--ease-out),
    opacity 220ms var(--ease-out),
    overlay 220ms allow-discrete,
    display 220ms allow-discrete;
}
.drawer[open] { opacity: 1; transform: translateX(0) }

/* The entry animation needs a start state for the frame the dialog appears. */
@starting-style {
  .drawer[open] { opacity: 0; transform: translateX(100%) }
}

.drawer::backdrop {
  background: color-mix(in srgb, var(--ink-900) 52%, transparent);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition:
    opacity 220ms var(--ease-out),
    overlay 220ms allow-discrete,
    display 220ms allow-discrete;
}
.drawer[open]::backdrop { opacity: 1 }
@starting-style {
  .drawer[open]::backdrop { opacity: 0 }
}

.drawer-in { display: flex; flex-direction: column; height: 100%; padding: 16px }
.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 48px;
  padding-left: 8px;
}
.drawer-close {
  flex: none;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-700);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard), color var(--duration-fast);
}
.drawer-close:hover { background: var(--brand-50); color: var(--brand-700) }

.drawer-links { display: flex; flex-direction: column; gap: 2px; margin-top: 12px }
.drawer-links a {
  display: flex;
  align-items: center;
  min-height: 50px;
  padding: 0 14px;
  border-radius: var(--radius-md);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink-700);
  transition: background var(--duration-fast) var(--ease-standard), color var(--duration-fast);
}
.drawer-links a:hover { background: var(--brand-50); color: var(--brand-700) }
.drawer-links a[aria-current] { background: var(--brand-100); color: var(--brand-700) }

/* Hold the page still while the drawer is open. */
.nav-open, .nav-open body { overflow: hidden }

@media (prefers-reduced-motion: reduce) {
  .drawer, .drawer[open] { transform: none }
  .drawer, .drawer::backdrop { transition-duration: 1ms }
  @starting-style {
    .drawer[open] { transform: none }
  }
}

/* Studio Status Badge */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--paper-0);
  border: 1px solid var(--surface-border);
  color: var(--ink-700);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  box-shadow: var(--shadow-sm);
}
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--sage-500);
  box-shadow: 0 0 0 2px var(--sage-100);
  display: inline-block;
  flex: none;
}

/* Feature grid for capabilities */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 24px);
}
@media (min-width: 1040px) {
  .feature-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (max-width: 680px) {
  .feature-grid {
    grid-template-columns: 1fr;
  }
}
.feature-tag {
  display: inline-flex;
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--brand-500);
  background: var(--paper-100);
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  letter-spacing: 0.02em;
}
.feature-item {
  background: var(--paper-0);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-lg);
  padding: clamp(24px, 2.5vw, 36px);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: box-shadow var(--duration-base) var(--ease-standard), border-color var(--duration-base);
}
.feature-item:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--brand-300);
}

/* Pillar Cards (Two Disciplines) */
.pillar-card {
  position: sticky;
  top: calc(var(--header-h) + var(--sticky-gap) + var(--i) * 20px);
  border-radius: var(--radius-xl);
  padding: clamp(28px, 3.5vw, 52px);
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--surface-border);
}
.pillar-facets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 16px 24px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent);
}
.pillar-facet {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pillar-facet-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  opacity: 0.8;
  font-family: var(--font-display);
  font-weight: 700;
}
.pillar-facet-val {
  font-size: var(--text-sm);
  font-weight: 600;
}

/* site.css */
/* Sticky geometry, in one place. Every pinned element offsets from these, so
   changing the header height cannot silently leave something tucked behind it.
   --sticky-gap is the breathing room between the header and whatever pins. */
:root{--header-h:92px;--sticky-gap:28px}
@media(max-width:860px){:root{--header-h:76px;--sticky-gap:16px}}
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--header-h) + var(--sticky-gap))}
/* Lenis animates scrolling itself; leaving native smooth behaviour on makes the
   two fight over anchor jumps. `.lenis` is the persistent class — `.lenis-smooth`
   is only present mid-scroll — so this applies exactly while Lenis is running,
   leaving the rule above to cover reduced-motion and no-JavaScript. */
html.lenis{scroll-behavior:auto}
body{background:var(--paper-50);overflow-x:hidden}
*{box-sizing:border-box}
a{text-decoration:none;color:var(--brand-700)}
a:hover{color:var(--brand-900);text-decoration:none}
.prose a,.linked{text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
p{margin:0}
ul{margin:0}
.wrap{width:min(1240px,100% - 96px);margin-inline:auto}
@media(max-width:720px){.wrap{width:min(1240px,100% - 40px)}}
@media(min-width:1800px){.wrap{width:min(1440px,100% - 200px)}}

/* header + bookmark */
.hdr{position:sticky;top:0;z-index:40;background:color-mix(in srgb,var(--paper-50) 88%,transparent);backdrop-filter:blur(10px)}
.hdr-in{display:flex;align-items:center;gap:24px;min-height:var(--header-h);padding-left:176px;position:relative}
.bookmark{position:absolute;left:36px;top:0;display:grid;place-items:start center;min-height:0;transition:opacity var(--duration-base) var(--ease-standard)}
.bookmark:hover{opacity:.78}
.bookmark img{width:130px;height:130px;object-fit:contain;margin-top:-6px}
.mark{font-family:var(--font-display);font-weight:800;font-size:20px;letter-spacing:-0.02em;color:var(--brand-700)}
.mark span{font-weight:500;color:var(--brand-400)}
.nav{display:flex;gap:4px;margin-left:auto;align-items:center}
.nav a{font-family:var(--font-display);font-weight:600;font-size:16px;padding:0 16px;height:44px;display:inline-flex;align-items:center;border-radius:var(--radius-pill);color:var(--ink-700);transition:background var(--duration-fast) var(--ease-standard),color var(--duration-fast)}
.nav a:hover{background:var(--brand-50);color:var(--brand-700)}
.nav a[aria-current]{background:var(--brand-100);color:var(--brand-700)}
/* Menu button. Hidden until the script reveals it, and only laid out on
   phone widths — see the collapsed-nav block below. */
.navtoggle{display:none;margin-left:auto;width:44px;height:44px;align-items:center;justify-content:center;border:none;background:transparent;border-radius:var(--radius-pill);color:var(--ink-700);cursor:pointer;transition:background var(--duration-fast) var(--ease-standard),color var(--duration-fast)}
.navtoggle:hover{background:var(--brand-50);color:var(--brand-700)}
.navtoggle[aria-expanded=true]{background:var(--brand-100);color:var(--brand-700)}
@media(max-width:860px){
  /* A narrower gutter for the header only, so the mark and wordmark sit closer
     to the edge than the body text does. */
  .hdr .wrap{width:min(1240px,100% - 24px)}
  .hdr-in{padding-left:78px}
  .bookmark{left:2px}
  .bookmark img{width:72px;height:72px}
  /* Without the script the links stay inline and wrap rather than overflow. */
  .nav{gap:0;flex-wrap:wrap;justify-content:flex-end}
  .nav a{padding:0 10px;font-size:15px}

  /* With the script: the inline links give way to one button and the drawer. */
  .js-nav .nav{display:none}
  .js-nav .navtoggle{display:inline-flex}
}
/* Only the no-script fallback still needs to shed the wordmark and tighten the
   links; with the popover the header is just logo + wordmark + one button. */
@media(max-width:560px){html:not(.js-nav) .mark{display:none}}
@media(max-width:520px){html:not(.js-nav) .nav a{padding:0 8px;font-size:14px}}
@media(max-width:400px){
  .hdr-in{padding-left:68px;gap:8px}
  .bookmark{left:0}
  .bookmark img{width:64px;height:64px}
  html:not(.js-nav) .nav a{padding:0 6px;font-size:13px}
}

/* type */
.h-xl{font-size:clamp(38px,5.6vw,72px);font-weight:800;line-height:1.03;letter-spacing:-0.03em}
.h-lg{font-size:clamp(28px,3.2vw,44px);font-weight:800;line-height:1.1;letter-spacing:-0.025em}
.h-md{font-size:clamp(21px,1.7vw,26px);font-weight:700;line-height:1.25}
.lead{font-size:clamp(18px,1.35vw,22px);line-height:1.65;color:var(--ink-700);max-width:46ch}
.body{font-size:var(--text-base);line-height:var(--leading-relaxed);color:var(--ink-700);max-width:62ch}
.small{font-size:var(--text-sm);color:var(--text-secondary)}
.eyebrow{font-family:var(--font-display);font-size:var(--text-sm);font-weight:700;letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--brand-400)}
.mono{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--brand-400)}

/* layout helpers */
.col{display:flex;flex-direction:column}
.sec{padding:clamp(64px,8vh,120px) 0}
.pill{display:inline-flex;align-items:center;gap:8px;height:34px;padding:0 14px;border-radius:var(--radius-pill);font-size:var(--text-sm);font-weight:700;font-family:var(--font-display)}
.dot{width:8px;height:8px;border-radius:50%}
.soft{background:var(--paper-0);border-radius:var(--radius-lg);padding:clamp(24px,2.4vw,36px);box-shadow:var(--shadow-sm)}
.cta{display:inline-flex;align-items:center;justify-content:center;height:52px;padding:0 26px;border-radius:var(--radius-md);font-family:var(--font-display);font-weight:700;font-size:var(--text-md);background:var(--brand-600);color:var(--paper-0);transition:background var(--duration-base) var(--ease-standard)}
.cta:hover{background:var(--brand-700);color:var(--paper-0)}
.cta.ghost{background:var(--brand-100);color:var(--brand-700)}
.cta.ghost:hover{background:var(--brand-200);color:var(--brand-900)}

/* pinned sections */
.pin{position:sticky;top:calc(var(--header-h) + var(--sticky-gap));align-self:start}
.stack{display:flex;flex-direction:column;gap:clamp(16px,2vw,28px)}
.stack .card{position:sticky;top:calc(var(--header-h) + var(--sticky-gap) + var(--i)*18px);border-radius:var(--radius-xl);padding:clamp(28px,3vw,52px);box-shadow:var(--shadow-sm)}
.split{display:grid;grid-template-columns:minmax(0,0.85fr) minmax(0,1.15fr);gap:clamp(32px,5vw,88px)}
/* minmax(0,1fr), not 1fr: a bare 1fr is minmax(auto,1fr), so a wide child such as
   a code block sets the track's minimum and pushes the page sideways. */
@media(max-width:900px){
  /* Block, not a one-column grid: in a grid each child gets its own row, and a
     sticky box cannot travel outside its row. As blocks they share .split as a
     tall containing block, so .pin can actually stick. */
  .split{display:block}
  .split>*{min-width:0}
  .split>*+*{margin-top:28px}
  /* Opaque, with a hairline and a soft edge: content scrolls underneath, so the
     pinned block has to read as a layer rather than as overlapping text. */
  /* The gap is padding here, not a top offset: on phones content scrolls
     directly under this block, and an open gap let a sliver of it show through
     between the header and the pin. Sitting flush with padding puts the same
     breathing room above the text while the background covers the seam. */
  .pin{top:var(--header-h);padding-top:var(--sticky-gap);z-index:5;background:var(--paper-50);
       padding-bottom:16px;border-bottom:1px solid var(--surface-border);
       box-shadow:0 14px 16px -14px rgb(36 29 26 / .16)}
  /* The stacked cards work either way: .stack is a flex column, so it stays a
     tall containing block. Only the offset needs to clear the shorter header. */
  .stack .card{top:calc(var(--header-h) + var(--sticky-gap) + var(--i)*14px)}
}

/* reveal */
.reveal{transition:opacity 500ms var(--ease-out),transform 500ms var(--ease-out)}
.js-reveal .reveal:not(.in){opacity:0;transform:translateY(18px)}
.reveal.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.js-reveal .reveal:not(.in){opacity:1;transform:none}.reveal{transition:none}html{scroll-behavior:auto}}

/* footer */
.ftr{background:var(--brand-900);color:var(--paper-100);padding:clamp(48px,6vw,80px) 0 32px;margin-top:clamp(48px,6vw,96px)}
.ftr .mark{color:var(--paper-0)}
.ftr .mark span{color:var(--brand-300)}
.ftr-grid{display:grid;grid-template-columns:1.4fr repeat(3,1fr);gap:clamp(28px,4vw,64px)}
@media(max-width:860px){.ftr-grid{grid-template-columns:1fr 1fr}}
.ftr h2{font-size:var(--text-sm);font-weight:700;letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--brand-300)}
.ftr a{color:var(--paper-100);font-size:var(--text-sm);display:inline-block;padding:5px 0;transition:color var(--duration-fast)}
.ftr a:hover{color:var(--paper-0)}
.ftr .rule{margin-top:clamp(32px,4vw,56px);padding-top:20px;display:flex;flex-wrap:wrap;gap:16px;justify-content:space-between;color:var(--paper-300);font-size:var(--text-sm)}

/* blog + prose */
.postlist{display:grid;gap:clamp(12px,1.4vw,20px)}
.postlink>div{transition:box-shadow var(--duration-base) var(--ease-standard)}
.postlink:hover>div{box-shadow:var(--shadow-md)}
.postcard-in{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:16px 32px;align-items:start}
@media(max-width:720px){.postcard-in{grid-template-columns:1fr}}
.postcard{background:var(--paper-0);border-radius:var(--radius-lg);padding:clamp(20px,2vw,32px);box-shadow:var(--shadow-sm);display:grid;grid-template-columns:minmax(0,1fr) auto;gap:16px 32px;align-items:start;transition:box-shadow var(--duration-base) var(--ease-standard),background var(--duration-base)}
.postcard:hover{box-shadow:var(--shadow-md)}
@media(max-width:720px){.postcard{grid-template-columns:1fr}}
.prose{max-width:68ch;overflow-wrap:break-word}
.prose pre{max-width:100%}
.prose>*:first-child{margin-top:0}
.prose h2{font-size:clamp(24px,2.2vw,32px);font-weight:700;margin:2em 0 .5em}
.prose h3{font-size:var(--text-lg);font-weight:700;margin:1.6em 0 .4em}
.prose p,.prose li{font-size:var(--text-md);line-height:1.75;color:var(--ink-700);max-width:68ch}
.prose p{margin:0 0 1.1em}
.prose ul,.prose ol{margin:0 0 1.2em;padding-left:1.3em;display:flex;flex-direction:column;gap:.5em}
.prose blockquote{margin:1.4em 0;background:var(--sage-100);border-radius:var(--radius-lg);padding:20px 24px}
.prose blockquote p{margin:0;color:var(--sage-700)}
.prose code{background:var(--paper-100);border-radius:6px;padding:2px 6px;font-size:.9em}
.prose pre{background:var(--dark-800);color:var(--paper-50);border-radius:var(--radius-md);padding:20px 22px;overflow-x:auto;margin:1.4em 0}
.prose pre code{background:none;color:inherit;padding:0}
.prose hr{border:none;height:1px;background:var(--paper-200);margin:2.4em 0}
.prose strong{color:var(--ink-900)}
.toc a{display:block;padding:6px 0;font-size:var(--text-sm);color:var(--ink-500)}
.toc a:hover{color:var(--brand-700)}
.toc a.active{color:var(--brand-700);font-weight:700}