/* Shared landing chrome styles (IMP-074 L0-L3).
 * Contains only rules whose text is byte-identical across every inline
 * <style> block that uses them today (homepage, docs, blog, 404). Each
 * page still links this file before its own inline <style>, so nothing
 * here should ever conflict with what a page overrides locally.
 * Do not add a rule here unless it is confirmed identical everywhere it
 * is used -- see docs/implementation-plans/IMP-074-hubconnector-navigation-redesign.md.
 * Every color below is a var(--...) token, never a new hex literal -- L4
 * adds a dark-mode override for these tokens and must not need to touch
 * any rule that uses them.
 */

/* Global [hidden] guard. Several chrome elements below (.nav-panel,
 * .nav-drawer, .nav-drawer-panel) are toggled purely via the `hidden`
 * attribute in nav.js, not a class. Without this, a same-specificity
 * `display` rule further down (e.g. .nav-drawer-panel's `display: flex`)
 * wins the cascade over the UA default `[hidden] { display: none }`
 * because author styles always beat user-agent styles regardless of
 * specificity -- leaving the element visible while `hidden` is set and
 * aria-expanded is false. Nothing in landing/ relies on showing an element
 * that also carries `hidden`, so this guard is safe globally.
 */
[hidden] { display: none !important; }

:root {
  color-scheme: light;

  --navy: #0F172A;
  --teal: #0EA5E9;
  --teal-dark: #0284C7;
  --teal-light: #E0F2FE;
  --slate: #475569;
  --grey-900: #111827;
  --grey-500: #6B7280;
  --grey-200: #E5E7EB;
  --grey-50: #F9FAFB;
  --white: #FFFFFF;
  --success: #10B981;
  --warning: #F59E0B;
  --error: #EF4444;

  --bg-primary: var(--white);
  --bg-secondary: var(--grey-50);
  /* Elevated/active surface (hover, active menu item, featured panel).
   * Same value as --bg-secondary in light (no visual change there) --
   * L4 gives it a lighter, distinct dark value so hover/active state reads
   * as "raised" rather than "recessed" on a dark background. */
  --bg-raised: var(--grey-50);
  --bg-dark: var(--navy);
  --text-heading: var(--navy);
  --text-body: var(--slate);
  --text-muted: var(--grey-500);
  --text-on-dark: #F1F5F9;
  --text-muted-on-dark: #94A3B8;
  --border: var(--grey-200);
  --card-bg: var(--white);
  --card-shadow: 0 1px 3px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04);
  --card-shadow-hover: 0 4px 12px rgba(15,23,42,0.08), 0 2px 4px rgba(15,23,42,0.04);
  --stat-bg: var(--white);

  /* Low-opacity tint backgrounds (docs callout, blog blockquote/callout).
   * Kept as separate tokens from --teal-light/--warning because their
   * light values are the page's existing 4-6% literal tints, not the
   * opaque --teal-light chip color -- L4 must not change that look. */
  --teal-soft: rgba(14, 165, 233, 0.04);
  --warn-soft: rgba(245, 158, 11, 0.06);

  /* Always-light success message (waitlist form on a white/card section). */
  --success-bg: #ECFDF5;
  --success-border: #A7F3D0;
  --success-text: #065F46;

  /* Hover-state link text. Same value as --teal-dark in light (no visual
   * change there) -- kept separate from --teal-dark itself because that
   * token is also used as a BACKGROUND (.btn-on-dark:hover), which must
   * stay constant across themes; only the as-TEXT role fails AA on dark. */
  --link-hover: var(--teal-dark);

  --focus-ring: var(--teal);

  /* Decorative shadows -- not contrast-relevant, but a navy-tinted shadow
   * is invisible on a dark background, so these get a dark override too. */
  --shadow-soft: 0 2px 8px rgba(15,23,42,0.08);
  --shadow-lift: 0 8px 24px rgba(0,0,0,0.12);

  /* .cta-section is always navy in both themes (IMP-074 L4) -- these
   * on-navy input/success/error colors are therefore theme-independent
   * and never overridden in the dark blocks below. */
  --input-bg-on-dark: rgba(255,255,255,0.08);
  --input-border-on-dark: rgba(255,255,255,0.15);
  --success-bg-on-dark: rgba(16,185,129,0.15);
  --success-border-on-dark: rgba(16,185,129,0.3);
  --success-text-on-dark: #6EE7B7;
  --error-text-on-dark: #FCA5A5;
}

