
/* === src/assets/vendor/knowledge-hub/knowledge-hub.css === */
/* ============================================================================
   Knowledge Hub — canonical 3-column doc layout for content sites.

   Inspired by docs.obsidian.md: sidebar nav (left, sticky) + article column
   (centre, line-length-constrained) + on-this-page TOC (right, sticky).
   Translated into Marbl tokens.

   Use for: Thou Art That, future Marbl knowledge-hub microsites,
   informational pages, repo doc pages.

   Spec: ./knowledge-hub.md  ·  Preview: ./preview.html
   Settled: 28 April 2026

   Class prefix: .kh-*
   Loads alongside canonical site-header / menu / site-footer / cookie-consent.
   Consumer must include these via marbl-core.css bundle (or individual links).
   ============================================================================ */

/* Smooth-scroll anchor jumps from the right-side TOC.
   Combines with scroll-margin-top on h2/h3 to avoid sticky-header tuck. */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* === Page shell — main becomes the 3-col grid container === */

.kh-shell {
  display: grid;
  grid-template-columns: minmax(0, var(--kh-sidebar-w, 260px)) minmax(0, 1fr) minmax(0, var(--kh-toc-w, 240px));
  gap: var(--gap-md, 40px);
  max-width: var(--kh-shell-max, 1600px);
  margin: 0 auto;
  padding: var(--gap-md, 40px);
  align-items: start;
  position: relative;
}


/* Sidebar scrollbar override — thin + subtle grey, scoped to KH
   sidebar only. Page-level (html) scrollbar stays canonical ember
   per marbl-v2.css. Locked 30 Apr 2026. */
.kh-sidebar,
.kh-toc {
  scrollbar-width: thin;
  scrollbar-color: var(--marbl-white-15, rgba(255, 255, 255, 0.15)) transparent;
}
.kh-sidebar::-webkit-scrollbar,
.kh-toc::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.kh-sidebar::-webkit-scrollbar-track,
.kh-toc::-webkit-scrollbar-track {
  background: transparent;
}
.kh-sidebar::-webkit-scrollbar-thumb,
.kh-toc::-webkit-scrollbar-thumb {
  background: var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius-full, 9999px);
}
.kh-sidebar::-webkit-scrollbar-thumb:hover,
.kh-toc::-webkit-scrollbar-thumb:hover {
  background: var(--marbl-white-30, rgba(255, 255, 255, 0.3));
}

/* === Sidebar (left) — sticky tree nav + search === */

.kh-sidebar {
  position: sticky;
  top: var(--gap-md, 40px);
  max-height: calc(100dvh - var(--gap-md, 40px) * 2);
  overflow-y: auto;
  padding-right: var(--gap-xs, 10px);
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: var(--text-sm, 13px);
}

/* Section heading — used twice: above search and above contents.
   Ember accent. Consistent 20px gap below to the following content
   (search field or nav) so both stretches breathe equally. */
.kh-sidebar__heading {
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  line-height: 1.2;
  margin: 0 0 var(--gap-sm, 20px) 0;
}
.kh-sidebar__heading:not(:first-child) { margin-top: var(--gap-md, 40px); }

/* Search input — line style (bottom border only), matches Marbl input convention.
   Underline lights ember on focus. */