/* IMP-074 L4 dark theme. Defined twice by design (the house pattern):
 * the @media block is the no-JS/OS-only fallback, the [data-theme="dark"]
 * block is what the inline no-flash script (hc:theme region) sets before
 * first paint. Tokens not redefined here (--navy, --teal, --teal-dark as a
 * background, --white, --error, --success, --warning, --text-on-dark,
 * --text-muted-on-dark, the *-on-dark tokens above) already pass contrast
 * unchanged and are intentionally left alone -- see IMP-074 L4 RETURN for
 * the full contrast table. Light-mode values above are byte-identical to
 * what shipped before L4; nothing in this file changes light mode.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg-primary: #111A2E;
    --bg-secondary: #0E1627;
    --bg-raised: #16223A;
    --text-heading: #E6ECF4;
    --text-body: #C7D2E0;
    --text-muted: #A0AEC2;
    --border: #1F2B42;
    --card-bg: #111A2E;
    --stat-bg: #111A2E;
    --teal-light: #0B2C40;
    --teal-soft: #0B2C40;
    --warn-soft: #3A2A08;
    --link-hover: #38BDF8;
    --shadow-soft: 0 2px 8px rgba(0,0,0,0.45);
    --shadow-lift: 0 8px 24px rgba(0,0,0,0.5);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg-primary: #111A2E;
  --bg-secondary: #0E1627;
  --bg-raised: #16223A;
  --text-heading: #E6ECF4;
  --text-body: #C7D2E0;
  --text-muted: #A0AEC2;
  --border: #1F2B42;
  --card-bg: #111A2E;
  --stat-bg: #111A2E;
  --teal-light: #0B2C40;
  --teal-soft: #0B2C40;
  --warn-soft: #3A2A08;
  --link-hover: #38BDF8;
  --shadow-soft: 0 2px 8px rgba(0,0,0,0.45);
  --shadow-lift: 0 8px 24px rgba(0,0,0,0.5);
}

.wrap { max-width: 1120px; margin: 0 auto; padding: 0 1.5rem; }

.skip-link {
  position: absolute;
  top: 0;
  left: -9999px;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--teal);
  color: var(--white);
  font-size: 0.9375rem;
  font-weight: 600;
  border-radius: 0 0 6px 0;
}
.skip-link:focus {
  left: 0;
  color: var(--white);
}

.eyebrow {
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 0.75rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.75rem 1.5rem;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  transition: background 0.15s, box-shadow 0.15s, transform 0.1s;
  white-space: nowrap;
}
.btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--teal);
  color: var(--white);
  transition: all 0.2s ease;
}
.btn-primary:hover {
  background: var(--teal-dark);
  transform: scale(1.03);
  box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3);
}

/* -- Nav -- */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(8px);
}
.nav.scrolled { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 64px;
}
.nav-brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  flex-shrink: 0;
}
.nav-brand img {
  width: 36px;
  height: 36px;
  border-radius: 6px;
}
/* Brand mark logo swap (IMP-074 L4). The mark's navy paths are invisible
 * on a dark nav background, so the header (hc:header region) renders two
 * <img>s -- .nav-brand-mark-dark is generated from the same source SVG in
 * scripts/landing/sync_chrome.py with only the navy fill swapped, so the
 * two can never drift apart. CSS-only toggle, no JS -- same dual pattern
 * as the rest of the dark theme. */
.nav-brand-mark-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .nav-brand-mark-light { display: none; }
  :root:not([data-theme="light"]) .nav-brand-mark-dark { display: block; }
}
:root[data-theme="dark"] .nav-brand-mark-light { display: none; }
:root[data-theme="dark"] .nav-brand-mark-dark { display: block; }
.wordmark {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1;
}
.wordmark-hub { color: var(--text-heading); }
.wordmark-connector { color: var(--teal); }

/* -- Nav: desktop disclosure menus (IMP-074 L1) -- */
.nav-menus {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  flex: 1;
  justify-content: center;
  min-width: 0;
}
.nav-menu { position: static; }
.nav-menu-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-body);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem 0.125rem;
  transition: color 0.15s;
}
.nav-menu-trigger::after {
  content: '';
  width: 0.375em;
  height: 0.375em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform 0.15s;
}
.nav-menu-trigger:hover,
.nav-menu-trigger[aria-expanded="true"] { color: var(--text-heading); }
.nav-menu-trigger[aria-expanded="true"]::after { transform: rotate(225deg) translateY(2px); }
.nav-menu-trigger.active { color: var(--teal); font-weight: 600; }

.nav-plain-link {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-body);
  transition: color 0.15s;
  white-space: nowrap;
}
.nav-plain-link:hover { color: var(--text-heading); }

.nav-panel {
  position: absolute;
  top: 64px;
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  box-shadow: 0 12px 24px rgba(15,23,42,0.1);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.16s ease, transform 0.16s ease;
  pointer-events: none;
}
.nav-panel.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.nav-panel-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 1.75rem 1.5rem 2rem;
  display: grid;
  gap: 2rem;
}
/* Column count follows content (an intro column, a group per heading, a
 * featured card) -- never forced to a fixed number. See IMP-074 L1. */
.nav-panel-cols-1 { grid-template-columns: minmax(180px, 1fr); }
.nav-panel-cols-2 { grid-template-columns: repeat(2, minmax(180px, 1fr)); }
.nav-panel-cols-3 { grid-template-columns: repeat(3, minmax(180px, 1fr)); }
.nav-panel-cols-4 { grid-template-columns: repeat(4, minmax(160px, 1fr)); }
.nav-panel-intro p {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text-heading);
  margin-bottom: 0.625rem;
}
.nav-panel-intro-link {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--teal);
}
.nav-panel-intro-link:hover { color: var(--link-hover); }
.nav-panel-group { display: flex; flex-direction: column; }
.nav-group-heading {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.625rem;
}
.nav-panel-link {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  padding: 0.5rem 0.625rem;
  margin: 0 -0.625rem;
  border-radius: 8px;
  transition: background 0.15s;
}
.nav-panel-link:hover,
.nav-panel-link:focus-visible { background: var(--bg-raised); }
.nav-link-label {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-heading);
}
.nav-link-desc {
  font-size: 0.8125rem;
  color: var(--text-muted);
}
.nav-panel-link[aria-current="page"] .nav-link-label,
.nav-panel-link[aria-current="page"] { color: var(--teal); }
.nav-panel-featured {
  background: var(--bg-raised);
  border-radius: 10px;
}
/* The padding lives on the link itself, not the wrapping div, so the link
 * fills the whole visible card (IMP-074 F3) -- otherwise a click inside
 * the padding area (e.g. the gap around the eyebrow/title) lands on the
 * wrapper, not the link, and looks like a dead click. The wrapper is a
 * grid cell in .nav-panel-inner and stretches to match its row's tallest
 * sibling column (grid's default align-items: stretch), so it is usually
 * taller than the link's own content -- height: 100% (with border-box, so
 * the padding is included rather than added on top) makes the link match
 * that stretched height instead of leaving a dead unclickable strip of
 * the wrapper's background below it. Visual result is identical: the
 * wrapper has no background of its own visible outside the card, so a
 * taller card box paints the same pixels as the wrapper alone did. */
.nav-featured-card {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 1.125rem;
  height: 100%;
  box-sizing: border-box;
}
.nav-featured-eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--teal);
}
.nav-featured-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-heading);
}

/* Right-hand actions: the waitlist CTA, the theme switch, and (phone only)
 * the hamburger, grouped in their own flex row so they stay snug against
 * each other and the right edge regardless of which of the three is
 * hidden at a given breakpoint -- see the no-JS fallback note below. */