.kh-sidebar__search {
  display: block;
  width: 100%;
  margin: 0 0 var(--gap-md, 40px) 0;
  padding: var(--gap-xs, 10px) 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: 0;
  color: var(--marbl-white, #ffffff);
  font: inherit;
  font-size: var(--text-base, 15px);
  transition: border-color 0.15s ease;
  -webkit-appearance: none;
  appearance: none;
}

.kh-sidebar__search::placeholder { color: var(--marbl-white-40, rgba(255, 255, 255, 0.4)); }
.kh-sidebar__search:focus { outline: none; border-bottom-color: var(--marbl-ember, #F35226); }
.kh-sidebar__search::-webkit-search-cancel-button { -webkit-appearance: none; }

/* Search field wrap — provides positioning context for the absolute-
   floated results panel so it overlays content instead of pushing
   the nav (and the sidebar's own scrollbar) down. */
.kh-sidebar__search-field {
  position: relative;
  margin: 0 0 var(--gap-md, 40px) 0;
}
.kh-sidebar__search-field .kh-sidebar__search { margin-bottom: 0; }

/* Search results panel — position:fixed escapes the sidebar's overflow:auto
   so the panel never gets clipped or triggers a sidebar scrollbar. JS
   computes top/left/width from the input's bounding rect on each render
   and on viewport scroll/resize. */
.kh-search-results {
  display: none;
  position: fixed;
  z-index: 100;
  padding: var(--gap-2xs, 6px);
  background: var(--marbl-charcoal-light, #1d1a1b);
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  border-radius: var(--radius, 10px);
  max-height: 50vh;
  overflow-y: auto;
  /* Themed scrollbar — Firefox + WebKit. Tracks the panel bg. */
  scrollbar-color: var(--marbl-white-15, rgba(255, 255, 255, 0.15)) var(--marbl-charcoal-light, #1d1a1b);
  scrollbar-width: thin;
}
.kh-search-results.is-open { display: block; }
.kh-search-results::-webkit-scrollbar { width: 8px; }
.kh-search-results::-webkit-scrollbar-track { background: var(--marbl-charcoal-light, #1d1a1b); }
.kh-search-results::-webkit-scrollbar-thumb {
  background: var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius-sm, 4px);
}
.kh-search-results::-webkit-scrollbar-thumb:hover {
  background: var(--marbl-white-30, rgba(255, 255, 255, 0.3));
}

.kh-search-results__item {
  display: block;
  padding: var(--gap-xs, 10px) var(--gap-sm, 20px);
  text-decoration: none;
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  border-radius: var(--radius-sm, 4px);
  transition: background 0.15s ease;
}
.kh-search-results__item + .kh-search-results__item { margin-top: var(--gap-3xs, 4px); }
.kh-search-results__item:hover,
.kh-search-results__item:focus-visible {
  background: var(--marbl-white-06, rgba(255, 255, 255, 0.06));
  color: var(--marbl-white, #ffffff);
  outline: none;
}

.kh-search-results__crumb {
  display: block;
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  margin-bottom: var(--gap-3xs, 4px);
}
.kh-search-results__title {
  display: block;
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: var(--text-base, 15px);
  font-weight: var(--font-semibold, 600);
  color: var(--marbl-white, #ffffff);
  margin-bottom: var(--gap-3xs, 4px);
}
.kh-search-results__snippet {
  display: block;
  font-size: var(--text-sm, 13px);
  line-height: 1.5;
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
}
.kh-search-results__empty {
  margin: 0;
  padding: var(--gap-xs, 10px) var(--gap-sm, 20px);
  font-size: var(--text-sm, 13px);
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
}
.kh-search-results mark {
  background: transparent;
  color: var(--marbl-ember, #F35226);
  font-weight: var(--font-semibold, 600);
}

/* Tree nav: ul/li, indent on nesting, no bullets */
.kh-nav { list-style: none; padding: 0; margin: 0; }
/* Obsidian-style: top-level groups stack tight, just enough breathing room. */
.kh-nav__group + .kh-nav__group { margin-top: var(--gap-3xs, 4px); }

/* Group label is a button — clicking expands/collapses the children
   with a slide animation. Chevron sits LEFT of the label (Obsidian-style).
   Sentence case (no uppercase / letter-spacing) so labels read like links. */
.kh-nav__group-label {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--gap-2xs, 6px);
  width: 100%;
  padding: 0;
  background: transparent;
  border: 0;
  font-family: inherit;
  font-size: var(--text-sm, 13px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 0;
  text-transform: none;
  color: var(--marbl-white, #ffffff);
  margin: 0 0 var(--gap-3xs, 4px) 0;
  cursor: pointer;
  text-align: left;
  line-height: 1.5;
}

.kh-nav__group-label:focus-visible {
  outline: 2px solid var(--marbl-ember, #F35226);
  outline-offset: 2px;
  border-radius: var(--radius-xs, 2px);
}

/* Obsidian-style chevron: small, white, sits left of label.
   Default (expanded) = points down. Collapsed = points right. */
.kh-nav__group-chevron {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  transition: transform 0.2s ease;
  fill: none;
  stroke: var(--marbl-white, #ffffff);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.kh-nav__group[aria-expanded="false"] > .kh-nav__group-label > .kh-nav__group-chevron {
  transform: rotate(-90deg);
}

/* Sliding-tier children container — collapses to height 0 when group is closed.
   Uses grid 1fr/0fr trick for true height animation without max-height guesswork.
   Wrapper is a div (not ul) so the inner ul can hold li children validly.
   Direct-child selectors so nested groups don't fight their parents. */
.kh-nav__children {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.25s ease;
}

.kh-nav__children-inner {
  list-style: none;
  padding: 0;
  margin: 0;
  overflow: hidden;
  min-height: 0;
}

.kh-nav__group[aria-expanded="false"] > .kh-nav__children {
  grid-template-rows: 0fr;
}

/* Nested groups — indent by tier so the hierarchy reads visually. */
.kh-nav__children-inner .kh-nav__group {
  margin-top: var(--gap-xs, 10px);
  padding-left: var(--gap-xs, 10px);
}
.kh-nav__children-inner .kh-nav__children-inner .kh-nav__group {
  padding-left: var(--gap-sm, 20px);
}

.kh-nav__item { padding: var(--gap-3xs) 0; list-style: none; }
.kh-nav__item--nested { padding-left: var(--gap-sm, 20px); }

.kh-nav__link {
  display: block;
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
  text-decoration: none;
  line-height: 1.5;
  border-left: 2px solid transparent;
  padding-left: var(--gap-xs, 10px);
  margin-left: -10px;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.kh-nav__link:hover {
  color: var(--marbl-white, #ffffff);
}

/* Active page: white text + subtle white border, NOT ember.
   Keeps the orange contained to group labels (intentional accent). */
.kh-nav__link[aria-current="page"] {
  color: var(--marbl-white, #ffffff);
  border-left-color: var(--marbl-white-30, rgba(255, 255, 255, 0.3));
  font-weight: var(--font-semibold, 600);
}

/* Top-level hierarchy emphasis (locked 29 Apr 2026):
   - direct .kh-nav children (top-level leaves + group labels) read WHITE
     and hover EMBER -- they're the entry points
   - nested children (everything inside .kh-nav__children-inner) keep the
     muted grey + white-on-hover treatment defined above */
.kh-nav > .kh-nav__item > .kh-nav__link {
  color: var(--marbl-white, #ffffff);
}
.kh-nav > .kh-nav__item > .kh-nav__link:hover {
  color: var(--marbl-ember, #F35226);
}
.kh-nav > .kh-nav__group > .kh-nav__group-label {
  color: var(--marbl-white, #ffffff);
}
.kh-nav > .kh-nav__group > .kh-nav__group-label:hover {
  color: var(--marbl-ember, #F35226);
}

/* Search filter: hide non-matching items + groups with no visible matches */
.kh-nav__item.is-hidden { display: none; }
.kh-nav__group.is-hidden { display: none; }

/* Sidebar top row: home icon button + search input on a single row.
   Pulls the Contents nav up the sidebar - the Search heading was
   removed because the input's placeholder + aria-label carry the
   meaning, and the heading was just adding vertical noise.
   Locked 30 Apr 2026. */
.kh-sidebar__top {
  display: flex;
  align-items: center;
  gap: var(--gap-xs, 10px);
  margin-bottom: var(--gap-sm, 20px);
}

.kh-sidebar__top .kh-sidebar__home {
  flex: 0 0 auto;
  margin: 0;
  text-decoration: none;
}

/* "Home" label is visually hidden on desktop (icon-only button - SR users
   get the parent's aria-label). Mobile rule below reveals it as the only
   visible content (icon hidden there). Locked 1 May 2026. */
.kh-sidebar__home-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.kh-sidebar__top .kh-sidebar__search-field {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;                  /* override the standalone search-field's bottom margin */
}

.kh-sidebar__top .kh-sidebar__search {
  height: 40px;               /* match btn-icon--mini (home button is 40x40) */
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  line-height: 38px;          /* 40 - 1 (border-bottom) - 1 (visual) */
}

/* === Article column (centre) === */

.kh-article {
  min-width: 0;
  max-width: var(--kh-article-max, 800px);
  margin: 0 auto;
  font-family: var(--font-body, 'Inter', sans-serif);
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  line-height: 1.7;
}

/* Article header gap → 40 (was 80). Locked 30 Apr 2026 — section
   spacing is too loud at 80px between header and first content; 40
   reads as "next thing related" rather than "next section". */
.kh-article__header { margin-bottom: var(--gap-md, 40px); }

/* Featured image at top of an article. Sits above the eyebrow.
   Same border-radius as code blocks; full-bleed within the article column. */
.kh-article__featured {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 var(--gap-md, 40px) 0;
  border-radius: var(--radius, 10px);
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
}

/* Responsive YouTube / video embed wrapper.
   Use: <div class="kh-video"><iframe src="..." allowfullscreen></iframe></div> */
.kh-video {
  width: 100%;
  margin: var(--gap-md, 40px) 0;
  border-radius: var(--radius, 10px);
  overflow: hidden;
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  aspect-ratio: 16 / 9;
}
.kh-video iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.kh-article__eyebrow {
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  margin: 0 0 var(--gap-sm, 20px) 0;
}

.kh-article__title {
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: clamp(36px, 1.5rem + 2.5vw, 56px);
  font-weight: var(--font-bold, 700);
  line-height: 1.1;
  color: var(--marbl-white, #ffffff);
  letter-spacing: -0.02em;
  margin: 0 0 var(--gap-sm, 20px) 0;
  text-wrap: balance;
}

.kh-article__lead {
  font-size: var(--text-lg, 18px);
  line-height: 1.6;
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  margin: 0;
  text-wrap: pretty;
}

.kh-article__body { font-size: var(--text-base, 15px); }

.kh-article__body h2 {
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: clamp(24px, 1.2rem + 1vw, 32px);
  font-weight: var(--font-bold, 700);
  line-height: 1.2;
  color: var(--marbl-white, #ffffff);
  margin: var(--gap-xl, 80px) 0 var(--gap-sm, 20px) 0;
  padding-bottom: var(--gap-xs, 10px);
  border-bottom: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  text-wrap: balance;
  scroll-margin-top: var(--gap-md, 40px);
}

/* Inline audio block at top of article body (KH §6.2). 40px gap below
   so the next h2 lands at consistent rhythm. Locked canonical 30 Apr
   2026 (was TAT-local in kh-content.css). */
.kh-article__body > .marbl-waveform.mwp-custom:first-child {
  margin: 0 0 var(--gap-md, 40px);
}

/* Strip trailing margin off the last paragraph in any article column or
   sub-section so the visual rhythm stays uniform between blocks. */
.kh-article__body p:last-of-type,
.kh-article__body article p:last-of-type {
  margin-bottom: 0;
}

.kh-article__body h3 {
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: var(--text-xl, 20px);
  font-weight: var(--font-semibold, 600);
  color: var(--marbl-white, #ffffff);
  margin: var(--gap-md, 40px) 0 var(--gap-sm, 20px) 0;
  scroll-margin-top: var(--gap-md, 40px);
}

.kh-article__body p {
  margin: 0 0 var(--gap-sm, 20px) 0;
  text-wrap: pretty;
}

.kh-article__body ul,
.kh-article__body ol {
  margin: 0 0 var(--gap-sm, 20px) 0;
  padding-left: var(--gap-sm, 20px);
}

.kh-article__body li { margin: 0 0 var(--gap-tight) 0; }

/* Markdown horizontal rule — `---` in source. Visually collapsed to
   zero footprint: the surrounding h2 (80px top margin) creates the
   section break already, and a bare line in mid-article reads as
   random noise. Source semantics preserved — screen readers still
   announce the separator. Locked 30 Apr 2026. */
.kh-article__body hr {
  border: 0;
  height: 0;
  margin: 0;
}

.kh-article__body a {
  color: var(--marbl-ember, #F35226);
  text-decoration: none;
  border-bottom: 1px solid var(--marbl-ember-30, rgba(243, 82, 38, 0.3));
  transition: border-color 0.15s ease;
}
.kh-article__body a:hover { border-bottom-color: var(--marbl-ember, #F35226); }

.kh-article__body strong { color: var(--marbl-white, #ffffff); font-weight: var(--font-semibold, 600); }

.kh-article__body code {
  font-family: ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace;
  font-size: 0.9em;
  padding: 2px 6px;
  background: var(--marbl-white-06, rgba(255, 255, 255, 0.06));
  border-radius: var(--radius-sm, 4px);
  color: var(--marbl-white, #ffffff);
}

.kh-article__body pre {
  margin: var(--gap-sm, 20px) 0;
  padding: var(--gap-sm, 20px);
  background: var(--marbl-charcoal-light, #1d1a1b);
  border: 1px solid var(--marbl-white-06, rgba(255, 255, 255, 0.06));
  border-radius: var(--radius, 10px);
  overflow-x: auto;
  font-family: ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace;
  font-size: var(--text-sm, 13px);
  line-height: 1.6;
}
.kh-article__body pre code { padding: 0; background: transparent; border-radius: 0; }

.kh-article__body blockquote {
  margin: var(--gap-md, 40px) 0;
  padding: var(--gap-sm, 20px) var(--gap-md, 40px);
  border-left: 2px solid var(--marbl-ember, #F35226);
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  font-style: italic;
  font-family: 'Petrona', Georgia, serif;
  font-size: var(--text-lg, 18px);
}

.kh-article__body hr {
  border: 0;
  height: 1px;
  background: var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  margin: var(--gap-xl, 80px) 0;
}

/* Pagination at end of article */
.kh-pagination {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-sm, 20px);
  margin-top: var(--gap-xl, 80px);
  padding-top: var(--gap-md, 40px);
  border-top: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
}

.kh-pagination__link {
  padding: var(--gap-sm, 20px);
  background: transparent;
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  border-radius: var(--radius, 10px);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease;
}
.kh-pagination__link:hover { border-color: var(--marbl-white-15, rgba(255, 255, 255, 0.15)); }
.kh-pagination__link--prev { text-align: left; }
.kh-pagination__link--next { text-align: right; }

.kh-pagination__label {
  display: block;
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  /* white-65 hits WCAG AA contrast ratio against --marbl-charcoal.
     white-40 was 3.5:1 (failed Lighthouse a11y). Locked 1 May 2026. */
  color: var(--marbl-white-65, rgba(255, 255, 255, 0.65));
  margin-bottom: var(--gap-tight);
}

.kh-pagination__title {
  font-family: var(--font-heading, 'Urbanist', sans-serif);
  font-size: var(--text-base, 15px);
  font-weight: var(--font-semibold, 600);
  color: var(--marbl-white, #ffffff);
}

/* === TOC (right) — sticky on this page === */

.kh-toc {
  position: sticky;
  top: var(--gap-md, 40px);
  max-height: calc(100dvh - var(--gap-md, 40px) * 2);
  overflow-y: auto;
  /* Full-card treatment: border on all sides, no background fill,
     standard radius + padding. Locked 30 Apr 2026 (replaced earlier
     border-left only). */
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  border-radius: var(--radius, 10px);
  padding: var(--gap-sm, 20px);
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: var(--text-xs, 11px);
}

/* Knowledge graph slot — sits above the "On this page" label inside
   the right column. Component to be plugged in (Obsidian-style force
   graph showing page relationships). Empty stub for now; the slot
   exists so consumers can drop in markup without re-shaping the
   canonical partial. Locked 30 Apr 2026. */
.kh-toc__graph {
  width: 100%;
  aspect-ratio: 1 / 1;
  margin-bottom: var(--gap-sm, 20px);
  border-bottom: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  padding-bottom: var(--gap-sm, 20px);
}
.kh-toc__graph:empty { display: none; }

.kh-toc__label {
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  margin: 0 0 var(--gap-sm, 20px) 0;
}

.kh-toc__list { list-style: none; padding: 0; margin: 0; }
.kh-toc__item { padding: var(--gap-3xs) 0; }
.kh-toc__item--nested { padding-left: var(--gap-xs, 10px); }

.kh-toc__link {
  display: block;
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
  text-decoration: none;
  font-size: var(--text-sm, 13px);
  line-height: 1.5;
  transition: color 0.15s ease;
}
.kh-toc__link:hover { color: var(--marbl-white, #ffffff); }

/* Active TOC link: white not orange (contains ember to the section labels). */
.kh-toc__link[aria-current="true"] {
  color: var(--marbl-white, #ffffff);
  font-weight: var(--font-semibold, 600);
}

/* === Mobile-friendly drawer behaviour ===
   Below 1024px: drop right-side TOC. Below 768px: collapse left sidebar
   into a drawer (toggled by a button at the top of .kh-article). */

@media (max-width: 1024px) {
  .kh-shell {
    grid-template-columns: minmax(0, var(--kh-sidebar-w, 240px)) minmax(0, 1fr);
  }
  .kh-toc { display: none; }
}

/* Mobile drawer toggle: hidden on desktop. Below 768px it appears and the
   sidebar contents collapse beneath it (own grid-rows slide animation).
   Sized to match an input field (44px tap target, base text). */
.kh-sidebar__toggle {
  display: none;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 44px;
  padding: var(--gap-xs, 10px) var(--gap-sm, 20px);
  background: transparent;
  border: 1px solid var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius, 10px);
  color: var(--marbl-white, #ffffff);
  font-family: inherit;
  font-size: var(--text-base, 15px);
  font-weight: var(--font-semibold, 600);
  cursor: pointer;
}

.kh-sidebar__toggle-chevron {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  transition: transform 0.25s ease;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.kh-sidebar[aria-expanded="false"] .kh-sidebar__toggle-chevron {
  transform: rotate(-90deg);
}

@media (max-width: 768px) {
  .kh-shell {
    grid-template-columns: 1fr;
    padding: var(--gap-sm, 20px);
    gap: var(--gap-sm, 20px);
  }
  .kh-sidebar {
    position: relative;
    top: 0;
    max-height: none;
    border-bottom: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
    padding-bottom: var(--gap-sm, 20px);
    margin-bottom: var(--gap-sm, 20px);
  }

  .kh-sidebar__toggle { display: flex; }

  /* Sidebar contents (search + nav) collapsed in a sliding panel */
  .kh-sidebar__panel {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.3s ease, margin-top 0.3s ease;
    margin-top: var(--gap-sm, 20px);
  }
  .kh-sidebar__panel > div {
    overflow: hidden;
    min-height: 0;
  }
  .kh-sidebar[aria-expanded="false"] .kh-sidebar__panel {
    grid-template-rows: 0fr;
    margin-top: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kh-nav__link,
  .kh-toc__link,
  .kh-article__body a,
  .kh-pagination__link { transition: none; }
}

/* === src/assets/vendor/waveform-player/waveform-player.css === */
/**
 * Waveform Player wrapper — Marbl pill-controls + line waveform.
 * Harvested from marbl.codes/thou-art-that 20 April 2026.
 * Truly canonical from 25 April 2026: pill-controls CSS moved here
 * from preview.html inline `<style>` block so consumers can drop the
 * component into any page without copying preview-only styles.
 *
 * Depends on: ArrayPress WaveformPlayer v1.5.2 CSS + JS, vendored
 * at marbl-codes/src/website/components/waveform-player/assets/arraypress/v1.5.2/.
 *
 * Markup: see waveform-player.md §1 (Structure). The wrapper is
 *   .marbl-waveform.mwp-custom > .mwp-inline > .mwp-controls-pill +
 *   .mwp-waveform-area > [data-waveform-player] + audio.mwp-fallback
 */

/* ===== Wrapper ============================================================ */

.marbl-waveform {
  container-type: inline-size;
  container-name: waveform-player;
  margin: var(--gap-sm, 20px) 0;
  min-height: 60px;
}

/* Marbl-brand focus ring on library's internal play button. */
.marbl-waveform [data-waveform-player] button:focus-visible {
  outline: 2px solid var(--marbl-ember, #F35226);
  outline-offset: 2px;
  border-radius: var(--radius-circle, 50%);
}

/* Native <audio> fallback — held invisible for 1.5s after page paint so
 * browser snapshots (e.g. View Transitions API) don't catch it before
 * waveform-player init fires. After 1.5s, if init succeeded the :has()
 * rule below keeps it hidden permanently; if init failed the fallback
 * reveals via the `mwp-fallback-reveal` keyframe so users without JS
 * still get a working player. Robust graceful degradation.
 *
 * Pattern earned 29 Apr 2026 on TAT microsite when View Transitions
 * caught the native player flashing before init. */
.marbl-waveform .mwp-fallback {
  width: 100%;
  margin-top: var(--gap-xs, 10px);
  border-radius: var(--radius, 10px);
  opacity: 0;
  animation: mwp-fallback-reveal 0s ease 1.5s forwards;
}

.marbl-waveform .mwp-fallback[hidden] {
  display: none;
}

@keyframes mwp-fallback-reveal {
  to { opacity: 1; }
}

/* Auto-hide the native fallback once the waveform-player has initialised
 * on the same row. CSS :has() keys off the data-waveform-initialized
 * attribute that init.js sets after `new WaveformPlayer(player)`. This is
 * more robust than JS-toggling [hidden] because it never races with the
 * library's DOM wrap or any post-init mutations. Browser support: Chrome
 * 105+, Firefox 121+, Safari 15.4+ — within Marbl's evergreen target. */
.mwp-inline:has([data-waveform-player][data-waveform-initialized]) .mwp-fallback {
  animation: none;
  display: none !important;
}

/* ===== Inline layout (pill on left, waveform fills remainder) ============== */

.mwp-inline {
  display: flex;
  align-items: center;
  gap: var(--gap-sm, 20px);
}

.mwp-inline .mwp-waveform-area {
  flex: 1;
  min-width: 0;
}

/* ===== Hide library native UI when .mwp-custom is set ===================== */

/* Native play button — accessible but visually hidden so our custom pill
 * controls can drive playback through it (proxy-click pattern). */
.mwp-custom .waveform-btn {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0,0,0,0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
  pointer-events: none !important;
}

.mwp-custom .waveform-info {
  display: none !important;
}

/* Prevent text selection + outline rings on canvas interaction. */
.mwp-custom .mwp-waveform-area,
.mwp-custom [data-waveform-player] {
  user-select: none;
  -webkit-user-select: none;
}

.mwp-custom [data-waveform-player] canvas,
.mwp-custom [data-waveform-player] canvas:focus,
.mwp-custom [data-waveform-player] canvas:active,
.mwp-custom .waveform-container,
.mwp-custom .waveform-track {
  outline: none !important;
  -webkit-tap-highlight-color: transparent !important;
}

/* Transparent waveform background, no glow (canvas glow patched in init.js). */
.mwp-custom .waveform-player-inner,
.mwp-custom .waveform-body,
.mwp-custom .waveform-track,
.mwp-custom [data-waveform-player] {
  background: transparent !important;
}

.mwp-custom .waveform-track canvas {
  filter: none !important;
  box-shadow: none !important;
}

/* ===== Pill controls (canonical Marbl) ===================================== */

.mwp-controls-pill {
  display: inline-flex;
  align-items: center;
  gap: 0;
  border: 1px solid var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius, 10px);
  padding: var(--gap-half, 5px);
  background: transparent;
  flex-shrink: 0;
  width: 93px;
  transition: width 0.4s cubic-bezier(0.32, 0.72, 0, 1);
}

.mwp-controls-pill:hover,
.mwp-controls-pill:focus-within,
.mwp-controls-pill.is-expanded {
  width: 134px;
}

/* Volume + secondary divider fade in when the pill expands. */
.mwp-pill-expandable {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}

.mwp-controls-pill:hover .mwp-pill-expandable,
.mwp-controls-pill:focus-within .mwp-pill-expandable,
.mwp-controls-pill.is-expanded .mwp-pill-expandable {
  opacity: 1;
  visibility: visible;
}

/* Pill icon buttons (play, volume) — UI Items style: ember on hover, no bg. */
.mwp-btn {
  width: var(--gap-md, 40px);
  height: var(--gap-md, 40px);
  border-radius: var(--radius-circle, 50%);
  border: none;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}

.mwp-btn:focus-visible {
  outline: 2px solid var(--marbl-ember, #F35226);
  outline-offset: 2px;
}

.mwp-btn svg {
  width: 14px;
  height: 14px;
  fill: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
  transition: fill var(--transition-fast, 0.15s ease);
}

.mwp-btn:hover svg {
  fill: var(--marbl-ember, #F35226);
}

/* Play icon optical-centre nudge. */
.mwp-btn--play .icon-play {
  margin-left: 2px;
}

/* Time display. */
.mwp-time {
  padding: 0 var(--gap-xs, 10px);
  font-family: var(--font-body, 'Inter', sans-serif);
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  height: 40px;
  line-height: 40px;
  flex-shrink: 0;
  white-space: nowrap;
}

/* Dividers between pill segments. */
.mwp-divider {
  width: 1px;
  height: 20px;
  background: var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  flex-shrink: 0;
}

/* ===== Volume slider (pops out to the right of the pill) =================== */

.mwp-volume-wrap {
  position: relative;
  flex-shrink: 0;
}

.mwp-volume-slider {
  position: absolute;
  top: 50%;
  left: calc(100% + var(--gap-xs, 10px));
  transform: translateY(-50%) scaleX(0);
  transform-origin: center left;
  background: var(--marbl-charcoal, #171415);
  border: 1px solid var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius, 10px);
  height: 48px;
  display: flex;
  align-items: center;
  padding: 0 14px;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--transition-base, 0.2s ease),
    transform 0.2s cubic-bezier(0.32, 0.72, 0, 1),
    visibility var(--transition-base, 0.2s ease);
  z-index: 10;
}

.mwp-volume-slider.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(-50%) scaleX(1);
}

.mwp-volume-slider input[type="range"] {
  width: var(--gap-xl, 80px);
  height: var(--radius-xs, 4px);
  appearance: none;
  background: var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius-2xs, 2px);
  outline: none;
}

.mwp-volume-slider input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: var(--icon-sm, 14px);
  height: var(--icon-sm, 14px);
  border-radius: var(--radius-circle, 50%);
  background: var(--marbl-ember, #F35226);
  cursor: pointer;
  border: none;
}

.mwp-volume-slider input[type="range"]::-moz-range-thumb {
  width: var(--icon-sm, 14px);
  height: var(--icon-sm, 14px);
  border-radius: var(--radius-circle, 50%);
  background: var(--marbl-ember, #F35226);
  cursor: pointer;
  border: none;
}

/* ===== Screen-reader live region (consumers can place anywhere) ============ */

.mwp-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ===== Container-query responsive ==========================================
 *
 * Pill controls + waveform stay inline at every container width. Locked
 * 1 May 2026 (Richard): the previous "stack pill above waveform below
 * 400px" stretched the pill full-width on mobile which read as a heavy
 * UI block. Inline reads as a single discrete player even when tight.
 * Pill shrinks naturally; waveform fills remaining space.
 */
.marbl-waveform .mwp-inline {
  flex-wrap: nowrap;
}

/* ===== Reduced motion ====================================================== */

@media (prefers-reduced-motion: reduce) {
  .mwp-controls-pill,
  .mwp-pill-expandable,
  .mwp-volume-slider,
  .mwp-btn svg {
    transition: none !important;
  }
  /* ArrayPress v1.5.2 has no CSS animations of its own. Revisit on library upgrade. */
}

/* === src/assets/vendor/repo-widget/repo-widget.css === */
/**
 * Marbl repo-widget canonical CSS.
 * Spec: ./repo-widget.md
 *
 * Two variants:
 *   .repo-widget--filled       solid card, body-content placement
 *   .repo-widget--transparent  no background, sidebar/aux placement
 *
 * The action buttons inside the widget use the canonical ui-items button
 * classes (.btn .btn--fill-up.btn--mini, .btn.btn--outline.btn--mini) -
 * NOT bespoke styles. Consumers must vendor ui-items/button.css alongside.
 *
 * All values from marbl-v2.css tokens. No invented px values.
 */

.repo-widget {
  display: flex;
  flex-direction: column;
  gap: var(--gap-xs, 10px);
  padding: var(--gap-sm, 20px);
  border-radius: var(--radius, 10px);
  background: var(--marbl-charcoal-light, #1d1a1b);
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
  font-family: var(--font-body, var(--marbl-font-body, 'Inter', sans-serif));
  color: var(--marbl-white-85, rgba(255, 255, 255, 0.85));
}

/* Transparent variant - sidebar use */
.repo-widget--transparent {
  background: transparent;
  border: 1px solid var(--marbl-white-10, rgba(255, 255, 255, 0.1));
  padding: var(--gap-sm, 20px);
}

/* Hide filled-only chrome inside transparent variant */
.repo-widget--transparent .repo-widget__description--filled-only {
  display: none;
}

/* ===== Header ============================================================= */

.repo-widget__header {
  display: flex;
  align-items: center;
  gap: var(--gap-xs, 10px);
  min-width: 0;
}

.repo-widget__icon {
  width: var(--icon-lg, 20px);
  height: var(--icon-lg, 20px);
  flex-shrink: 0;
  fill: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

.repo-widget__name {
  margin: 0;
  font-size: var(--text-sm, 13px);
  font-weight: 500;
  letter-spacing: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.repo-widget__name a {
  color: var(--marbl-white, #ffffff);
  text-decoration: none;
  transition: color 150ms ease;
}

.repo-widget__name a:hover,
.repo-widget__name a:focus-visible {
  color: var(--marbl-ember, #F35226);
}

.repo-widget__name a:focus-visible {
  outline: 2px solid var(--marbl-ember, #F35226);
  outline-offset: 2px;
  border-radius: var(--radius-sm, 5px);
}

/* ===== Description ======================================================== */

.repo-widget__description {
  margin: 0;
  font-size: var(--text-sm, 13px);
  line-height: 1.5;
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

/* ===== Meta row =========================================================== */

.repo-widget__meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-2xs, 8px);
  font-size: var(--text-xs, 11px);
  color: var(--marbl-white-65, rgba(255, 255, 255, 0.65));
}

.repo-widget__stat {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-3xs, 5px);
  white-space: nowrap;
}

.repo-widget__stat a {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-3xs, 5px);
  color: inherit;
  text-decoration: none;
  transition: color 150ms ease;
}

.repo-widget__stat a:hover,
.repo-widget__stat a:focus-visible,
.repo-widget__stat a:hover .repo-widget__stat-value,
.repo-widget__stat a:focus-visible .repo-widget__stat-value,
.repo-widget__stat a:hover .repo-widget__stat-label,
.repo-widget__stat a:focus-visible .repo-widget__stat-label {
  color: var(--marbl-ember, #F35226);
}

.repo-widget__stat a:focus-visible {
  outline: 2px solid var(--marbl-ember, #F35226);
  outline-offset: 2px;
  border-radius: var(--radius-sm, 5px);
}

.repo-widget__stat-icon {
  width: var(--icon-xs, 12px);
  height: var(--icon-xs, 12px);
  flex-shrink: 0;
  fill: currentColor;
  opacity: 0.85;
}

.repo-widget__stat-value {
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  color: var(--marbl-white-85, rgba(255, 255, 255, 0.85));
}

.repo-widget__stat-label {
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
}

/* ===== Actions ============================================================
   Buttons are the canonical .btn / .btn--fill-up / .btn--outline / .btn--mini
   pattern from ui-items/button.css. The footer is a flex container only;
   button styling lives in the canonical button.css and must be vendored
   alongside this component. */

/* DEFAULT button layout: inline at content-natural widths, wrap if tight.
   Visual variant (--filled / --transparent) is INDEPENDENT of layout -
   either visual variant uses the default inline layout unless the
   --stack-actions modifier is added (see below). */
.repo-widget__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-xs, 10px);
  margin-top: var(--gap-3xs, 5px);
}

/* MODIFIER --stack-actions: opt-in vertical stack with full-width buttons.
   For narrow contexts (sidebars, rails). Composable with either visual
   variant. Apply alongside --transparent for the typical sidebar use. */
.repo-widget--stack-actions .repo-widget__actions {
  flex-direction: column;
  align-items: stretch;
}
.repo-widget--stack-actions .repo-widget__actions .btn {
  width: 100%;
  justify-content: center;
}

/* MOBILE (any variant, any modifier): buttons collapse to inline 50/50
   equal-width. Overrides --stack-actions on small viewports because
   stacking on a phone wastes vertical space. */
@media (max-width: 768px) {
  .repo-widget .repo-widget__actions {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: stretch;
  }
  .repo-widget .repo-widget__actions .btn {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    padding-left: var(--gap-2xs, 8px);
    padding-right: var(--gap-2xs, 8px);
    justify-content: center;
  }
}

/* ===== Reduced motion ===================================================== */

/* Hide filled-only stats inside transparent variant (e.g. version). */
.repo-widget--transparent .repo-widget__stat--filled-only {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .repo-widget__name a,
  .repo-widget__stat a {
    transition: none;
  }
}

/* === src/assets/css/landing.css === */
/* ===================================================================
   Thou Art That — Landing — LOCKED
   TAT-specific hero rhythm only. Tokens, scrollbar, cursor, button,
   header, footer, menu, cookie banner, waveform-player chrome all
   come from the Marbl design system (marbl-v2.css + canonical
   component CSS) loaded above this file.

   Per PLAN.md (locked 24 April 2026, Phase 1).
   Re-locked 29 April 2026 after canonical chrome re-vendor sweep
   (menu/site-header/site-footer/marbl-v2/button/cookie-consent/
   waveform-player CSS resync vs marbl-codes canonical) and burger
   left-column nav trim to "The piece" + "Source" only. Do not modify
   landing.html or landing.css without explicit Richard sign-off.

   Additions on top of lock (29 Apr 2026, sign-off Richard):
   - View Transitions API: subtle cross-fade with scale on every
     same-origin TAT navigation (see "Page transition" block below).
   =================================================================== */

/* Page transition (View Transitions API) — landing surface only.
   Pairs with the matching opt-in injected into the origin-story page
   by build.mjs. All other TAT routes do NOT opt in, so navigation
   between them stays instant per Richard's call 29 Apr 2026.

   Stronger settings than the first pass: 3% scale, 500/650ms,
   so the transition is felt rather than guessed at. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: marbl-page-fade-out 500ms cubic-bezier(0.32, 0.72, 0, 1) both;
}

::view-transition-new(root) {
  animation: marbl-page-fade-in 650ms cubic-bezier(0.32, 0.72, 0, 1) both;
}

@keyframes marbl-page-fade-out {
  to {
    opacity: 0;
    transform: scale(0.97);
  }
}

@keyframes marbl-page-fade-in {
  from {
    opacity: 0;
    transform: scale(1.03);
  }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.01ms;
  }
}

/* Audio fallback delayed-reveal now lives in canonical
   waveform-player.css (promoted from TAT-local 29 Apr 2026). */

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--marbl-ember, #F35226);
  color: var(--marbl-charcoal, #131112);
  padding: var(--space-3, 12px) var(--space-5, 20px);
  text-decoration: none;
  border-radius: 0 0 var(--radius, 10px) 0;
  font-family: var(--marbl-font-body, 'Inter', sans-serif);
  font-weight: var(--font-semibold, 600);
  z-index: 100;
}
.skip-link:focus {
  left: 0;
  outline: 2px solid var(--marbl-white, #fff);
  outline-offset: 2px;
}

/* Page-level layout: header / main / footer flex column so the hero
   centres vertically when the viewport is taller than the content. */
body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* When the burger menu opens, .site-header gets .menu-is-open and goes
   position:fixed (canonical pin behaviour, see site-header.md §4). That
   removes ~90px of flow space and the centred hero jumps up. Hold the
   space here while the menu is open. */
body:has(.site-header.menu-is-open) {
  padding-top: 90px;
}

.tat-landing-main {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gap-lg, 60px) var(--gap-md, 40px) var(--gap-xl, 80px);
}

/* Hero */
.tat-hero {
  max-width: 720px;
  width: 100%;
  text-align: center;
}

.tat-hero__eyebrow {
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  line-height: 1;
  margin: 0 0 var(--gap-sm, 20px);
}

.tat-hero__title {
  font-family: var(--marbl-font-display, 'Urbanist', sans-serif);
  font-size: clamp(48px, 8vw, 96px);
  font-weight: var(--font-extrabold, 800);
  line-height: 1;
  letter-spacing: -0.03em;
  margin: 0 0 var(--space-6, 24px);
  color: var(--marbl-white, #ffffff);
}

.tat-hero__title-accent {
  font-family: var(--marbl-font-accent, 'Petrona', Georgia, serif);
  font-style: italic;
  font-weight: 700;
  color: var(--marbl-ember, #F35226);
}

.tat-hero__strapline {
  font-family: var(--marbl-font-body, 'Inter', sans-serif);
  font-size: clamp(17px, 2vw, 20px);
  line-height: 1.5;
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  margin: 0 auto var(--gap-md, 40px);
  max-width: 540px;
}

/* Audio wrapper — narrows the canonical waveform-player to hero proportions. */
.tat-hero__audio {
  margin: 0 auto var(--gap-md, 40px);
  max-width: 560px;
  text-align: left;
}

/* CTA: layout only — geometry/colour/hover come from .btn .btn--fill-up
   in vendor/ui-items/button.css. Do NOT redeclare button styles. */
.tat-hero__cta {
  margin: 0 auto var(--gap-md, 40px);
}

.tat-hero__byline {
  font-family: var(--marbl-font-body, 'Inter', sans-serif);
  font-size: var(--text-sm, 13px);
  line-height: 1.6;
  color: var(--marbl-white-50, rgba(255, 255, 255, 0.5));
  margin: 0 auto;
  max-width: 480px;
}

.tat-hero__byline strong {
  font-weight: var(--font-semibold, 600);
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

.tat-hero__byline-link {
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.15);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease, color 0.15s ease;
}
.tat-hero__byline-link:hover,
.tat-hero__byline-link:focus-visible {
  color: var(--marbl-ember, #F35226);
  text-decoration-color: var(--marbl-ember, #F35226);
  outline: none;
}

/* Static logo (Phase 1 — no GSAP-driven hover stinger).
   Matches the canonical animated logo dimensions from MarblLogo.config: 40x24. */
.marbl-logo-static {
  display: block;
  width: 40px;
  height: 24px;
  fill: var(--marbl-ember, #F35226);
}

@media (prefers-reduced-motion: reduce) {
  .tat-hero__byline-link {
    transition: none;
  }
}

/* === src/assets/css/about.css === */
/* ===================================================================
   Thou Art That — About page
   Article-style typography on top of canonical Marbl chrome.
   Tokens come from marbl-v2.css. Buttons from ui-items/button.css.
   =================================================================== */

.tat-page-main {
  flex: 1;
  display: flex;
  justify-content: center;
  padding: var(--gap-lg, 60px) var(--gap-md, 40px) var(--gap-xl, 80px);
}

.tat-article {
  max-width: 680px;
  width: 100%;
  font-family: var(--marbl-font-body, 'Inter', sans-serif);
  color: var(--marbl-white-90, rgba(255, 255, 255, 0.9));
  line-height: 1.7;
}

.tat-article__eyebrow {
  font-size: var(--text-xs, 11px);
  font-weight: var(--font-semibold, 600);
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--marbl-ember, #F35226);
  line-height: 1;
  margin: 0 0 var(--gap-sm, 20px);
}

.tat-article__title {
  font-family: var(--marbl-font-display, 'Urbanist', sans-serif);
  font-size: clamp(40px, 6vw, 72px);
  font-weight: var(--font-extrabold, 800);
  line-height: 1;
  letter-spacing: -0.03em;
  margin: 0 0 var(--gap-md, 40px);
  color: var(--marbl-white, #ffffff);
}

.tat-article__lede {
  font-size: clamp(17px, 1.6vw, 19px);
  line-height: 1.6;
  color: var(--marbl-white-90, rgba(255, 255, 255, 0.9));
  margin: 0 0 var(--gap-md, 40px);
}

.tat-article__lede em {
  font-family: var(--marbl-font-accent, 'Petrona', Georgia, serif);
  font-style: italic;
  font-weight: 600;
  font-size: 1.05em;
}

.tat-article p {
  font-size: 16px;
  margin: 0 0 var(--space-5, 20px);
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

.tat-article p strong {
  color: var(--marbl-white, #ffffff);
  font-weight: var(--font-semibold, 600);
}

.tat-article__section {
  font-family: var(--marbl-font-display, 'Urbanist', sans-serif);
  font-size: clamp(22px, 2.4vw, 28px);
  font-weight: var(--font-bold, 700);
  letter-spacing: -0.01em;
  color: var(--marbl-white, #ffffff);
  margin: var(--gap-md, 40px) 0 var(--space-4, 16px);
  padding-top: var(--gap-sm, 20px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.tat-article ul {
  margin: 0 0 var(--space-5, 20px);
  padding-left: var(--gap-sm, 20px);
}

.tat-article ul li {
  font-size: 16px;
  margin-bottom: var(--space-3, 12px);
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

.tat-article ul li strong {
  color: var(--marbl-white, #ffffff);
  font-weight: var(--font-semibold, 600);
}

.tat-article__note {
  margin-top: var(--gap-md, 40px);
  padding: var(--space-4, 16px) var(--space-5, 20px);
  border-left: 2px solid var(--marbl-ember, #F35226);
  background: rgba(243, 82, 38, 0.04);
  border-radius: 0 var(--radius, 10px) var(--radius, 10px) 0;
  font-size: 14px;
  color: var(--marbl-white-70, rgba(255, 255, 255, 0.7));
}

.tat-article__cta-row {
  margin-top: var(--gap-lg, 60px);
  display: flex;
  justify-content: flex-start;
  align-items: center;
}

/* === src/assets/css/kh-content.css === */
/* ===================================================================
   Thou Art That — KH content overlay
   TAT-specific tweaks on top of canonical knowledge-hub.css.
   Tokens come from marbl-v2.css. Don't redeclare KH internals.
   =================================================================== */

/* Home icon override:
   1. Pin width/height (canonical .btn-icon--mini svg rule was being
      overridden inside the bundle - computed width collapsed to 1.5px).
   2. Canonical .btn-icon svg uses fill:none + stroke: currentColor
      (designed for outline-style arrows). The home path is a closed
      house shape that renders as a thin barely-visible outline with
      that treatment. Switch this specific icon to filled rendering. */
.kh-sidebar__home-icon {
  width: var(--text-lg, 18px) !important;
  height: var(--text-lg, 18px) !important;
  fill: currentColor !important;
  stroke: none !important;
  flex-shrink: 0;
}

/* Audio first-child margin now lives in canonical knowledge-hub.css
   (promoted from TAT-local 30 Apr 2026). */

/* Source markdown sometimes carries a leading blockquote with the audio
   reference (e.g., do-no-harm.md). When build.mjs strips that block we
   may end up with an opening empty <blockquote>; hide just-in-case. */
.kh-article__body > blockquote:empty {
  display: none;
}

/* Skip-link visibility (canonical Marbl pattern, mirrors landing.css). */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--marbl-ember, #F35226);
  color: var(--marbl-charcoal, #131112);
  padding: var(--gap-xs, 12px) var(--gap-sm, 20px);
  text-decoration: none;
  border-radius: 0 0 var(--radius, 10px) 0;
  font-family: var(--marbl-font-body, 'Inter', sans-serif);
  font-weight: var(--font-semibold, 600);
  z-index: 100;
}
.skip-link:focus {
  left: 0;
  outline: 2px solid var(--marbl-white, #fff);
  outline-offset: 2px;
}

/* When the burger menu opens, .site-header gets .menu-is-open and goes
   position:fixed (canonical pin behaviour, see site-header.md §4). That
   removes ~90px of flow space and the centred shell jumps up. Hold the
   space here while the menu is open. Mirrors landing.css. */
body:has(.site-header.menu-is-open) {
  padding-top: 90px;
}

/* View transitions are NOT applied at the kh-content layer.
   Only the landing + origin-story pages opt in (landing.css + an
   inline opt-in injected by build.mjs into origin-story specifically),
   so navigation between study pages stays instant per Richard's call
   29 Apr 2026. */

/* Audio fallback delayed-reveal now lives in canonical
   waveform-player.css (promoted from TAT-local 29 Apr 2026). */

/* Right rail subscribe CTA - sits below the TOC card, inside .kh-rail
   stack. Full-width inside the rail column so it reads as a deliberate
   action below the chapter list. */
.kh-rail__cta {
  display: flex;
  width: 100%;
  justify-content: center;
}


/* About page - "Who wrote it" Richard block: avatar floats LEFT, text
   flows around it with 20px gap. Mobile drops float and stacks. */
.about-author__avatar {
  float: left;
  margin: 0 var(--gap-sm, 20px) var(--gap-xs, 10px) 0;
  padding: 0;
}

.about-author__avatar img {
  display: block;
  width: 160px;
  height: 160px;
  object-fit: cover;
  border-radius: var(--radius, 10px);
  border: 1px solid var(--marbl-white-08, rgba(255, 255, 255, 0.08));
}

/* Clear float so the next H2 (What we believe) doesn't wrap around it. */
.about-author__clear {
  clear: both;
}

@media (max-width: 600px) {
  .about-author__avatar {
    float: none;
    margin: 0 0 var(--gap-sm, 20px) 0;
  }
  .about-author__avatar img {
    width: 120px;
    height: 120px;
  }
}

/* Right-column rail wraps the TOC + source-repo card into a single
   grid-column-3 cell, stacked vertically. Sticky like the left sidebar
   so the rail stays visible while the article scrolls. Internal scroll
   if the rail itself outgrows the viewport. */
.kh-rail {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: var(--gap-sm, 20px);
  font-size: var(--text-sm, 13px);
  position: sticky;
  top: var(--gap-md, 40px);
  align-self: start;
  max-height: calc(100dvh - var(--gap-md, 40px) * 2);
  overflow-y: auto;
  /* Match the .kh-sidebar / .kh-toc canonical scrollbar - thin grey
     subtle, not the page-level ember bar. */
  scrollbar-width: thin;
  scrollbar-color: var(--marbl-white-15, rgba(255, 255, 255, 0.15)) transparent;
}
.kh-rail::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.kh-rail::-webkit-scrollbar-track { background: transparent; }
.kh-rail::-webkit-scrollbar-thumb {
  background: var(--marbl-white-15, rgba(255, 255, 255, 0.15));
  border-radius: var(--radius-sm, 5px);
}
.kh-rail::-webkit-scrollbar-thumb:hover {
  background: var(--marbl-white-30, rgba(255, 255, 255, 0.3));
}

/* Canonical .kh-toc has its own position: sticky + max-height. With the
   rail wrapper now doing the sticky work, the inner sticky reserves
   max-height inside the rail and pushes the source card down. Neutralise
   the inner sticky locally so .kh-toc takes its natural height inside
   the flex column and the source card sits flush below it. */
.kh-rail .kh-toc {
  position: static;
  max-height: none;
  overflow-y: visible;
}

@media (max-width: 1023px) {
  .kh-rail { display: none; }
}

/* Source repo card sits below the article body on every page - full
   width inside the article column, above pagination. */
.kh-source {
  display: block;
  margin-top: var(--gap-lg, 60px);
}

/* Mobile rhythm overrides — text section breaks at 40px (was 80px on
   desktop), pagination top spacing matches the 20px below it visually
   instead of overshooting. */
@media (max-width: 768px) {
  .kh-article__body h2 {
    margin-top: var(--gap-md, 40px);
  }
  .kh-pagination {
    margin-top: var(--gap-sm, 20px);
    padding-top: var(--gap-sm, 20px);
  }
}