.nav-actions { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; }

.nav-cta { flex-shrink: 0; }

/* -- Nav: theme switch --
 * Hidden by default (like .nav-hamburger below): the button does nothing
 * without nav.js -- no fallback link exists for it -- so a dead control is
 * worse than none. `html.js .nav-theme` (unlike the hamburger's own rule)
 * is not scoped to a max-width media query: the switch is visible at every
 * width, next to the hamburger on phones and next to Log in on desktop. */
.nav-theme { position: relative; display: none; }
html.js .nav-theme { display: flex; align-items: center; }

.nav-theme-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--text-body);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.nav-theme-btn:hover,
.nav-theme-btn[aria-expanded="true"] { background: var(--bg-raised); color: var(--text-heading); }
.nav-theme-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.nav-theme-btn svg { display: none; }
/* The button icon shows the RESOLVED theme currently on screen -- sun when
 * html[data-theme] is (or resolves to) light, moon when dark -- not the
 * raw "system"/"light"/"dark" preference, so it reads as "here's the theme
 * you're looking at" rather than an abstract setting name (the preference
 * itself is still chosen via the popover options below, each labelled with
 * its own icon). Keyed off html[data-theme], not a button attribute: the
 * pre-paint <!-- hc:theme --> script (sync_chrome.py THEME_TEMPLATE) sets
 * this on <html> before first paint, so the correct icon already shows
 * there -- keying off the button instead would default to one icon until
 * nav.js's deferred script ran, briefly showing the wrong icon (IMP-074
 * F5). nav.js's applyTheme() keeps data-theme current afterwards,
 * including on an OS-level change while the preference is "system". With
 * no data-theme at all (JS disabled, so nav.js never runs and the
 * pre-paint script -- itself inline JS -- never sets it either), this
 * falls back to prefers-color-scheme, matching that script's own
 * fallback. */
.nav-theme-btn .nav-theme-icon-light { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .nav-theme-btn .nav-theme-icon-light { display: none; }
  :root:not([data-theme="light"]) .nav-theme-btn .nav-theme-icon-dark { display: block; }
}
:root[data-theme="dark"] .nav-theme-btn .nav-theme-icon-light { display: none; }
:root[data-theme="dark"] .nav-theme-btn .nav-theme-icon-dark { display: block; }

.nav-theme-popover {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 110;
  min-width: 200px;
  max-width: calc(100vw - 2rem);
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 24px rgba(15,23,42,0.1);
  padding: 0.375rem;
}
.nav-theme-options { display: flex; gap: 0.25rem; }
.nav-theme-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  flex: 1;
  font-family: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-body);
  background: none;
  border: none;
  border-radius: 8px;
  padding: 0.5rem 0.375rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.nav-theme-option:hover { background: var(--bg-raised); color: var(--text-heading); }
/* --text-heading, not --link-hover, for the text role in light mode:
 * --link-hover there is --teal-dark (#0284C7) on --teal-light (#E0F2FE) =
 * 3.57:1, failing AA for this 13px/600-weight text. --text-heading (navy
 * #0F172A) on the same background is 15.55:1. Dark mode keeps --link-hover
 * (#38BDF8 on --teal-light's dark override #0B2C40 = 6.77:1, already
 * passing) via the same @media/[data-theme] override pair used for the
 * other theme-dependent tokens above. */
.nav-theme-option[aria-checked="true"] { background: var(--teal-light); color: var(--text-heading); font-weight: 600; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .nav-theme-option[aria-checked="true"] { color: var(--link-hover); }
}
:root[data-theme="dark"] .nav-theme-option[aria-checked="true"] { color: var(--link-hover); }
.nav-theme-option:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .nav-theme-btn, .nav-theme-option { transition: none; }
}

.nav-hamburger {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
  margin-right: -0.5rem;
}
.nav-hamburger svg { display: block; }

/* -- Nav: phone drawer (below 900px, IMP-074 L1) -- */
.nav-drawer {
  position: absolute;
  top: 64px;
  left: 0;
  right: 0;
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  box-shadow: 0 12px 24px rgba(15,23,42,0.1);
  max-height: calc(100vh - 64px);
  overflow-y: auto;
}
.nav-drawer-inner {
  display: flex;
  flex-direction: column;
  padding: 0.5rem 1.5rem 1.5rem;
}
.nav-drawer-accordion { display: flex; flex-direction: column; }
.nav-drawer-item { border-bottom: 1px solid var(--border); }
.nav-drawer-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-body);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.875rem 0;
}
.nav-drawer-trigger.active { color: var(--teal); font-weight: 600; }
.nav-drawer-trigger::after {
  content: '';
  flex-shrink: 0;
  width: 0.4em;
  height: 0.4em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.15s;
}
.nav-drawer-trigger[aria-expanded="true"]::after { transform: rotate(225deg); }
.nav-drawer-panel {
  display: flex;
  flex-direction: column;
  padding: 0 0 1rem 0.25rem;
}
.nav-drawer-heading {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0.75rem 0 0.375rem;
}
.nav-drawer-panel a {
  font-size: 0.9375rem;
  color: var(--text-body);
  padding: 0.5rem 0;
}
.nav-drawer-panel a[aria-current="page"] { color: var(--teal); font-weight: 600; }
.nav-drawer-link {
  display: block;
  font-size: 1rem;
  font-weight: 500;
  color: var(--text-body);
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--border);
}
.nav-drawer-cta { margin-top: 1rem; width: 100%; }

@media (min-width: 900px) {
  .nav-drawer { display: none !important; }
}
/* Below 900px, the hamburger/drawer layout only applies once nav.js has
 * run (it adds `.js` to <html> as the first thing in the header region --
 * see sync_chrome.py HEADER_TEMPLATE). Without JS these selectors would
 * otherwise hide every header link with no working replacement, since the
 * hamburger has no click handler and the drawer never opens -- IMP-074 F4. */
@media (max-width: 899px) {
  html.js .nav-menus,
  html.js .nav-plain-link,
  html.js .nav-cta { display: none; }
  html.js .nav-hamburger { display: block; }

  /* No-JS fallback: the disclosure menus, Pricing, Log in and the waitlist
   * button all stay visible (the menu buttons are inert without nav.js,
   * but every link they would reveal is also in the footer), so let the
   * header wrap onto multiple lines instead of clipping at the fixed
   * 64px .nav-inner height built for the single-row JS layout. */
  html:not(.js) .nav-inner {
    height: auto;
    flex-wrap: wrap;
    /* padding-top/-bottom only (IMP-074 F6) -- .nav-inner shares its
     * element with .wrap, whose `padding: 0 1.5rem` supplies the side
     * gutter; a `padding: 0.75rem 0` shorthand here would win on
     * specificity and zero that gutter out with JS off. */
    padding-top: 0.75rem;
    padding-bottom: 0.75rem;
  }
  html:not(.js) .nav-menus {
    flex: 1 1 100%;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 1rem;
    order: 3;
  }
  html:not(.js) .nav-actions { order: 2; }
}

/* ── Footer (IMP-074 L3: grouped columns, unified across page families) ── */
.footer {
  background: var(--navy);
  border-top: 1px solid rgba(255,255,255,0.06);
  padding: 3rem 0 2rem;
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(200px, 1.4fr) repeat(4, minmax(120px, 1fr));
  gap: 2rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.footer-brand { display: flex; flex-direction: column; gap: 0.75rem; }
.footer-brand .wordmark-hub { color: var(--text-on-dark); }
.footer-tagline {
  font-size: 0.8125rem;
  color: var(--text-muted-on-dark);
  max-width: 220px;
}
.footer-col { display: flex; flex-direction: column; gap: 0.625rem; }
.footer-col-heading {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted-on-dark);
  margin-bottom: 0.125rem;
}
.footer-col a {
  font-size: 0.8125rem;
  color: var(--text-muted-on-dark);
  transition: color 0.15s;
}
.footer-col a:hover { color: var(--teal); }
/* A grouped column (IMP-074 F4b) nests header-panel-style sub-groups, each
 * with its own small heading, instead of one long undifferentiated list. */
.footer-col-group { display: flex; flex-direction: column; gap: 0.625rem; }
.footer-col-group:not(:first-child) { margin-top: 0.625rem; }
.footer-col-subheading {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted-on-dark);
  opacity: 0.75;
}
.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-top: 1.5rem;
}
.footer-copy {
  font-size: 0.8125rem;
  color: var(--text-muted-on-dark);
}
.footer-legal { display: flex; gap: 1.25rem; }
.footer-legal a {
  font-size: 0.8125rem;
  color: var(--text-muted-on-dark);
  transition: color 0.15s;
}
.footer-legal a:hover { color: var(--teal); }

@media (max-width: 900px) {
  .footer-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-brand { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
}

/* -- Docs sidebar (IMP-074 L2) -- */
.docs-layout { display: block; }
/* Each docs page nests .wrap -> .docs-article -> .docs-page -> .wrap
 * (IMP-074 F2): the outer .wrap already supplies the page's side gutter,
 * so the inner one doubles it (48px instead of 24px at 390px) and its
 * max-width does nothing useful once .docs-article is already narrower
 * than 1120px inside the >=1024px grid. Zero it out here instead of
 * hand-editing all 13 docs pages. */
.docs-article .wrap { padding-left: 0; padding-right: 0; max-width: none; }
.docs-sidebar { margin-bottom: 1.5rem; }
.docs-sidenav {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-secondary);
}
.docs-sidenav-summary {
  cursor: pointer;
  list-style: none;
  padding: 0.875rem 1.125rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-heading);
}
.docs-sidenav-summary::-webkit-details-marker { display: none; }
.docs-sidenav-summary::before {
  content: '\25B8';
  display: inline-block;
  margin-right: 0.5rem;
  transition: transform 0.15s;
}
.docs-sidenav[open] > .docs-sidenav-summary::before { transform: rotate(90deg); }
.docs-sidenav-body { padding: 0 1.125rem 1.125rem; }
.docs-sidenav-group { margin-top: 1.125rem; }
.docs-sidenav-group:first-child { margin-top: 0; }
.docs-sidenav-heading {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}
.docs-sidenav-group ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.docs-sidenav-group a { font-size: 0.875rem; color: var(--text-body); }
.docs-sidenav-group a:hover { color: var(--text-heading); }
.docs-sidenav-group a.current {
  color: var(--teal);
  font-weight: 600;
  pointer-events: none;
}

/* The generator emits <details ... open> immediately followed by a
 * synchronous inline <script> (DOCS_NAV_TEMPLATE in sync_chrome.py) that
 * clears the `open` attribute before first paint when the viewport is
 * below 1024px. That script runs during parsing, not after first paint,
 * so the details element's own `open` state -- and therefore the arrow's
 * `[open]` rotation above -- is already correct at first paint on phones,
 * with no CSS override needed here and no dependency on nav.js ever
 * running (R4: the previous `html.js`/`data-ready` CSS gate hid the body
 * unconditionally while `open` stayed true, which showed the open-rotation
 * arrow over collapsed content, and left the sidebar permanently
 * unopenable below 1024px if nav.js failed to load, since toggling `open`
 * did nothing while the gate was in effect). nav.js still keeps `open` in
 * sync with the breakpoint on resize; native <details> toggling (open
 * attribute, no JS at all) works unconditionally at every width. */

@media (min-width: 1024px) {
  .docs-layout {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    gap: 2.5rem;
    align-items: start;
  }
  .docs-sidebar { margin-bottom: 0; }
  .docs-sidenav {
    position: sticky;
    top: 88px;
    border: none;
    background: none;
    border-radius: 0;
  }
  .docs-sidenav-summary { display: none; }
  .docs-sidenav-body { display: block !important; padding: 0; }
}

@media (max-width: 480px) {
  .nav-brand .wordmark { font-size: 1.1rem; }
}
