/* ============================================================================
   Knowledge Portal — Portal v2 rewrite (full file).
   Design source of truth: design-system/design_handoff_doc_portal/README.md
   + the two .dc.html prototypes (exact values). Markup contract:
   server/kb-ssr.ts (+ server/portal-ssr.ts for the ticket-portal shell).

   Theming: the 9-token set (+ accent trio, fixed accents, typography vars)
   is emitted server-side in <style id="kb-theme-vars"> AFTER this
   stylesheet's <link>, so the fallback block below only covers a failed /
   raced theme tag. Light values live on :root, dark on html.dark — every
   component below rides the tokens, so dark mode needs zero per-component
   overrides.

   Raw-hex policy: only the six fixed accents (#ea3f2e #f9ab00 #e59700
   #1aa34a #1b57d6 #1f1f1f), #fff/#ffffff chrome, white/black rgba(), and
   rgba() tints of the fixed accents (status hero/badge washes) are
   allowed outside the fallback token block.
   ========================================================================== */

/* ─── View Transitions opt-in ───────────────────────────────────────────────
   Cross-document navigations between the Knowledge surface and the Support
   portal share the same SSR-emitted header; opting in lets the browser
   crossfade documents, and the named transition on .kb-header morphs the
   header in place instead of flashing it. Firefox no-ops the @rule. */
@view-transition { navigation: auto; }

/* ─── Fallback tokens ───────────────────────────────────────────────────────
   The server's <style id="kb-theme-vars"> loads after this file and wins.
   These are the light defaults (accent = the design's reference blue) so a
   cached page never renders unstyled if the theme tag is missing. */
:root {
  --kb-frame: #1b57d6;
  --kb-cover: #f1f0ec;
  --kb-surface: #ffffff;
  --kb-surface-2: #f5f4f1;
  --kb-pill: #eceae5;
  --kb-text: #1f1f1f;
  --kb-text-2: #3a3a3a;
  --kb-text-3: #5a5a5a;
  --kb-chip: #111111;
  --kb-accent: #1b57d6;
  --kb-accent-ink: #1b57d6;
  --kb-accent-soft: rgba(27, 87, 214, 0.12);
  --kb-red: #ea3f2e;
  --kb-amber: #f9ab00;
  --kb-amber-hover: #e59700;
  --kb-green: #1aa34a;
  --kb-blue: #1b57d6;
  --kb-ink: #1f1f1f;
  --kb-font-family: 'Figtree', system-ui, sans-serif;
  --kb-font-weight: 400;
  --kb-heading-font-family: 'Rubik', 'Figtree', system-ui, sans-serif;
  --kb-heading-font-weight: 500;
  --kb-base-font-size: 16px;
  /* Scroll progress (0..1) — kb.js writes this on <html> on article pages.
     Drives the close-✕ fade-in and the scroll-cue fade-out. */
  --p: 0;
}

/* ─── Reset / base ────────────────────────────────────────────────────────── */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* Theme-swap colour transition — global per the design spec (.28s ease on
   colour-ish properties only, so layout/motion transitions stay per-rule). */
* {
  transition:
    background-color .28s ease,
    color .28s ease,
    border-color .28s ease,
    fill .28s ease,
    stroke .28s ease;
}

html {
  font-size: var(--kb-base-font-size, 16px);
  scroll-behavior: smooth;
}

body {
  background: var(--kb-frame);
  font-family: var(--kb-font-family, 'Figtree', system-ui, sans-serif);
  font-weight: var(--kb-font-weight, 400);
  color: var(--kb-text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--kb-accent-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

button {
  font-family: inherit;
}

/* Overlay scroll lock — the kb.js overlay manager refcounts this class. */
html.kb-scroll-locked,
html.kb-scroll-locked body {
  overflow: hidden;
}

/* Many components below set their own display value — this guard keeps the
   HTML `hidden` attribute authoritative over all of them (assistant empty
   state, feedback thanks, modal states, backdrops…). */
[hidden] {
  display: none !important;
}

/* Accessible focus — never removed. White ring on frame-coloured chrome,
   accent ring on light surfaces. */
:focus-visible {
  outline: 2px solid var(--kb-accent-ink);
  outline-offset: 2px;
}
.kb-header :focus-visible,
.kb-sitenav :focus-visible,
.kb-toc :focus-visible,
.kb-footer :focus-visible,
.kb-scroll-cue:focus-visible,
.kb-close:focus-visible {
  outline-color: #fff;
}

/* ─── Utilities ─────────────────────────────────────────────────────────────
   .kb-pill — the shared eyebrow/pill geometry (r100, 8/16). Composed by the
   eyebrow classes below; also available to tenant custom HTML. */
.kb-pill {
  display: inline-block;
  padding: 8px 16px;
  border-radius: 100px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
}

/* .kb-iconbtn — 40px round translucent-white button on the frame colour
   (theme toggle, hamburger, drawer ✕). Panels/modals re-skin it locally. */
.kb-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: none;
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
}
.kb-iconbtn:hover {
  background: rgba(255, 255, 255, 0.22);
}

/* Keyboard chips. `.kb-kbd-chip` is the free-standing chip (home hero ⌘K,
   search modal Esc); `.kb-pill-shortcut` is the chip inside header pills.
   The ⌘/Ctrl prefix mechanism: chips carrying [data-shortcut] render their
   key via ::after and the platform prefix via ::before — kb.js sets
   html[data-platform="other"] on non-Mac. */
.kb-kbd-chip {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  line-height: 1.4;
  color: var(--kb-text-3);
  background: var(--kb-surface-2);
  border-radius: 6px;
  padding: 3px 7px;
}
.kb-pill-shortcut {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  line-height: 1.4;
  border-radius: 6px;
  padding: 2px 6px;
}
.kb-pill-shortcut::before,
.kb-kbd-chip[data-shortcut]::before {
  content: "⌘";
}
[data-platform="other"] .kb-pill-shortcut::before,
[data-platform="other"] .kb-kbd-chip[data-shortcut]::before {
  content: "Ctrl ";
}
.kb-pill-shortcut::after,
.kb-kbd-chip[data-shortcut]::after {
  content: attr(data-shortcut);
}

/* ─── Header (fixed, 64px, on the frame) ──────────────────────────────────── */
.kb-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 64px;
  z-index: 30;
  /* --kb-header-bg is emitted by the theme tag only when the tenant has
     recoloured the band or made it translucent; otherwise it is the frame
     colour, exactly as before. The blur is not a separate setting — a
     see-through bar over scrolling text is unreadable without one, so any
     band the tenant makes translucent gets it (and `none` costs nothing). */
  background: var(--kb-header-bg, var(--kb-frame));
  backdrop-filter: var(--kb-header-blur, none);
  -webkit-backdrop-filter: var(--kb-header-blur, none);
  /* Stable identity across document navigations — the View Transitions API
     morphs the header between routes rather than fading old/new. */
  view-transition-name: kb-header;
}

.kb-header-inner {
  position: relative;
  height: 100%;
  padding: 0 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.kb-header-cluster {
  display: flex;
  align-items: center;
  min-width: 0;
}
.kb-header-cluster--left { gap: 10px; }
/* Never shrinks below its buttons: the tenant name truncates instead. (It used
   to shrink, and on a 375px phone the Login chip ran 18px off the screen.) */
.kb-header-cluster--right {
  gap: 12px;
  flex: none;
  margin-left: auto;
}

/* Hamburger — hidden ≥1181, square-ish per spec (r10, not round). */
.kb-menu-btn {
  display: none;
  border-radius: 10px;
}

.kb-logo {
  display: flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  min-width: 0;
}
.kb-logo-tile {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
}
.kb-logo-tile img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 3px;
}
.kb-logo-tile--initial {
  font-family: var(--kb-heading-font-family);
  font-weight: 700;
  font-size: 16px;
  color: var(--kb-accent-ink);
}
.kb-logo-name {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.2px;
  color: var(--kb-header-ink, #fff);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Logo size + shape (docs/plans/2026-10-02-portal-logo-sizing-and-dark-logo.md).
   M is the tile above; S and L scale the tile and the name beside it. A wide
   logo ("lockup") is drawn alone at its own shape — the server writes its
   width/height inline from shared/logo-layout.ts, so nothing reflows. */
.kb-logo-tile--sm { width: 28px; height: 28px; border-radius: 8px; }
.kb-logo-tile--lg { width: 38px; height: 38px; border-radius: 10px; }
.kb-logo-name--sm { font-size: 16px; }
.kb-logo-name--lg { font-size: 20px; }
.kb-logo-lockup {
  display: block;
  flex: none;
  object-fit: contain;
}
.kb-login-card .kb-logo-lockup--card {
  height: 44px;
  width: auto;
  max-width: 220px;
  margin: 0 auto;
}
/* A dark-theme logo: both copies are in the page and html.dark (the theme
   toggle's class) picks one. `contents` keeps the art a direct flex child of
   .kb-logo, so its gap and the compact morph rules apply unchanged. */
.kb-logo-art { display: contents; }
.kb-logo-art[data-logo-theme="dark"] { display: none; }
html.dark .kb-logo-art[data-logo-theme="light"] { display: none; }
html.dark .kb-logo-art[data-logo-theme="dark"] { display: contents; }

/* Surface nav — straight after the left cluster (its own element because it is
   one of the liquid nav's islands); hides ≤1180 (moves into the drawer). Keeps
   the old in-cluster spacing of 32px from the logo: the inner row's 12px gap
   plus this 20px. */
.kb-header-nav {
  display: flex;
  align-items: center;
  gap: 30px;
  margin-left: 20px;
}
.kb-header-nav a,
.kb-header-nav-primary {
  position: relative;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 16px;
  color: color-mix(in srgb, var(--kb-header-ink, #fff) 72%, transparent);
  text-decoration: none;
  white-space: nowrap;
}
.kb-header-nav a:hover {
  color: var(--kb-header-ink, #fff);
}
.kb-header-nav a[aria-current="page"] {
  color: var(--kb-header-ink, #fff);
  font-weight: 600;
}

/* "Unseen ticket update" indicator — red dot top-right of the Tickets link.
   Toggled by kb.js setting [data-has-update="true"] after polling
   /api/ticket-portal/.../has-updates. Static under reduced motion. */
.kb-header-nav a[data-has-update="true"]::after {
  content: '';
  position: absolute;
  top: -2px;
  right: -9px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--kb-red);
  box-shadow: 0 0 0 2px var(--kb-frame);
  animation: kb-nav-dot-pulse 1.5s ease-in-out infinite;
}
@keyframes kb-nav-dot-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: 0.4; transform: scale(0.85); }
}

/* Shared toolbar-pill base — translucent 40px pill on the frame. Search,
   language switcher and Ask Assistant all build on this. */
.kb-toolbar-pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 40px;
  padding: 0 12px;
  border-radius: 100px;
  background: color-mix(in srgb, var(--kb-header-ink, #fff) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--kb-header-ink, #fff) 24%, transparent);
  color: var(--kb-header-ink, #fff);
  font-family: var(--kb-font-family);
  font-size: 14px;
  cursor: pointer;
  flex-shrink: 0;
}
.kb-toolbar-pill:hover {
  border-color: color-mix(in srgb, var(--kb-header-ink, #fff) 42%, transparent);
}

/* Search trigger pill — opens the ⌘K modal. Collapses to a 40px round icon
   ≤1340 and in the compact liquid nav (see media queries). */
.kb-search-pill {
  min-width: 184px;
}
.kb-search-pill .kb-pill-icon,
.kb-search-icon {
  width: 16px;
  height: 16px;
  flex: none;
  color: color-mix(in srgb, var(--kb-header-ink, #fff) 70%, transparent);
}
.kb-search-pill .kb-pill-label {
  flex: 1;
  text-align: left;
  font-size: 14px;
  color: color-mix(in srgb, var(--kb-header-ink, #fff) 65%, transparent);
  white-space: nowrap;
  overflow: hidden;
}
.kb-search-pill .kb-pill-shortcut {
  color: color-mix(in srgb, var(--kb-header-ink, #fff) 72%, transparent);
  background: color-mix(in srgb, var(--kb-header-ink, #fff) 16%, transparent);
}

/* Ask Assistant pill — solid white, accent-ink text. Short label ("Ask AI")
   swaps in ≤1340; a round icon ≤820 and in the compact liquid nav. */
.kb-ask-pill {
  background: #fff;
  border: none;
  padding: 0 14px;
  gap: 8px;
}
.kb-ask-pill:hover {
  background: rgba(255, 255, 255, 0.88);
}
.kb-ask-pill .kb-pill-icon {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--kb-accent-ink);
}
.kb-ask-pill .kb-pill-label {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 14px;
  color: var(--kb-accent-ink);
  white-space: nowrap;
}
.kb-ask-label--short {
  display: none;
}
.kb-ask-pill .kb-pill-shortcut {
  color: rgba(0, 0, 0, 0.5);
  background: rgba(0, 0, 0, 0.06);
}

/* Theme toggle — moon shown in light mode (click → dark), sun in dark. */
.kb-theme-toggle .kb-theme-icon-light { display: block; }
.kb-theme-toggle .kb-theme-icon-dark { display: none; }
.dark .kb-theme-toggle .kb-theme-icon-light { display: none; }
.dark .kb-theme-toggle .kb-theme-icon-dark { display: block; }

/* ─── Language switcher (native <details>, JS-free) ─────────────────────────
   The <details> carries .kb-toolbar-pill, so it inherits the translucent
   header-pill skin; this block shapes the summary + anchored menu. */
.kb-lang-switcher {
  position: relative;
  padding: 0;
  overflow: visible;
}
.kb-lang-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 38px;
  padding: 0 12px;
  list-style: none; /* strip the default disclosure triangle (Firefox) */
  cursor: pointer;
  border-radius: 100px;
}
.kb-lang-summary::-webkit-details-marker {
  display: none; /* strip the default disclosure triangle (WebKit) */
}
.kb-lang-flag {
  font-size: 16px;
  line-height: 1;
}
/* CSS-drawn caret — flips when the menu is open. */
.kb-lang-caret {
  width: 7px;
  height: 7px;
  border-right: 1.5px solid rgba(255, 255, 255, 0.8);
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.8);
  transform: rotate(45deg);
  margin-top: -3px;
  transition: transform .15s ease;
}
.kb-lang-switcher[open] .kb-lang-caret {
  transform: rotate(-135deg);
  margin-top: 2px;
}
.kb-lang-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 200px;
  background: var(--kb-surface);
  border: 1px solid var(--kb-pill);
  border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
  padding: 6px;
  z-index: 50;
}
.kb-lang-switcher:not([open]) .kb-lang-menu {
  display: none;
}
.kb-lang-option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  color: var(--kb-text);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
}
.kb-lang-option:hover,
.kb-lang-option:focus-visible {
  background: var(--kb-surface-2);
  outline: none;
}
.kb-lang-option .kb-lang-name {
  flex: 1;
}
.kb-lang-option[aria-current="true"]::after {
  content: "✓";
  color: var(--kb-green);
  font-weight: 700;
}

/* ─── Auth slot (client-rendered by auth-slot.js) ───────────────────────────
   Empty until /me resolves — the SSR is cached tenant-wide and anonymous. */
.kb-auth-slot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  min-height: 40px;
}
.kb-auth-slot:empty {
  display: none;
}

/* Login button — dark chip pill (design's --chip). auth-slot.js renders it
   as .kb-login-btn (modal trigger) with .kb-auth-link kept as the legacy
   anchor-fallback class; both get the same skin. */
.kb-login-btn,
.kb-auth-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 0 22px;
  border-radius: 100px;
  background: var(--kb-chip);
  border: none;
  color: #fff;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.kb-login-btn:hover,
.kb-auth-link:hover {
  box-shadow: inset 0 0 0 99px rgba(255, 255, 255, 0.09);
}
.kb-login-btn:disabled,
.kb-auth-link:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ─── Header style — how the bar sits (appearance_settings.kb_header_style) ──
   Emitted as data-kb-header-style / data-kb-header-sticky on .kb-header by
   generateKBHeader. "bar" is the default and adds nothing, so a tenant who has
   not touched these settings gets byte-identical geometry.

   "bar_rounded" insets the bar from the viewport edges and rounds it, so the
   page background (a colour, or the 0403 image) shows around it.

   "condensed" starts on the liquid nav's compact islands instead of arriving
   there on scroll; the engine reads data-liquid-nav-lock and never morphs.

   Non-sticky pins the header to the top of the DOCUMENT instead of the
   viewport. The 94px top padding the page already carries is what it sits in,
   so nothing below has to move — and the morph is off, because there is
   nothing to morph once the header has scrolled away. */
.kb-header[data-kb-header-style="bar_rounded"] {
  top: 12px;
  left: 16px;
  right: 16px;
  border-radius: 18px;
  /* Deliberately NOT overflow:hidden. border-radius already clips the bar's
     own background, and nothing inside reaches the corners — but the header
     box is only 64px tall, so hiding the overflow sliced the compact islands'
     drop shadow off in a straight line across the page. */
}
/* The rounded bar is an island in its own right: it needs the same lift off the
   page that the compact islands get, or it reads as a mis-drawn full bar. */
.kb-header[data-kb-header-style="bar_rounded"]:not([data-liquid-nav="compact"]):not([data-liquid-nav-morphing]) {
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.18),
    0 2px 6px rgba(0, 0, 0, 0.10);
}
@media (max-width: 560px) {
  .kb-header[data-kb-header-style="bar_rounded"] {
    top: 8px;
    left: 8px;
    right: 8px;
    border-radius: 14px;
  }
}

.kb-header[data-kb-header-sticky="false"] {
  position: absolute;
}

/* ─── Liquid nav — the header once the page scrolls ─────────────────────────
   public/knowledge/liquid-nav.js flips [data-liquid-nav] on .kb-header from
   "expanded" (the bar above) to "compact": the bar pinches into floating
   islands ([data-liquid-nav-island] — logo · links · actions), centred ≥1181
   and pinned to the corners below. While the engine animates
   ([data-liquid-nav-morphing]) the blob layer draws the bar-to-island morph and
   an SVG goo filter joins the blobs. At rest each island paints its own
   background, so late content (auth chip, the injected Projects link, the
   unseen-update dot) resizes it with no JS.
   Plan: docs/plans/2026-09-13-portal-liquid-nav.md. */
.kb-header[data-liquid-nav="compact"],
.kb-header[data-liquid-nav-morphing] {
  background: transparent;
  /* The islands carry their own blur; blurring the full-width strip too would
     frost the empty space around them. */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  /* Clicks and scrolls pass through the empty strip around the islands. */
  pointer-events: none;
}
.kb-header[data-liquid-nav="compact"] [data-liquid-nav-island],
.kb-header[data-liquid-nav-morphing] [data-liquid-nav-island] {
  pointer-events: auto;
}
/* The theme-swap colour transition at the top of this file would fade the bar
   out — and the islands in — over .28s at the exact moments the blobs take over
   and hand back, leaving a ghost bar over the morph. Off while morphing, and
   for the settling frame the engine holds straight after. */
.kb-header[data-liquid-nav-morphing],
.kb-header[data-liquid-nav-settling],
.kb-header[data-liquid-nav-morphing] [data-liquid-nav-island],
.kb-header[data-liquid-nav-settling] [data-liquid-nav-island] {
  transition: none;
}

.kb-liquid-nav-blobs {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.kb-liquid-nav-blobs > span {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  background: var(--kb-header-bg, var(--kb-frame));
  visibility: hidden;
}
.kb-header[data-liquid-nav-morphing] .kb-liquid-nav-blobs > span {
  visibility: visible;
}
/* Set by the engine only while the blobs move — at rest the filter would cost
   a paint for nothing. */
.kb-liquid-nav-blobs[data-gooey] {
  filter: url(#ec-liquid-nav-goo);
}

.kb-header[data-liquid-nav="compact"] .kb-header-inner {
  justify-content: center;
  gap: 14px;
  padding: 0 16px;
}
.kb-header[data-liquid-nav="compact"] [data-liquid-nav-island] {
  flex: none;
  height: 48px;
  border-radius: 100px;
}
/* The faint white rim is what separates a dark frame from a dark page, where
   the shadow disappears; on a light page it reads as a soft edge. */
.kb-header[data-liquid-nav="compact"]:not([data-liquid-nav-morphing]) [data-liquid-nav-island] {
  background: var(--kb-header-bg, var(--kb-frame));
  backdrop-filter: var(--kb-header-blur, none);
  -webkit-backdrop-filter: var(--kb-header-blur, none);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.22),
    0 2px 6px rgba(0, 0, 0, 0.12),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

/* Logo island — the tile alone. The name is made transparent rather than
   removed, so it stays in the accessibility tree as the link's name. It goes
   at once (it would sit over the links as they gather) and fades back in only
   once the islands have spread out again. */
.kb-header[data-liquid-nav="compact"] .kb-header-cluster--left {
  gap: 8px;
  padding: 0 8px;
}
.kb-header[data-liquid-nav="compact"] .kb-logo {
  position: relative;
}
.kb-logo-name {
  transition: opacity .2s ease .2s;
}
.kb-header[data-liquid-nav="compact"] .kb-logo-name {
  position: absolute;
  left: 43px;
  /* tile + .kb-logo's 11px gap */
  opacity: 0;
  pointer-events: none;
  transition: none;
}
.kb-header[data-liquid-nav="compact"] .kb-logo-name--sm { left: 39px; }
.kb-header[data-liquid-nav="compact"] .kb-logo-name--lg { left: 49px; }
.kb-header[data-liquid-nav="compact"] .kb-menu-btn {
  border-radius: 50%;
}

/* Links island — the current page sits in a soft capsule. */
.kb-header[data-liquid-nav="compact"] .kb-header-nav {
  gap: 2px;
  margin-left: 0;
  padding: 0 5px;
}
.kb-header[data-liquid-nav="compact"] .kb-header-nav a {
  padding: 7px 13px;
  border-radius: 100px;
  font-size: 15px;
}
.kb-header[data-liquid-nav="compact"] .kb-header-nav a[aria-current="page"] {
  background: rgba(255, 255, 255, 0.16);
}
.kb-header[data-liquid-nav="compact"] .kb-header-nav a[data-has-update="true"]::after {
  top: 3px;
  right: 5px;
}

/* Actions island — search and the assistant shrink to round icons. */
.kb-header[data-liquid-nav="compact"] .kb-header-cluster--right {
  margin-left: 0;
  gap: 6px;
  padding: 0 4px;
}
.kb-header[data-liquid-nav="compact"] .kb-search-pill,
.kb-header[data-liquid-nav="compact"] .kb-ask-pill {
  min-width: 0;
  width: 40px;
  padding: 0;
  justify-content: center;
  border-radius: 50%;
}
.kb-header[data-liquid-nav="compact"] .kb-search-pill {
  border-color: transparent;
}
.kb-header[data-liquid-nav="compact"] .kb-toolbar-pill .kb-pill-label,
.kb-header[data-liquid-nav="compact"] .kb-toolbar-pill .kb-pill-shortcut {
  display: none;
}

/* ─── Bottom dock — the sections' tab bar on phones ─────────────────────────
   generateKBDock (server/kb-ssr.ts): the portal's sections plus a round button
   for the page's main action (Search, or Subscribe on Status / Changelog).
   liquid-nav.js sets [data-liquid-dock] to "folded" while the visitor scrolls
   down — the capsule shrinks to the current section — and back to "open".
   Shown ≤560 only (the phone block below); the header rules that hand it
   their action live there too. Plan: docs/plans/2026-09-14-portal-bottom-dock.md. */
.kb-dock {
  display: none;
}
.kb-dock :focus-visible {
  outline-color: #fff;
}
.kb-dock-tabs {
  display: flex;
  align-items: center;
  height: 56px;
  padding: 4px;
  border-radius: 100px;
  background: var(--kb-frame);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.22),
    0 2px 6px rgba(0, 0, 0, 0.12),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
.kb-dock-tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 48px;
  min-width: 52px;
  max-width: 96px;
  padding: 0 8px;
  border-radius: 100px;
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  overflow: hidden;
  transition:
    max-width .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    min-width .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    padding .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    opacity .2s ease,
    visibility 0s linear 0s,
    background-color .28s ease,
    color .28s ease;
}
.kb-dock-tab:hover {
  color: #fff;
}
.kb-dock-tab[aria-current="page"] {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
}
.kb-dock-icon {
  width: 20px;
  height: 20px;
  flex: none;
}
.kb-dock-label {
  max-height: 14px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 10.5px;
  line-height: 14px;
  white-space: nowrap;
  transition:
    opacity .2s ease,
    max-height .4s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1));
}
.kb-dock-tab[data-has-update="true"]::after {
  content: '';
  position: absolute;
  top: 6px;
  right: calc(50% - 16px);
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--kb-red);
  box-shadow: 0 0 0 2px var(--kb-frame);
  animation: kb-nav-dot-pulse 1.5s ease-in-out infinite;
}
.kb-dock-action {
  display: grid;
  place-items: center;
  flex: none;
  width: 56px;
  height: 56px;
  border: none;
  border-radius: 50%;
  background: var(--kb-frame);
  color: #fff;
  cursor: pointer;
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.22),
    0 2px 6px rgba(0, 0, 0, 0.12),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
.kb-dock-action:hover {
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.22),
    0 2px 6px rgba(0, 0, 0, 0.12),
    inset 0 0 0 99px rgba(255, 255, 255, 0.1);
}

/* Folded: every tab but the current one collapses, and becomes unfocusable
   once it has (visibility waits for the collapse); the labels go too. */
.kb-dock[data-liquid-dock="folded"] .kb-dock-tab {
  min-width: 48px;
  padding: 0;
}
.kb-dock[data-liquid-dock="folded"] .kb-dock-tab:not([aria-current="page"]) {
  min-width: 0;
  max-width: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    max-width .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    min-width .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    padding .5s var(--ec-liquid-spring, cubic-bezier(.2, .8, .2, 1)),
    opacity .15s ease,
    visibility 0s linear .5s;
}
/* A page no tab is current for folds to the first tab rather than to nothing. */
.kb-dock[data-liquid-dock="folded"] .kb-dock-tabs:not(:has([aria-current="page"])) .kb-dock-tab:first-child {
  min-width: 48px;
  max-width: 96px;
  opacity: 1;
  visibility: visible;
}
.kb-dock[data-liquid-dock="folded"] .kb-dock-label {
  max-height: 0;
  opacity: 0;
}

/* Five or more sections (Courses and Projects can both join the four): the
   labelled tabs no longer fit beside the round button on a 375px phone, so
   only the current tab keeps its label and the rest are icons. The label is
   clipped, not removed, so each tab keeps its accessible name. Open state
   only — the folded rules above own the tab sizes while folded.
   Mirrored in project-portal.css; docs/plans/2026-10-05-learn-portal-appearance.md. */
.kb-dock[data-liquid-dock="open"] .kb-dock-tabs:has(> :nth-child(5 of .kb-dock-tab)) .kb-dock-tab:not([aria-current="page"]) {
  min-width: 44px;
  padding: 0 6px;
}
.kb-dock[data-liquid-dock="open"] .kb-dock-tabs:has(> :nth-child(6 of .kb-dock-tab)) .kb-dock-tab:not([aria-current="page"]) {
  min-width: 38px;
  padding: 0 4px;
}
.kb-dock[data-liquid-dock="open"] .kb-dock-tabs:has(> :nth-child(5 of .kb-dock-tab)) .kb-dock-tab:not([aria-current="page"]) .kb-dock-label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* ─── Site nav — left rail (article pages ≥1181) / drawer (<1181) ───────────
   ONE element serves both roles; CSS transforms it at the breakpoint. The
   `--drawer-only` variant (home / category / portal shell) renders nothing
   at desktop widths. */
.kb-sitenav {
  position: fixed;
  left: 44px;
  top: 84px;
  width: 210px;
  max-height: calc(100vh - 108px);
  overflow-y: auto;
  z-index: 22;
  /* Rail scrollbar would paint over the frame colour — hide it (content
     still scrolls with wheel/touch/keys). */
  scrollbar-width: none;
}
.kb-sitenav::-webkit-scrollbar {
  width: 0;
  height: 0;
}
.kb-sitenav--drawer-only {
  display: none;
}

/* Drawer-only affordances — hidden at desktop widths. */
.kb-drawer-close {
  display: none;
}
.kb-sitenav-surfaces {
  display: none;
}
/* The language switcher, repeated in the drawer for phones (shown ≤560, where
   the header drops it). Its menu opens in place instead of as a dropdown. */
.kb-sitenav-lang {
  display: none;
  margin: 0 0 20px;
}
.kb-sitenav-lang .kb-lang-switcher {
  display: inline-block;
  height: auto;
  vertical-align: top;
}
.kb-sitenav-lang .kb-lang-switcher[open] {
  border-radius: 16px;
  padding-bottom: 6px;
}
.kb-sitenav-lang .kb-lang-menu {
  position: static;
  margin: 4px 6px 0;
  box-shadow: none;
}

.kb-sitenav-label {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  padding-bottom: 6px;
}

.kb-sitenav-tree {
  margin-top: 8px;
}

.kb-category {
  margin-top: 6px;
}
.kb-category-header {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px 0;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  color: #fff;
  text-align: left;
}
/* Truncation belongs to exactly ONE surface: the pinned 210px desktop rail,
   which is the only place this tree is narrow enough to need it. Everywhere
   else it renders in a 300px panel — the collapsed peek and the ≤1180 drawer —
   where a wrapped title is simply the title. Truncating here instead reached
   all three, which is why "Mobile App / Stock Mana…" was the best a phone
   could do. The narrow case is re-added in the collapsible-nav section. */
.kb-category-title {
  flex: 1;
  min-width: 0;
}
.kb-category-icon {
  width: 14px;
  height: 14px;
  flex: none;
  color: rgba(255, 255, 255, 0.75);
  transform: rotate(0deg);
  transition: transform .25s ease;
}
.kb-category.collapsed .kb-category-icon {
  transform: rotate(-90deg);
}

/* Collapse animation contract: the open state is max-height:none via CSS;
   kb.js animates with inline max-height (scrollHeight → 0 / 0 → scrollHeight
   → cleared) so restores from localStorage don't animate. */
.kb-category-content {
  overflow: hidden;
  max-height: none;
  transition: max-height .32s ease;
}
.kb-category.collapsed .kb-category-content {
  max-height: 0;
}

.kb-article-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-left: 7px;
  padding-left: 16px;
  border-left: 2px solid rgba(255, 255, 255, 0.22);
}
.kb-article-link {
  display: block;
  font-size: 14.5px;
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  padding: 7px 0;
}
.kb-article-link:hover {
  color: #fff;
}
/* Active article — white pill, accent-ink text (guarded ≥4.5:1 on white). */
.kb-article-link.active {
  font-weight: 600;
  color: var(--kb-accent-ink);
  background: #fff;
  border-radius: 8px;
  padding: 7px 10px;
  margin-left: -11px;
}

/* Surface links duplicated at the top of the drawer (<1181 only). */
.kb-sitenav-surface {
  display: block;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 16px;
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  padding: 6px 0;
}
.kb-sitenav-surface:hover {
  color: #fff;
}
.kb-sitenav-surface.is-current {
  color: #fff;
  font-weight: 600;
}

/* Drawer backdrop — z 55 sits between the header (30) and the drawer (60). */
.kb-drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease;
  z-index: 55;
}
.kb-drawer-backdrop[hidden] {
  display: none;
}
html.kb-drawer-open .kb-drawer-backdrop {
  opacity: 1;
  pointer-events: auto;
}

/* ─── Article — cover + content sheet (scroll reveal) ───────────────────────
   The cover pins full-viewport; the sheet overlaps it (negative margin) and
   scrolls up over it. kb.js writes --p (scroll progress) on <html> and
   toggles html.kb-scrolled at p > 0.25, which gates pointer-events on the
   close-✕ / scroll cue so the invisible one is never clickable. */
.kb-flow {
  position: relative;
  z-index: 1;
  padding-top: 94px;
}

/* Bounds the cover's sticky range to cover + sheet (+ the sheet's 40px
   bottom margin). display:flow-root makes this a BFC root so the sheet's
   bottom margin is contained (counts into the auto height) instead of
   collapsing through — the cover's sticky clamp is this box's content
   bottom, so the pinned cover unpins at the end of the article and its
   rounded bottom edge comes to rest 40px below the sheet: the cream pane
   visibly wraps around the content panel. flow-root (unlike overflow:
   hidden) does NOT create a scroll container, so position:sticky keeps
   tracking the viewport. */
.kb-reveal {
  display: flow-root;
  /* The reveal wrapper IS the cream pane: it spans the cover content, the
     whole sheet, and the 40px wrap band below it — so the cream flanks the
     sheet all the way down and wraps its bottom, regardless of how tall
     the cover content is. */
  width: min(1080px, calc(100% - 520px));
  margin: 0 auto;
  background: var(--kb-cover);
  border-radius: 30px;
}

/* Content-sized sticky layer inside the pane: exactly as tall as the
   eyebrow / title / TL;DR / cover art (+ grid padding). Same cream as the
   reveal wrapper, so while it's pinned it slides invisibly within the
   pane — only its content (the title block) reads as pinned while the
   sheet scrolls up over it. */
.kb-cover {
  position: sticky;
  top: 72px;
  width: 100%;
  background: var(--kb-cover);
  border-radius: 30px;
  overflow: hidden;
  z-index: 1;
}

/* Flex, not grid — the illustration owns its own column and can never
   overflow into the headline. */
.kb-cover-grid {
  display: flex;
  align-items: stretch;
  gap: 44px;
  /* Bottom padding = 64px of visible cream below the content + the 40px
     the sheet tucks over the pane's bottom edge (.kb-sheet margin-top). */
  padding: 84px 64px 104px 84px;
}
.kb-cover-col {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.kb-cover-eyebrow {
  display: inline-block;
  align-self: flex-start;
  background: var(--kb-accent);
  color: #fff;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  padding: 8px 16px;
  border-radius: 100px;
}
.kb-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 56px;
  line-height: 1.1;
  letter-spacing: -1.5px;
  color: var(--kb-text);
  margin: 24px 0 0;
}
.kb-cover-summary {
  margin-top: 36px;
  /* Narrow measure only while sharing the row with the cover art. */
  max-width: 380px;
}
/* No cover image → the SSR omits the media column entirely, leaving the
   text column as the grid's only child — let the TL;DR run the full
   width of the panel. */
.kb-cover-col:only-child .kb-cover-summary {
  max-width: none;
}
.kb-cover-summary-label {
  font-family: var(--kb-heading-font-family);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.3px;
  color: var(--kb-red);
}
.kb-cover-summary p {
  /* Match the article body's reading rhythm (same body font, comfortable
     measure + line-height) so the TL;DR reads like the prose in the editor,
     just as a summary rather than a cramped caption. */
  font-family: var(--kb-font-family);
  font-size: 16px;
  line-height: 1.65;
  color: var(--kb-text-2);
  max-width: 680px;
  margin: 16px 0 0;
}
.kb-cover-media {
  flex: 0 0 280px;
  width: 280px;
  /* Top-aligned with the eyebrow/title column; the ≤820 stacked layout
     re-centres it (horizontally) in its own media rule. */
  align-self: flex-start;
}
.kb-cover-media img {
  display: block;
  width: 100%;
  height: auto;
}
/* Per-article custom cover image (kb-ssr.ts) — rendered at its natural
   aspect ratio (width tracks the .kb-cover-media column), NOT cropped to
   the illo's portrait frame. max-height only bites on extremely tall
   uploads, where object-fit crops instead of blowing out the cover pane. */
.kb-cover-custom {
  max-height: 340px;
  object-fit: cover;
  border-radius: 18px;
}

/* Content sheet — 80px narrower than the cover so the frame shows around it
   (nested-card look). The -40px top margin tucks it over the cover pane's
   bottom edge so its head sits just below the cover content. */
.kb-sheet {
  position: relative;
  z-index: 2;
  /* 40px cream flank each side within the reveal pane. */
  width: min(1000px, calc(100% - 80px));
  /* Bottom margin = the cream wrap band (flow-root on .kb-reveal keeps it
     inside the pane), matching the 40px side flanks and the 40px top tuck
     over the cover. */
  margin: -40px auto 40px;
  background: var(--kb-surface);
  border-radius: 30px;
  min-height: 100vh;
  overflow: hidden;
}

.kb-article {
  padding: 64px 88px 52px;
}

/* Notices. .kb-notice-translation = locale-fallback ("not yet translated")
   banner at the top of the article body. */
.kb-notice {
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 12px;
  padding: 12px 16px;
  font-size: 14px;
  color: var(--kb-text-2);
  margin-bottom: 28px;
}
.kb-notice-translation {
  background: var(--kb-accent-soft);
  border-color: transparent;
  color: var(--kb-text);
}

/* Fixed cover controls — Copy page + close ✕, anchored to the content
   sheet's top-right corner, faded in together by scroll progress.
   pointer-events stays off until html.kb-scrolled so the invisible
   controls can't intercept clicks at the top of the page. */
.kb-cover-controls {
  position: fixed;
  top: 170px;
  right: max(318px, calc((100vw - 1000px) / 2 + 18px));
  z-index: 21;
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: calc(var(--p, 0) * 4);
  transition: opacity .2s ease;
  pointer-events: none;
}
html.kb-scrolled .kb-cover-controls {
  pointer-events: auto;
}
/* The drawer covers the sheet — hide the controls underneath it. */
html.kb-drawer-open .kb-cover-controls {
  opacity: 0;
  pointer-events: none;
}
.kb-close {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--kb-chip);
  border: none;
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

/* "Scroll to read ↓" cue — inverse fade of the ✕. */
.kb-scroll-cue {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 21;
  background: rgba(255, 255, 255, 0.14);
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  color: #fff;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 14px;
  padding: 10px 20px;
  border-radius: 100px;
  cursor: pointer;
  opacity: calc(1 - var(--p, 0) * 4);
  backdrop-filter: blur(4px);
}
html.kb-scrolled .kb-scroll-cue {
  pointer-events: none;
}

/* ─── TOC rail ("On this page", right gutter, article pages ≥1181) ────────── */
.kb-toc {
  position: fixed;
  right: 44px;
  top: 84px;
  /* box-sizing + width/padding keep the text where it was while adding a 12px
     left gutter so overflow-x:hidden doesn't clip the scroll-spy dot's shadow. */
  box-sizing: border-box;
  width: 200px;
  padding-left: 12px;
  z-index: 22;
  /* When the TOC is taller than the viewport (long articles, many headings),
     scroll it internally instead of clipping the bottom entries. */
  max-height: calc(100vh - 84px - 20px);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.28) transparent;
}
.kb-toc::-webkit-scrollbar {
  width: 6px;
}
.kb-toc::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--kb-toc-ink, #fff) 25%, transparent);
  border-radius: 3px;
}
.kb-toc::-webkit-scrollbar-track {
  background: transparent;
}
/* Optional rounded panel behind the in-page nav
   (appearance_settings.kb_toc_panel). The rail is transparent by default and
   reads against the frame colour; over a background image, or any busy page,
   it needs a plate of its own. Emitted as --kb-toc-panel-bg only when the
   tenant turns it on, so the default is unchanged. */
.kb-toc[data-kb-toc-panel="true"] {
  background: var(--kb-toc-panel-bg, transparent);
  backdrop-filter: var(--kb-toc-panel-blur, none);
  -webkit-backdrop-filter: var(--kb-toc-panel-blur, none);
  border-radius: 18px;
  /* The rail's own 12px left gutter stays (it keeps overflow-x from clipping
     the scroll-spy dot's shadow); the rest is the plate's padding. */
  padding: 18px 18px 18px 18px;
  /* max-height is computed from the top offset, so the padding has to come
     back out of it or a long TOC overflows the viewport. */
  max-height: calc(100vh - 84px - 20px - 36px);
}

.kb-toc-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--kb-toc-ink, #fff) 55%, transparent);
  margin-bottom: 16px;
}
.kb-toc-list {
  list-style: none;
  position: relative;
  padding-left: 22px;
  margin: 0;
}
/* Track line the indicator dot rides along. */
.kb-toc-list::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  bottom: 10px;
  width: 2px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--kb-toc-ink, #fff) 25%, transparent);
}
/* Scroll-spy dot — kb.js sets --kb-toc-dot-y to the active link's vertical
   centre; the elastic overshoot easing is part of the design (keep it). */
.kb-toc-indicator {
  position: absolute;
  left: 1px;
  top: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--kb-toc-ink, #fff);
  margin-left: -4.5px;
  margin-top: -4.5px;
  transform: translateY(var(--kb-toc-dot-y, 20px));
  transition: transform .5s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--kb-toc-ink, #fff) 28%, transparent);
  pointer-events: none;
}
.kb-toc-link {
  display: block;
  font-size: 14px;
  line-height: 1.35;
  padding: 8px 0;
  color: color-mix(in srgb, var(--kb-toc-ink, #fff) 60%, transparent);
  text-decoration: none;
}
.kb-toc-link:hover {
  color: color-mix(in srgb, var(--kb-toc-ink, #fff) 85%, transparent);
}
.kb-toc-link.active {
  color: var(--kb-toc-ink, #fff);
  font-weight: 600;
}
.kb-toc-link--sub {
  padding-left: 14px;
  font-size: 13.5px;
}

/* Anchored headings land below the fixed header + breathing room. */
.kb-prose h1[id],
.kb-prose h2[id],
.kb-prose h3[id],
.kb-prose h4[id] {
  scroll-margin-top: 120px;
}

/* ─── Prose (article body skin) ─────────────────────────────────────────────
   Body 19/1.6, headings on the heading font, everything on tokens. The
   reading measure is 720px; media blocks may run wider. */
.kb-prose {
  /* 19px at the default 16px base — tracks the tenant's base-size setting. */
  font-size: calc(var(--kb-base-font-size, 16px) + 3px);
  line-height: 1.6;
  color: var(--kb-text);
}
.kb-prose > :first-child {
  margin-top: 0;
}

.kb-prose p {
  margin: 20px 0 0;
  max-width: 720px;
}

.kb-prose h1,
.kb-prose h2 {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 48px;
  line-height: 1.07;
  letter-spacing: -1.1px;
  color: var(--kb-text);
  margin: 96px 0 0;
  max-width: 720px;
}
.kb-prose h3 {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 30px;
  line-height: 1.2;
  letter-spacing: -0.5px;
  color: var(--kb-text);
  margin: 64px 0 0;
  max-width: 720px;
}
.kb-prose h4 {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.3;
  color: var(--kb-text);
  margin: 40px 0 0;
  max-width: 720px;
}
.kb-prose h1 + p,
.kb-prose h2 + p {
  margin-top: 32px;
}
.kb-prose h3 + p,
.kb-prose h4 + p {
  margin-top: 20px;
}

.kb-prose ul,
.kb-prose ol {
  margin: 20px 0 0;
  padding-left: 26px;
  max-width: 720px;
}
.kb-prose li {
  margin-top: 10px;
}
.kb-prose li::marker {
  color: var(--kb-text-3);
}

.kb-prose strong {
  font-weight: 600;
}

.kb-prose a {
  color: var(--kb-accent-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.kb-prose a:hover {
  text-decoration: none;
}

/* Blockquote = designed pull-quote, not the bordered aside of v1. */
.kb-prose blockquote {
  margin: 56px 0 0;
  max-width: 820px;
  border: none;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 27px;
  line-height: 1.32;
  letter-spacing: -0.3px;
  color: var(--kb-text);
}
.kb-prose blockquote p {
  margin: 0;
  max-width: none;
}
.kb-prose blockquote p + p {
  margin-top: 22px;
}

.kb-prose code {
  background: var(--kb-surface-2);
  border-radius: 6px;
  padding: 2px 7px;
  font-size: 0.82em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.kb-prose pre {
  background: var(--kb-surface-2);
  color: var(--kb-text);
  padding: 20px 24px;
  border-radius: 12px;
  overflow-x: auto;
  margin: 32px 0 0;
  max-width: 720px;
  font-size: 14px;
  line-height: 1.6;
}
.kb-prose pre code {
  background: none;
  padding: 0;
  font-size: inherit;
}

.kb-prose img {
  max-width: 100%;
  height: auto;
  border-radius: 18px;
  margin: 32px 0 0;
}

/* Image figures — an image the author gave a caption, a width or an
   alignment. The editor writes data attributes; `preprocessBlocks` converts
   them to these classes BEFORE the sanitizer runs, because the sanitizer
   forbids `style` (see shared/image-figure.ts). */
.kb-prose .kb-figure {
  margin: 32px 0 0;
  max-width: 100%;
}
.kb-prose .kb-figure > img {
  /* The figure owns the outer margin now — a second one here would double it. */
  margin: 0;
}
/* Percentage figures stretch their image to fill the figure. A px figure must
   be EXCLUDED rather than overridden: the `width="300"` attribute is an author
   presentational hint, which loses to any author rule — `width: auto` here
   would override it exactly as `width: 100%` does. */
.kb-prose .kb-figure:not(.kb-figure--px) > img {
  width: 100%;
}
.kb-prose .kb-figure > figcaption {
  margin: 10px 0 0;
  color: var(--kb-text-3);
  font-size: 14px;
  line-height: 1.5;
}

/* Alignment. `margin-inline` rather than `float` so a caption travels with the
   image and following text never wraps into an awkward column. */
.kb-prose .kb-figure--left {
  margin-right: auto;
}
.kb-prose .kb-figure--center {
  margin-left: auto;
  margin-right: auto;
}
.kb-prose .kb-figure--center > figcaption {
  text-align: center;
}
.kb-prose .kb-figure--right {
  margin-left: auto;
}

/* One rule per step the editor can emit — IMAGE_WIDTH_STEPS in
   shared/image-figure.ts. 100% needs none: it is the default. */
.kb-prose .kb-figure--w10 {
  width: 10%;
}
.kb-prose .kb-figure--w15 {
  width: 15%;
}
.kb-prose .kb-figure--w20 {
  width: 20%;
}
.kb-prose .kb-figure--w25 {
  width: 25%;
}
.kb-prose .kb-figure--w30 {
  width: 30%;
}
.kb-prose .kb-figure--w35 {
  width: 35%;
}
.kb-prose .kb-figure--w40 {
  width: 40%;
}
.kb-prose .kb-figure--w45 {
  width: 45%;
}
.kb-prose .kb-figure--w50 {
  width: 50%;
}
.kb-prose .kb-figure--w55 {
  width: 55%;
}
.kb-prose .kb-figure--w60 {
  width: 60%;
}
.kb-prose .kb-figure--w65 {
  width: 65%;
}
.kb-prose .kb-figure--w70 {
  width: 70%;
}
.kb-prose .kb-figure--w75 {
  width: 75%;
}
.kb-prose .kb-figure--w80 {
  width: 80%;
}
.kb-prose .kb-figure--w85 {
  width: 85%;
}
.kb-prose .kb-figure--w90 {
  width: 90%;
}
.kb-prose .kb-figure--w95 {
  width: 95%;
}

/* An image sized in PIXELS rather than as a percentage of the column. The px
   width lives on the <img>'s own `width` attribute (which the sanitizer
   allows), so the figure just has to stop stretching it back to 100%. See
   IMAGE_PX_FIGURE_CLASS in shared/image-figure.ts. */
.kb-prose .kb-figure--px {
  /* Hug the image so the caption sits under it and alignment has something to
     push around. The image's own `max-width: 100%` keeps both inside the
     column on a narrow screen. */
  width: fit-content;
  max-width: 100%;
}

/* Narrow screens have no room to honour a width; a 20% image on a phone is a
   thumbnail nobody can see. A px figure needs no rule here — the img keeps its
   own `max-width: 100%`, so it shrinks with the column on its own. */
@media (max-width: 640px) {
  .kb-prose .kb-figure[class*="kb-figure--w"] {
    width: 100%;
  }
}

.kb-prose table {
  width: 100%;
  max-width: 720px;
  border-collapse: collapse;
  margin: 32px 0 0;
  font-size: 15px;
}
.kb-prose th,
.kb-prose td {
  border: 1px solid var(--kb-pill);
  padding: 10px 14px;
  text-align: left;
}
.kb-prose th {
  background: var(--kb-surface-2);
  font-weight: 600;
}
/* Horizontal-scroll wrapper for wide tables (added by the SSR block
   pre-processor). Keeps wide/imported tables from overflowing the viewport
   on mobile — they scroll inside the wrapper instead. */
.kb-prose .kb-table-scroll {
  overflow-x: auto;
  max-width: 720px;
  margin: 32px 0 0;
}
.kb-prose .kb-table-scroll > table {
  margin: 0;
  max-width: none;
  min-width: 100%;
}

/* Placeholder shown when an imported image could not be fetched/re-hosted
   (e.g. an expired Notion/Google-Docs signed URL). Replaces a would-be broken
   <img>. Rendered as an INLINE-flex chip so it's valid both standalone (Notion)
   and inline inside a paragraph (Google Docs) without breaking the flow. */
.kb-prose .kb-img-missing {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0;
  padding: 8px 14px;
  border: 1px dashed var(--kb-pill);
  border-radius: 10px;
  background: var(--kb-surface-2);
  color: var(--kb-text-3);
  font-size: 14px;
  vertical-align: middle;
}

.kb-prose hr {
  border: none;
  height: 1px;
  background: var(--kb-pill);
  margin: 56px 0 0;
  max-width: 720px;
}

/* ─── Content blocks (.ec-*) — hydrated by /knowledge/blocks.js ─────────────
   Structural selectors are the contract with blocks.js — keep them all;
   only the skin changes. Embed/video aspect boxes are sized by inline
   styles from the hydrator — don't fight them. */

/* Shared spacing. */
.ec-video,
.ec-embed,
.ec-form,
.ec-scheduler,
.ec-checklist,
.ec-rawhtml {
  margin: 32px auto 0;
}

/* Section title injected for Form/Scheduler embeds with a wrapperTitle. */
.kb-prose .kb-block-section-title {
  margin-bottom: 8px;
}
.kb-prose .kb-block-section-title + .ec-form,
.kb-prose .kb-block-section-title + .ec-scheduler,
.kb-prose .kb-block-section-title + [data-ec-block] {
  margin-top: 16px;
}
.ec-block-wrapper-body {
  font-size: 15px;
  line-height: 1.55;
  color: var(--kb-text-3);
  margin: 0 0 16px;
}

/* Raw HTML — sandboxed iframe owns its own chrome. */
.ec-rawhtml {
  width: 100%;
}
.ec-rawhtml iframe {
  display: block;
  width: 100%;
  border: 0;
}

/* Columns — pure CSS grid keyed off data-col-count. */
.kb-prose [data-ec-columns] {
  display: grid;
  gap: 24px;
  margin: 32px 0 0;
  align-items: start;
}
.kb-prose [data-ec-columns][data-col-count="2"] {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.kb-prose [data-ec-columns][data-col-count="3"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.kb-prose [data-ec-columns][data-col-count="4"] {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.kb-prose [data-ec-column] {
  min-width: 0;
}
.kb-prose [data-ec-column] > *:first-child {
  margin-top: 0;
}
.kb-prose [data-ec-column] > *:last-child {
  margin-bottom: 0;
}
@media (max-width: 767px) {
  .kb-prose [data-ec-columns],
  .kb-prose [data-ec-columns][data-col-count="2"],
  .kb-prose [data-ec-columns][data-col-count="3"],
  .kb-prose [data-ec-columns][data-col-count="4"] {
    grid-template-columns: 1fr;
  }
}

/* Video */
.ec-video {
  max-width: 100%;
}
.ec-video-aspect {
  position: relative;
  width: 100%;
  background: var(--kb-ink);
  border-radius: 18px;
  overflow: hidden;
}
.ec-video-aspect iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.ec-video-caption {
  text-align: center;
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--kb-text-3);
}

/* Embed — mirrors Video for iframe (URL) mode; ec-embed-html is a plain
   container for sanitized author HTML (no aspect box). */
.ec-embed {
  max-width: 100%;
}
.ec-embed-aspect {
  position: relative;
  width: 100%;
  height: 0;
  background: var(--kb-ink);
  border-radius: 18px;
  overflow: hidden;
}
.ec-embed-aspect iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.ec-embed-caption {
  text-align: center;
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--kb-text-3);
}
.ec-embed-html {
  max-width: 100%;
}
.ec-embed-html iframe {
  max-width: 100%;
}

/* Form / Scheduler — surface-2 card envelope; the embedded widget keeps its
   own inner chrome. */
.ec-form,
.ec-scheduler {
  max-width: 640px;
  background: var(--kb-surface-2);
  border-radius: 18px;
  padding: 20px;
}
.ec-scheduler {
  max-width: 760px;
}
.ec-form iframe,
.ec-scheduler iframe {
  width: 100%;
  border: 0;
  display: block;
  background: transparent;
  border-radius: 10px;
}

/* Checklist — surface-2 card rows. */
.ec-checklist {
  max-width: 720px;
}
.ec-checklist-title {
  margin: 0 0 6px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  color: var(--kb-text);
}
.ec-checklist-body {
  margin: 0 0 16px;
  color: var(--kb-text-3);
}
.ec-checklist-section {
  margin: 14px 0 8px;
  color: var(--kb-text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 12px;
}
.ec-checklist-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.ec-checklist-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 12px;
  margin-bottom: 8px;
  transition: opacity .15s ease;
}
.ec-checklist-item[data-checked="true"] {
  opacity: 0.55;
}
.ec-checklist-item input[type="checkbox"] {
  margin-top: 4px;
  accent-color: var(--kb-accent);
}
.ec-checklist-item-heading {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--kb-text);
  font-weight: 600;
}
.ec-checklist-item[data-checked="true"] .ec-checklist-item-heading {
  text-decoration: line-through;
}
.ec-checklist-item-description {
  margin: 2px 0 0;
  color: var(--kb-text-3);
  font-size: 14px;
}
.ec-checklist-required {
  color: var(--kb-red);
  font-weight: 700;
}

/* FAQ — server-rendered <details><summary>, surface-2 cards + rotating
   chevron (drawn with ::before). */
.ec-faq {
  max-width: 720px;
  margin: 32px auto 0;
}
.ec-faq-item {
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 14px;
  margin-bottom: 10px;
}
.ec-faq-item summary {
  padding: 14px 18px;
  cursor: pointer;
  font-weight: 600;
  font-size: 16px;
  color: var(--kb-text);
  list-style: none;
  display: flex;
  align-items: center;
}
.ec-faq-item summary::-webkit-details-marker {
  display: none;
}
.ec-faq-item summary::before {
  content: "▸";
  display: inline-block;
  width: 22px;
  flex: none;
  color: var(--kb-text-3);
  transition: transform .25s ease;
}
.ec-faq-item[open] summary::before {
  transform: rotate(90deg);
}
.ec-faq-answer {
  padding: 0 18px 16px 40px;
  color: var(--kb-text-2);
  font-size: 16px;
}
.ec-faq-answer p {
  margin: 0 0 8px;
  max-width: none;
}
.ec-faq-answer p:last-child {
  margin: 0;
}

/* ─── Feedback card ("Was this content helpful?") ──────────────────────────
   State contract (feedback.js): `.is-voted` on .kb-feedback hides the ask
   row; the thanks row un-hides via removing [hidden]. */
/* ─── In-body document links ──────────────────────────────────────────────── */
/* Resolved links inherit the prose-link colour (.kb-prose a) — they ARE prose
   links. The only distinction is a softer underline, so an internal reference
   reads as part of the sentence rather than an interruption. Unresolvable
   links never reach the browser: the SSR replaces them with plain text. */
.kb-prose a.kb-doc-link {
  text-decoration-color: var(--kb-accent-soft);
  text-decoration-thickness: 1.5px;
}
.kb-prose a.kb-doc-link:hover {
  text-decoration: underline;
  text-decoration-color: var(--kb-accent-ink);
}

/* ─── Related articles ────────────────────────────────────────────────────── */
/* Author-curated, resolved at render time. Absent entirely when nothing
   resolves, so this never renders as an empty heading. */
.kb-related {
  margin-top: 72px;
}
.kb-related-title {
  font-family: var(--kb-heading-font-family);
  font-weight: var(--kb-heading-font-weight);
  font-size: 20px;
  color: var(--kb-text);
  margin: 0 0 12px;
}
.kb-related-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.kb-related-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 14px;
  text-decoration: none;
  border: 1px solid transparent;
}
.kb-related-card:hover {
  background: var(--kb-surface-2);
}
.kb-related-card-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--kb-surface-2);
  color: var(--kb-text-3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-related-card:hover .kb-related-card-icon {
  background: var(--kb-surface);
}
.kb-related-card-text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
.kb-related-card-title {
  font-size: 16px;
  font-weight: 500;
  color: var(--kb-text);
}
.kb-related-card-desc {
  font-size: 14px;
  color: var(--kb-text-3);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kb-related-card-chevron {
  color: var(--kb-text-3);
  flex: none;
  display: flex;
}

.kb-feedback {
  margin-top: 96px;
  background: var(--kb-surface-2);
  border-radius: 24px;
  padding: 34px 40px;
}
.kb-feedback-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
}
.kb-feedback.is-voted .kb-feedback-ask {
  display: none;
}
.kb-feedback-prompt {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.4px;
  color: var(--kb-text);
}
.kb-feedback-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}
.kb-feedback-btn {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--kb-surface);
  border: 1.5px solid var(--kb-pill);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.kb-feedback-btn--up {
  color: var(--kb-green);
}
.kb-feedback-btn--up:hover,
.kb-feedback-btn--up.is-selected {
  border-color: var(--kb-green);
  background: rgba(26, 163, 74, 0.08);
}
.kb-feedback-btn--down {
  color: var(--kb-red);
}
.kb-feedback-btn--down:hover,
.kb-feedback-btn--down.is-selected {
  border-color: var(--kb-red);
  background: rgba(234, 63, 46, 0.08);
}
.kb-feedback-thanks {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
}
.kb-feedback-thanks[hidden] {
  display: none;
}
.kb-feedback-check {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(26, 163, 74, 0.14);
  color: var(--kb-green);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-feedback-thanks-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 18px;
  color: var(--kb-text);
}

/* ─── Copy page split-button (behaviour: /knowledge/copy-page.js) ─────────── */
.kb-copy-page {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  flex-shrink: 0;
}
.kb-copy-page-main,
.kb-copy-page-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--kb-surface-2);
  color: var(--kb-text-2);
  border: 1px solid var(--kb-pill);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
}
.kb-copy-page-main {
  gap: 6px;
  padding: 8px 12px;
  border-radius: 100px 0 0 100px;
  border-right: 0;
}
.kb-copy-page-chevron {
  padding: 8px 9px;
  border-radius: 0 100px 100px 0;
}
.kb-copy-page-main:hover,
.kb-copy-page-chevron:hover {
  background: var(--kb-pill);
  color: var(--kb-text);
}
.kb-copy-page-icon-success {
  display: none;
}
.kb-copy-page.is-copied .kb-copy-page-icon-default {
  display: none;
}
.kb-copy-page.is-copied .kb-copy-page-icon-success {
  display: inline-block;
  color: var(--kb-green);
}
.kb-copy-page-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 280px;
  background: var(--kb-surface);
  border: 1px solid var(--kb-pill);
  border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
  padding: 6px;
  z-index: 50;
}
.kb-copy-page-menu[hidden] {
  display: none;
}
.kb-copy-page-item {
  display: flex;
  align-items: flex-start;
  width: 100%;
  gap: 10px;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: var(--kb-text);
  font-family: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.kb-copy-page-item:hover,
.kb-copy-page-item:focus-visible {
  background: var(--kb-surface-2);
  outline: none;
}
.kb-copy-page-item > svg {
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--kb-text-3);
}
.kb-copy-page-item-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.kb-copy-page-item-title {
  font-weight: 500;
  color: var(--kb-text);
}
.kb-copy-page-item-sub {
  font-size: 12px;
  color: var(--kb-text-3);
}
.kb-copy-page-item-arrow {
  display: inline-block;
  margin-left: 2px;
  color: var(--kb-text-3);
  font-size: 11px;
}
@media (max-width: 640px) {
  .kb-copy-page-main .kb-copy-page-label {
    display: none;
  }
  .kb-copy-page-main {
    padding: 8px 10px;
  }
}

/* ─── Overlays: shared open/close contract ─────────────────────────────────
   All overlay roots ship [hidden]. kb.js (or the overlay's own script)
   removes hidden, then adds .is-open on the next frame so the transitions
   run; close removes .is-open and re-hides after the transition. */

/* ─── Search modal (⌘K command palette) ───────────────────────────────────── */
.kb-search-modal {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 84px 24px 24px;
}
.kb-search-modal[hidden] {
  display: none;
}
.kb-search-modal-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity .2s ease;
}
.kb-search-modal.is-open .kb-search-modal-scrim {
  opacity: 1;
}
.kb-search-modal-card {
  position: relative;
  width: min(600px, 100%);
  background: var(--kb-surface);
  border-radius: 18px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: 70vh;
  transform: translateY(-10px);
  opacity: 0;
  transition: transform .2s ease, opacity .2s ease;
}
.kb-search-modal.is-open .kb-search-modal-card {
  transform: none;
  opacity: 1;
}
.kb-search-modal-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--kb-pill);
}
.kb-search-modal-head > svg {
  color: var(--kb-text-3);
  flex: none;
}
.kb-search-modal-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  outline: none;
  font-family: var(--kb-font-family);
  font-size: 17px;
  color: var(--kb-text);
}
.kb-search-modal-input::placeholder {
  color: var(--kb-text-3);
}
.kb-search-modal-results {
  overflow-y: auto;
  padding: 8px;
}
.kb-search-modal-label {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--kb-text-3);
  padding: 8px 12px 6px;
}
.kb-search-modal-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border-radius: 10px;
  text-decoration: none;
}
.kb-search-modal-row.is-active {
  background: var(--kb-surface-2);
}
/* "See all results for …" — first row whenever something is typed; opens
   the /search results page. */
.kb-search-modal-row--all .kb-search-modal-row-title {
  font-weight: 500;
  color: var(--kb-accent-ink);
}
.kb-search-modal-row-icon {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--kb-surface-2);
  color: var(--kb-text-3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-search-modal-row.is-active .kb-search-modal-row-icon {
  background: var(--kb-surface);
}
.kb-search-modal-row-text {
  flex: 1;
  min-width: 0;
}
.kb-search-modal-row-title {
  display: block;
  font-size: 14.5px;
  color: var(--kb-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kb-search-modal-row-cat {
  display: block;
  font-size: 12.5px;
  color: var(--kb-text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kb-search-modal-row > svg {
  color: var(--kb-text-3);
  flex: none;
}
mark.kb-search-hl {
  background: none;
  color: var(--kb-accent-ink);
  font-weight: 600;
}
.kb-search-modal-empty {
  padding: 26px 12px 32px;
  text-align: center;
  font-size: 14px;
  color: var(--kb-text-3);
}

/* ─── Ask Assistant slide-in panel (⌘I) ─────────────────────────────────────
   The SSR emits the shell; /knowledge/ask-assistant.js drives the thread.
   Thread-item classes below are the render contract with that script:
   .kb-assistant-row(--bot/--typing) > .kb-assistant-avatar +
   .kb-assistant-row-body; .kb-assistant-msg(--user/--bot/--error);
   .kb-assistant-typing (3 <i> dots); .kb-assistant-sources /
   -sources-label / -source (anchor OR no-href <span>). User bubbles are
   direct children of [data-kb-assistant-thread] (flex column) so
   align-self:flex-end works. */
.kb-assistant[hidden] {
  display: none;
}
.kb-assistant-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.38);
  opacity: 0;
  transition: opacity .3s ease;
  z-index: 64;
}
.kb-assistant.is-open .kb-assistant-scrim {
  opacity: 1;
}
.kb-assistant-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(420px, 100vw);
  background: var(--kb-surface);
  z-index: 65;
  transform: translateX(100%);
  transition: transform .34s cubic-bezier(0.4, 0, 0.2, 1),
              width .28s cubic-bezier(0.4, 0, 0.2, 1);
  display: flex;
  flex-direction: column;
  box-shadow: -14px 0 48px rgba(0, 0, 0, 0.22);
}
.kb-assistant.is-open .kb-assistant-panel {
  transform: none;
}

/* Full-screen mode (the header's expand toggle; persisted per browser by
   ask-assistant.js). The panel fills the viewport but the CONTENT stays in a
   ~860px reading column — an answer set edge-to-edge across a desktop is
   harder to read than the 420px rail it replaced. Symmetric padding does that
   without any extra wrapper markup. */
.kb-assistant.is-full .kb-assistant-panel {
  width: 100vw;
}
.kb-assistant.is-full .kb-assistant-head,
.kb-assistant.is-full .kb-assistant-scroll,
.kb-assistant.is-full .kb-assistant-foot {
  padding-inline: max(18px, calc((100vw - 860px) / 2));
}

.kb-assistant-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 18px;
  border-bottom: 1px solid var(--kb-pill);
}
.kb-assistant-head-id {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
.kb-assistant-mark {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--kb-accent-soft);
  color: var(--kb-accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-assistant-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 15px;
  color: var(--kb-text);
  line-height: 1.2;
}
.kb-assistant-subtitle {
  font-size: 12px;
  color: var(--kb-text-3);
}
.kb-assistant-head-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
}
/* Panel/modal close buttons — the .kb-iconbtn base is frame-tinted; on a
   surface they become quiet square-ish ghosts. */
.kb-assistant-close,
.kb-assistant-expand {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: transparent;
  color: var(--kb-text-3);
}
.kb-assistant-close:hover,
.kb-assistant-expand:hover {
  background: var(--kb-surface-2);
}
/* One button, two icons — the state lives on .kb-assistant, so the swap is a
   class toggle rather than DOM surgery in a CSP-strict script. */
.kb-assistant-expand .i-collapse {
  display: none;
}
.kb-assistant.is-full .kb-assistant-expand .i-expand {
  display: none;
}
.kb-assistant.is-full .kb-assistant-expand .i-collapse {
  display: block;
}
/* Below 640px the panel is already full-bleed (see the 480px override), and
   at 640px there's no room to widen — the toggle would be a no-op. */
@media (max-width: 640px) {
  .kb-assistant-expand {
    display: none;
  }
}

.kb-assistant-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 22px 18px;
}
.kb-assistant-empty-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 21px;
  letter-spacing: -0.4px;
  color: var(--kb-text);
}
.kb-assistant-empty-body {
  font-size: 14px;
  line-height: 1.55;
  color: var(--kb-text-3);
  margin: 8px 0 22px;
}
.kb-assistant-suggest-label {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--kb-text-3);
  margin-bottom: 10px;
}
.kb-assistant-suggestions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.kb-assistant-suggestion {
  text-align: left;
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 12px;
  padding: 12px 14px;
  font-family: var(--kb-font-family);
  font-size: 14px;
  color: var(--kb-text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.kb-assistant-suggestion:hover {
  border-color: var(--kb-accent-ink);
}
.kb-assistant-suggestion > svg {
  color: var(--kb-text-3);
  flex: none;
}

/* Thread — a flex column so user bubbles (direct children) can align-self
   to the end. */
.kb-assistant-thread {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.kb-assistant-thread:empty {
  display: none;
}
/* Bot / typing rows: avatar + body. */
.kb-assistant-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.kb-assistant-row-body {
  flex: 1;
  min-width: 0;
}
.kb-assistant-avatar {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: var(--kb-accent-soft);
  color: var(--kb-accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
/* Message bubbles. */
.kb-assistant-msg {
  font-size: 14px;
  overflow-wrap: break-word;
}
.kb-assistant-msg--user {
  align-self: flex-end;
  max-width: 82%;
  background: var(--kb-accent);
  color: #fff;
  line-height: 1.5;
  padding: 10px 14px;
  border-radius: 16px 16px 4px 16px;
}
.kb-assistant-msg--bot {
  background: var(--kb-surface-2);
  color: var(--kb-text);
  line-height: 1.55;
  padding: 12px 14px;
  border-radius: 4px 16px 16px 16px;
  white-space: pre-wrap;
}
.kb-assistant-msg--error {
  color: var(--kb-red);
  background: rgba(234, 63, 46, 0.06);
  border: 1px solid rgba(234, 63, 46, 0.3);
}
/* Markdown-rendered bot answers (kb-markdown.js). The renderer emits real
   block elements, so drop pre-wrap and space the blocks instead. */
.kb-assistant-msg--md {
  white-space: normal;
}
.kb-assistant-msg--md p {
  margin: 0 0 10px;
}
.kb-assistant-msg--md ul,
.kb-assistant-msg--md ol {
  margin: 0 0 10px;
  padding-left: 20px;
}
.kb-assistant-msg--md li {
  margin: 3px 0;
}
.kb-assistant-msg--md li::marker {
  color: var(--kb-text-3);
}
.kb-assistant-msg--md strong {
  font-weight: 650;
}
.kb-assistant-msg--md a {
  color: var(--kb-accent-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}
.kb-assistant-msg--md a:hover {
  text-decoration-thickness: 2px;
}
.kb-assistant-msg--md a:focus-visible {
  outline: 2px solid var(--kb-accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.kb-assistant-msg--md .kb-md-heading {
  font-size: 15px;
  margin: 14px 0 6px;
}
.kb-assistant-msg--md > :first-child {
  margin-top: 0;
}
.kb-assistant-msg--md > :last-child {
  margin-bottom: 0;
}
.kb-assistant-typing {
  display: inline-flex;
  gap: 5px;
  align-items: center;
  background: var(--kb-surface-2);
  border-radius: 14px;
  padding: 13px 15px;
}
.kb-assistant-typing i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--kb-text-3);
  display: inline-block;
  animation: kbAsstDot 1s infinite;
}
.kb-assistant-typing i:nth-child(2) {
  animation-delay: .15s;
}
.kb-assistant-typing i:nth-child(3) {
  animation-delay: .3s;
}
@keyframes kbAsstDot {
  0%, 80%, 100% { opacity: .3; transform: none; }
  40%           { opacity: 1;  transform: translateY(-3px); }
}
.kb-assistant-sources {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.kb-assistant-sources-label {
  font-size: 12px;
  color: var(--kb-text-3);
}
.kb-assistant-source {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 100px;
  padding: 5px 11px;
  font-size: 12.5px;
  color: var(--kb-text-2);
  text-decoration: none;
}
.kb-assistant-source:hover {
  border-color: var(--kb-accent-ink);
}
.kb-assistant-source > svg {
  color: var(--kb-text-3);
  flex: none;
}

.kb-assistant-foot {
  border-top: 1px solid var(--kb-pill);
  padding: 14px 16px 16px;
}
.kb-assistant-composer {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 18px;
  padding: 14px 14px 12px;
}
.kb-assistant-input {
  width: 100%;
  border: none;
  background: transparent;
  resize: none;
  outline: none;
  font-family: var(--kb-font-family);
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--kb-text);
  max-height: 160px;
  min-height: 22px;
  padding: 0;
}
.kb-assistant-input::placeholder {
  color: var(--kb-text-3);
}
.kb-assistant-composer-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
/* Send — grey while empty, green with a white arrow once there's text
   (ask-assistant.js toggles .has-text; the svg rides currentColor). */
.kb-assistant-send {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--kb-pill);
  border: none;
  color: var(--kb-text-3);
  cursor: default;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  transition: background-color .2s ease, color .2s ease;
}
.kb-assistant-send.has-text {
  background: var(--kb-green);
  color: #fff;
  cursor: pointer;
}
.kb-assistant-disclaimer {
  font-size: 11px;
  color: var(--kb-text-3);
  margin-top: 9px;
  text-align: center;
}

/* ─── Login modal (magic-link) ─────────────────────────────────────────────── */
.kb-login-modal {
  position: fixed;
  inset: 0;
  z-index: 69;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.kb-login-modal[hidden] {
  display: none;
}
.kb-login-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity .25s ease;
}
.kb-login-modal.is-open .kb-login-scrim {
  opacity: 1;
}
.kb-login-card {
  position: relative;
  width: min(400px, 100%);
  background: var(--kb-surface);
  border-radius: 20px;
  padding: 34px 32px 30px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
  transform: translateY(14px) scale(0.98);
  opacity: 0;
  transition: transform .25s ease, opacity .25s ease;
}
.kb-login-modal.is-open .kb-login-card {
  transform: none;
  opacity: 1;
}
.kb-login-x {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: transparent;
  color: var(--kb-text-3);
}
.kb-login-x:hover {
  background: var(--kb-surface-2);
}
/* Brand tile inside the card — bigger than the header tile; the no-logo
   initial variant flips to a solid accent tile. */
.kb-login-card .kb-logo-tile {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  border: 1px solid var(--kb-pill);
}
.kb-login-card .kb-logo-tile--initial {
  background: var(--kb-accent);
  border: none;
  color: #fff;
  font-size: 20px;
}
.kb-login-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 24px;
  letter-spacing: -0.5px;
  color: var(--kb-text);
  margin: 20px 0 0;
}
.kb-login-subtext {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--kb-text-3);
  margin: 8px 0 24px;
}
.kb-login-label {
  display: block;
  font-weight: 600;
  font-size: 13px;
  color: var(--kb-text-2);
  margin-bottom: 7px;
}
.kb-login-email {
  width: 100%;
  height: 46px;
  padding: 0 14px;
  border-radius: 11px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  font-family: var(--kb-font-family);
  font-size: 15px;
  color: var(--kb-text);
  outline: none;
}
.kb-login-email:focus {
  border-color: var(--kb-accent-ink);
}
.kb-login-email.is-invalid {
  border-color: var(--kb-red);
}
.kb-login-error {
  font-size: 13px;
  color: var(--kb-red);
  margin-top: 8px;
}
.kb-login-error[hidden] {
  display: none;
}
.kb-login-submit {
  width: 100%;
  height: 48px;
  margin-top: 18px;
  border-radius: 12px;
  background: var(--kb-accent);
  border: none;
  cursor: pointer;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  color: #fff;
}
.kb-login-submit:hover {
  box-shadow: inset 0 0 0 99px rgba(0, 0, 0, 0.08);
}
.kb-login-submit:disabled {
  opacity: 0.6;
  cursor: default;
}
.kb-login-success-state {
  text-align: center;
}
.kb-login-form-state[hidden],
.kb-login-success-state[hidden] {
  display: none;
}
.kb-login-mail-badge {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(26, 163, 74, 0.14);
  color: var(--kb-green);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.kb-login-success-state .kb-login-title {
  margin-top: 14px;
}
.kb-login-success-state .kb-login-subtext {
  margin: 10px 0 0;
}
.kb-login-success-state .kb-login-subtext b {
  color: var(--kb-text);
}
.kb-login-success-state .kb-login-submit {
  margin-top: 22px;
}
.kb-login-resend {
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--kb-font-family);
  font-size: 13px;
  color: var(--kb-text-3);
  margin-top: 14px;
}
.kb-login-resend:hover {
  color: var(--kb-accent-ink);
}
.kb-login-resend:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ─── Home page (panel + hero + tiles) ─────────────────────────────────────── */
.kb-panel {
  position: relative;
  width: min(1180px, calc(100% - 96px));
  margin: 0 auto;
  background: var(--kb-surface);
  border-radius: 30px;
  min-height: calc(100vh - 94px);
  overflow: hidden;
}

.kb-home-hero {
  background: var(--kb-cover);
  padding: 74px 40px 66px;
  text-align: center;
}
.kb-home-eyebrow {
  display: inline-block;
  background: var(--kb-pill);
  color: var(--kb-text);
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 14px;
  padding: 8px 16px;
  border-radius: 100px;
}
.kb-home-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 52px;
  line-height: 1.08;
  letter-spacing: -1.5px;
  color: var(--kb-text);
  margin: 22px 0 0;
}
.kb-home-desc {
  font-size: 17px;
  line-height: 1.55;
  color: var(--kb-text-2);
  margin: 18px auto 0;
  max-width: 500px;
}

/* Hero search — a <button> styled as the big field; opens the ⌘K modal. */
.kb-home-search {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  max-width: 580px;
  height: 58px;
  margin: 34px auto 0;
  padding: 0 16px 0 20px;
  border-radius: 15px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.05);
  cursor: pointer;
  text-align: left;
}
.kb-home-search:hover,
.kb-home-search:focus-visible {
  border-color: var(--kb-accent-ink);
}
.kb-home-search-icon {
  color: var(--kb-text-3);
  flex: none;
}
.kb-home-search-label {
  flex: 1;
  min-width: 0;
  font-family: var(--kb-font-family);
  font-size: 16px;
  color: var(--kb-text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kb-home-search .kb-kbd-chip {
  background: var(--kb-pill);
}

.kb-home-popular {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 22px;
}
.kb-home-popular-label {
  font-size: 13.5px;
  color: var(--kb-text-3);
  margin-right: 2px;
}
.kb-home-popular-chip {
  font-size: 13.5px;
  color: var(--kb-text-2);
  text-decoration: none;
  background: var(--kb-surface);
  border: 1px solid var(--kb-pill);
  padding: 6px 13px;
  border-radius: 100px;
}
.kb-home-popular-chip:hover {
  border-color: var(--kb-accent-ink);
  color: var(--kb-accent-ink);
}

/* Category tiles. */
.kb-home-tiles {
  padding: 52px 48px 120px;
}
.kb-home-tiles-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 26px;
}
.kb-home-tiles-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 30px;
  letter-spacing: -0.6px;
  color: var(--kb-text);
  margin: 0;
}
.kb-home-tiles-count {
  font-size: 14px;
  color: var(--kb-text-3);
}
.kb-tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 22px;
}
/* The global `*` colour transition would clobber transform/box-shadow —
   restate all of it here so the hover lift AND theme swap both animate. */
.kb-tile {
  background: var(--kb-surface-2);
  border-radius: 18px;
  padding: 24px 24px 22px;
  display: flex;
  flex-direction: column;
  transition:
    transform .2s ease,
    box-shadow .2s ease,
    background-color .28s ease,
    color .28s ease,
    border-color .28s ease;
}
.kb-tile:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.10);
}
.kb-tile-head {
  display: flex;
  align-items: center;
  gap: 14px;
}
.kb-tile-visual {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-tile-visual--image {
  overflow: hidden;
  background: var(--kb-surface);
}
.kb-tile-visual--image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Accent cycle (data-kb-tile-accent = index % 4): tenant accent, red,
   green, amber tints. rgba fallback first; color-mix (tint over surface,
   theme-aware) wins where supported. */
.kb-tile[data-kb-tile-accent="0"] .kb-tile-visual--icon {
  background: var(--kb-accent-soft);
  color: var(--kb-accent-ink);
}
.kb-tile[data-kb-tile-accent="1"] .kb-tile-visual--icon {
  background: rgba(234, 63, 46, 0.12);
  background: color-mix(in srgb, var(--kb-red) 12%, var(--kb-surface));
  color: var(--kb-red);
}
.kb-tile[data-kb-tile-accent="2"] .kb-tile-visual--icon {
  background: rgba(26, 163, 74, 0.12);
  background: color-mix(in srgb, var(--kb-green) 12%, var(--kb-surface));
  color: var(--kb-green);
}
.kb-tile[data-kb-tile-accent="3"] .kb-tile-visual--icon {
  background: rgba(249, 171, 0, 0.16);
  background: color-mix(in srgb, var(--kb-amber) 16%, var(--kb-surface));
  color: var(--kb-amber-hover);
}
.kb-tile-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 19px;
  color: var(--kb-text);
  margin: 0;
}
.kb-tile-desc {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--kb-text-3);
  margin: 14px 0 0;
}
.kb-tile-list {
  list-style: none;
  margin: 16px 0 0;
  border-top: 1px solid var(--kb-pill);
  padding: 6px 0 0;
  display: flex;
  flex-direction: column;
}
.kb-tile-list a {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14.5px;
  color: var(--kb-text-2);
  text-decoration: none;
  padding: 7px 0;
}
.kb-tile-list a:hover {
  color: var(--kb-accent-ink);
}
.kb-tile-list a svg {
  color: var(--kb-text-3);
  flex: none;
}
.kb-tile-more {
  margin-top: 12px;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--kb-accent-ink);
  text-decoration: none;
}
.kb-tile-more:hover {
  text-decoration: underline;
}

/* ─── Category index page ──────────────────────────────────────────────────── */
.kb-catpage-hero {
  background: var(--kb-cover);
  padding: 64px 48px;
}
.kb-catpage-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 40px;
  line-height: 1.1;
  letter-spacing: -1px;
  color: var(--kb-text);
  margin: 20px 0 0;
}
.kb-catpage-desc {
  font-size: 17px;
  line-height: 1.55;
  color: var(--kb-text-2);
  margin: 14px 0 0;
  max-width: 640px;
}
.kb-catpage-count {
  display: block;
  font-size: 14px;
  color: var(--kb-text-3);
  margin-top: 18px;
}
.kb-catpage-list {
  padding: 32px 48px 96px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.kb-catpage-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border-radius: 14px;
  text-decoration: none;
}
.kb-catpage-row:hover {
  background: var(--kb-surface-2);
}
.kb-catpage-row-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--kb-surface-2);
  color: var(--kb-text-3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-catpage-row:hover .kb-catpage-row-icon {
  background: var(--kb-surface);
}
.kb-catpage-row-text {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
.kb-catpage-row-title {
  font-size: 16px;
  font-weight: 500;
  color: var(--kb-text);
}
.kb-catpage-row-desc {
  font-size: 14px;
  color: var(--kb-text-3);
  margin-top: 2px;
}
.kb-catpage-row > svg {
  color: var(--kb-text-3);
  flex: none;
}
/* /search results page — reached from the ⌘K modal's "See all results" row
   (and Enter). Reuses the category list rows; adds a refine field, "Did you
   mean", a category label per row, and a zero-results state with popular
   articles + Ask AI. */
.kb-search-page-form {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 580px;
  height: 52px;
  margin-top: 24px;
  padding: 0 16px;
  border-radius: 14px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  color: var(--kb-text-3);
}
.kb-search-page-form:focus-within {
  border-color: var(--kb-accent-ink);
}
.kb-search-page-form input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 16px;
  color: var(--kb-text);
  outline: none;
}
.kb-search-page-dym {
  margin: 16px 0 0;
  font-size: 16px;
  color: var(--kb-text-2);
}
.kb-search-page-dym a {
  color: var(--kb-accent-ink);
  text-decoration: none;
}
.kb-search-page-dym a:hover {
  text-decoration: underline;
}
.kb-search-page-cat {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--kb-text-3);
  margin-bottom: 2px;
}
.kb-search-page-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--kb-text-3);
  padding: 0 16px 8px;
}
.kb-search-page-empty {
  padding: 40px 48px 8px;
  font-size: 15px;
  color: var(--kb-text-3);
}
.kb-search-page-empty-title {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
  color: var(--kb-text);
}
.kb-search-page-empty-hint {
  margin: 8px 0 0;
}
.kb-search-page-ask {
  margin-top: 16px;
  height: 40px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  color: var(--kb-text);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.kb-search-page-ask:hover,
.kb-search-page-ask:focus-visible {
  border-color: var(--kb-accent-ink);
}
@media (max-width: 560px) {
  .kb-search-page-empty {
    padding: 32px 24px 8px;
  }
}

/* ─── 404 / empty panel ────────────────────────────────────────────────────── */
.kb-panel--empty {
  display: flex;
  align-items: center;
  justify-content: center;
}
.kb-empty {
  text-align: center;
  padding: 80px 24px;
}
.kb-empty-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 32px;
  letter-spacing: -0.6px;
  color: var(--kb-text);
  margin-bottom: 12px;
}
.kb-empty-desc {
  color: var(--kb-text-3);
}
.kb-empty-home {
  margin-top: 20px;
}
.kb-empty-home a {
  color: var(--kb-accent-ink);
}

/* ─── Ticket-portal shell ──────────────────────────────────────────────────
   The React portal mounts inside the same white panel (.portal-main inner
   measure comes from portal-ssr's inline style). */
.kb-panel--portal {
  min-height: calc(100vh - 94px);
}

/* ─── Semantic tone utilities (Status / Changelog) ─────────────────────────
   Fixed in BOTH themes (design rule): green=operational/new/resolved,
   amber=degraded/fixed/identified, red=outage/security/investigating,
   blue=maintenance/improved/monitoring, neutral=scheduled. */
.kb-tone-text--green { color: var(--kb-green); }
.kb-tone-text--amber { color: var(--kb-amber); }
.kb-tone-text--red { color: var(--kb-red); }
.kb-tone-text--blue { color: var(--kb-blue); }
.kb-tone-text--neutral { color: var(--kb-text-3); }
.kb-tone-bg--green { background: var(--kb-green); }
.kb-tone-bg--amber { background: var(--kb-amber); }
.kb-tone-bg--red { background: var(--kb-red); }
.kb-tone-bg--blue { background: var(--kb-blue); }
.kb-tone-bg--neutral { background: var(--kb-text-3); }
.kb-tone-badge--green { background: var(--kb-green); }
.kb-tone-badge--amber { background: var(--kb-amber); }
.kb-tone-badge--red { background: var(--kb-red); }
.kb-tone-badge--blue { background: var(--kb-blue); }
.kb-tone-badge--neutral { background: var(--kb-text-3); }

/* Shared "load more" pill ("View full history" / "Load older updates"). */
.kb-portal-more-wrap {
  text-align: center;
  margin-top: 36px;
}
.kb-portal-more {
  display: inline-block;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 14px;
  color: var(--kb-text-2);
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 100px;
  padding: 10px 22px;
  text-decoration: none;
  cursor: pointer;
}
.kb-portal-more:hover {
  border-color: var(--kb-text-3);
}

/* ─── Status page ──────────────────────────────────────────────────────────
   Spec: design-system/design_handoff_status_updates/Doc Portal Status.dc.html
   (markup contract: generateStatusPage in server/portal-status-ssr.ts).
   Panel width: the base .kb-panel (1180) — deliberately unified with the
   Knowledge/Tickets surfaces (the handoff's narrower 1000px panel was
   dropped); prose-y runs below carry their own measure caps instead. */
.kb-status-pad {
  padding: 44px 56px 64px;
}

/* Overall status hero — tinted with the worst active state. */
.kb-status-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  border-radius: 22px;
  padding: 30px 34px;
}
.kb-status-hero--green {
  background: rgba(26, 163, 74, 0.09);
  border: 1px solid rgba(26, 163, 74, 0.28);
}
.kb-status-hero--amber {
  background: rgba(249, 171, 0, 0.09);
  border: 1px solid rgba(249, 171, 0, 0.28);
}
.kb-status-hero--red {
  background: rgba(234, 63, 46, 0.09);
  border: 1px solid rgba(234, 63, 46, 0.28);
}
.kb-status-hero--blue {
  background: rgba(27, 87, 214, 0.09);
  border: 1px solid rgba(27, 87, 214, 0.28);
}
.kb-status-hero-main {
  display: flex;
  align-items: center;
  gap: 20px;
}
.kb-status-hero-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-status-hero--green .kb-status-hero-icon {
  background: rgba(26, 163, 74, 0.16);
  color: var(--kb-green);
}
.kb-status-hero--amber .kb-status-hero-icon {
  background: rgba(249, 171, 0, 0.16);
  color: var(--kb-amber);
}
.kb-status-hero--red .kb-status-hero-icon {
  background: rgba(234, 63, 46, 0.16);
  color: var(--kb-red);
}
.kb-status-hero--blue .kb-status-hero-icon {
  background: rgba(27, 87, 214, 0.16);
  color: var(--kb-blue);
}
.kb-status-hero-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 30px;
  letter-spacing: -0.5px;
  color: var(--kb-text);
  margin: 0;
}
.kb-status-hero-updated {
  font-size: 15px;
  color: var(--kb-text-3);
  margin-top: 4px;
}
.kb-status-hero-uptime {
  text-align: right;
  flex: none;
}
.kb-status-hero-pct {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 26px;
  line-height: 1;
}
.kb-status-hero-pct-note {
  font-size: 13px;
  color: var(--kb-text-3);
  margin-top: 5px;
}

/* Legacy manual status message — shown until the tenant clears it; incidents
   and maintenance drive the page now. */
.kb-status-message {
  margin-top: 16px;
  padding: 14px 18px;
  border-radius: 12px;
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--kb-text-2);
}

/* Services list. */
.kb-status-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 52px 0 6px;
}
.kb-status-h2 {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.3px;
  color: var(--kb-text);
  margin: 0;
}
.kb-status-section-hint {
  font-size: 13px;
  color: var(--kb-text-3);
}
.kb-status-service {
  padding: 20px 4px;
  border-top: 1px solid var(--kb-pill);
}
.kb-status-service-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.kb-status-service-name {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 16px;
  color: var(--kb-text);
}
.kb-status-service-pill {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  font-size: 13.5px;
}
.kb-status-service-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

/* 90-day uptime bar — 90 equal segments, one per UTC day. */
.kb-status-bar {
  display: flex;
  gap: 2px;
  margin-top: 14px;
}
.kb-status-seg {
  flex: 1 1 0;
  min-width: 0;
  height: 30px;
  border-radius: 2px;
}
.kb-status-seg--up {
  background: var(--kb-green);
  opacity: 0.82;
}
.kb-status-seg--degraded {
  background: var(--kb-amber);
}
.kb-status-seg--down {
  background: var(--kb-red);
}
.kb-status-seg--nodata {
  background: var(--kb-pill);
}
.kb-status-scale {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
  font-size: 12px;
  color: var(--kb-text-3);
}
.kb-status-scale-pct {
  color: var(--kb-green);
  font-weight: 600;
}
.kb-status-scale-pct--nodata {
  color: var(--kb-text-3);
  font-weight: 500;
}

/* Incident history. */
.kb-status-incidents-head {
  margin: 56px 0 6px;
}
.kb-status-incidents-sub {
  font-size: 14px;
  color: var(--kb-text-3);
  margin: 6px 0 0;
}
.kb-status-incident {
  padding: 26px 0;
  border-top: 1px solid var(--kb-pill);
}
.kb-status-incident-date {
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--kb-text-3);
  margin-bottom: 14px;
}
.kb-status-incident-title-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
}
.kb-status-incident-badge {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 12px;
  color: #fff;
  padding: 4px 11px;
  border-radius: 100px;
  flex: none;
}
.kb-status-incident-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 18px;
  letter-spacing: -0.2px;
  color: var(--kb-text);
}

/* Staged updates on a connected line, newest first. */
.kb-status-update {
  position: relative;
  padding: 0 0 20px 26px;
}
.kb-status-update--last {
  padding-bottom: 0;
}
.kb-status-update:not(.kb-status-update--last)::before {
  content: '';
  position: absolute;
  left: 5px;
  top: 14px;
  bottom: 0;
  width: 2px;
  background: var(--kb-pill);
}
.kb-status-update-dot {
  position: absolute;
  left: 0;
  top: 3px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  box-shadow: 0 0 0 3px var(--kb-surface);
}
.kb-status-update-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.kb-status-update-tag {
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 13.5px;
}
.kb-status-update-time {
  font-size: 12.5px;
  color: var(--kb-text-3);
}
.kb-status-update-body {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--kb-text-2);
  margin-top: 5px;
  /* Readable measure inside the full-width (1180) panel. */
  max-width: 760px;
}
.kb-status-empty {
  text-align: center;
  padding: 40px 0;
  font-size: 15px;
  color: var(--kb-text-3);
}

/* Active incidents + upcoming maintenance, above the services. Same incident
   anatomy as the history, so a visitor reads one shape everywhere. */
.kb-status-live .kb-status-incident:first-child {
  border-top: 1px solid var(--kb-pill);
}
.kb-status-window,
.kb-status-impact,
.kb-status-incident-affected {
  font-size: 14px;
  line-height: 1.5;
  color: var(--kb-text-2);
  margin: -8px 0 12px;
  max-width: 760px;
}
.kb-status-window {
  font-weight: 600;
  color: var(--kb-text);
}
.kb-status-incident-affected {
  color: var(--kb-text-3);
  margin-bottom: 20px;
}

/* Third-party services: providers the tenant depends on, grouped after its own. */
.kb-status-subhead {
  margin: 28px 0 6px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 16px;
  color: var(--kb-text);
}
.kb-status-subhead-hint {
  margin-left: 8px;
  font-family: inherit;
  font-weight: 400;
  font-size: 13px;
  color: var(--kb-text-3);
}
.kb-status-provider-link {
  margin-left: 10px;
  margin-right: auto;
  font-size: 12.5px;
  color: var(--kb-text-3);
  text-decoration: none;
}
.kb-status-provider-link:hover {
  color: var(--kb-text);
  text-decoration: underline;
}

/* ─── Changelog page ───────────────────────────────────────────────────────
   Spec: design-system/design_handoff_status_updates/Doc Portal
   Changelog.dc.html (markup: generateChangelogPage; filter behaviour:
   /knowledge/changelog.js). Panel width: the base .kb-panel (1180),
   unified with Knowledge/Tickets (handoff's 920px panel dropped); body
   text carries measure caps instead. */
.kb-changelog-pad {
  padding: 52px 60px 64px;
}
.kb-changelog-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 46px;
  line-height: 1.08;
  letter-spacing: -1.2px;
  color: var(--kb-text);
  margin: 20px 0 0;
}
.kb-changelog-intro {
  font-size: 18px;
  line-height: 1.55;
  color: var(--kb-text-3);
  margin: 14px 0 0;
  max-width: 560px;
}

/* Type filter pills — active = ink-on-text inversion. */
.kb-changelog-filters {
  display: flex;
  gap: 8px;
  margin-top: 30px;
}
.kb-changelog-filter {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 13.5px;
  padding: 8px 15px;
  border-radius: 100px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  color: var(--kb-text-2);
  cursor: pointer;
  white-space: nowrap;
}
.kb-changelog-filter.is-active {
  border-color: transparent;
  background: var(--kb-text);
  color: var(--kb-surface);
}

/* Release timeline — sticky date/version meta + bordered body column. */
.kb-changelog-entries {
  margin-top: 36px;
}
.kb-changelog-entry {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 28px;
  padding-bottom: 44px;
}
.kb-changelog-entry--last {
  padding-bottom: 8px;
}
.kb-changelog-entry[hidden] {
  display: none;
}
.kb-changelog-meta {
  position: sticky;
  top: 88px;
  align-self: start;
}
.kb-changelog-date {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--kb-text);
}
.kb-changelog-version {
  display: inline-block;
  margin-top: 8px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 12px;
  color: var(--kb-text-3);
  background: var(--kb-surface-2);
  border: 1px solid var(--kb-pill);
  border-radius: 100px;
  padding: 3px 10px;
}
.kb-changelog-body {
  position: relative;
  border-left: 2px solid var(--kb-pill);
  padding-left: 28px;
  padding-bottom: 2px;
}
.kb-changelog-dot {
  position: absolute;
  left: -7px;
  top: 5px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--kb-blue);
  box-shadow: 0 0 0 4px var(--kb-surface);
}
.kb-changelog-entry-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.3px;
  color: var(--kb-text);
  margin: 0;
}
.kb-changelog-summary {
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--kb-text-3);
  margin: 8px 0 12px;
  /* Readable measure inside the full-width (1180) panel. */
  max-width: 640px;
}
.kb-changelog-change {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 9px 0;
}
.kb-changelog-change[hidden] {
  display: none;
}
.kb-changelog-badge {
  flex: none;
  margin-top: 1px;
  font-family: var(--kb-heading-font-family);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  border: 1px solid currentColor;
  border-radius: 6px;
  padding: 2px 8px;
  min-width: 56px;
  text-align: center;
  background: transparent;
}
/* Tone-keyed badge colors — the SSR resolves each entry type's tone from the
   tenant taxonomy (changelog_types). Same fixed-in-both-themes palette as the
   .kb-tone-* utilities above. */
.kb-changelog-badge--tone-green { color: var(--kb-green); }
.kb-changelog-badge--tone-blue { color: var(--kb-blue); }
.kb-changelog-badge--tone-amber { color: var(--kb-amber); }
.kb-changelog-badge--tone-red { color: var(--kb-red); }
.kb-changelog-badge--tone-neutral { color: var(--kb-text-3); }
/* Legacy type-keyed classes — kept one release for CDN-cached HTML rendered
   before the taxonomy shipped (s-maxage/SWR window), then remove. */
.kb-changelog-badge--new { color: var(--kb-green); }
.kb-changelog-badge--improved { color: var(--kb-blue); }
.kb-changelog-badge--fixed { color: var(--kb-amber); }
.kb-changelog-badge--security { color: var(--kb-red); }
.kb-changelog-change-text {
  font-size: 15px;
  line-height: 1.55;
  color: var(--kb-text-2);
  max-width: 680px;
}
/* Legacy freeform entries render their sanitized rich-text body instead of
   typed change rows (no badges; visible only under "All"). */
.kb-changelog-legacy-body {
  font-size: 15px;
  line-height: 1.6;
  color: var(--kb-text-2);
  margin-top: 4px;
  max-width: 680px;
}
.kb-changelog-legacy-body p {
  margin: 8px 0;
}
.kb-changelog-legacy-body a {
  color: var(--kb-accent-ink);
}
.kb-changelog-empty {
  text-align: center;
  padding: 60px 0;
  font-size: 15px;
  color: var(--kb-text-3);
}
.kb-changelog-empty[hidden] {
  display: none;
}

/* ─── Subscribe (header chip + modal) ──────────────────────────────────────
   Chip renders in the status header variant; the modal shell is
   generateKBSubscribeModal, driven by /knowledge/subscribe.js with the
   login-modal open/close mechanics. */
.kb-subscribe-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  color: #fff;
  background: var(--kb-chip);
  border: none;
  border-radius: 100px;
  height: 40px;
  padding: 0 20px;
  cursor: pointer;
  flex: none;
}
.kb-subscribe-btn:hover {
  box-shadow: inset 0 0 0 99px rgba(255, 255, 255, 0.08);
}

.kb-subscribe-modal {
  position: fixed;
  inset: 0;
  z-index: 69;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.kb-subscribe-modal[hidden] {
  display: none;
}
.kb-subscribe-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity .25s ease;
}
.kb-subscribe-modal.is-open .kb-subscribe-scrim {
  opacity: 1;
}
.kb-subscribe-card {
  position: relative;
  width: min(440px, 100%);
  background: var(--kb-surface);
  border-radius: 20px;
  padding: 34px 32px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
  transform: translateY(14px) scale(0.98);
  opacity: 0;
  transition: transform .25s ease, opacity .25s ease;
}
.kb-subscribe-modal.is-open .kb-subscribe-card {
  transform: none;
  opacity: 1;
}
.kb-subscribe-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.kb-subscribe-mail-tile {
  width: 40px;
  height: 40px;
  border-radius: 11px;
  background: var(--kb-accent-soft);
  color: var(--kb-accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
.kb-subscribe-x {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--kb-surface-2);
  color: var(--kb-text-3);
}
.kb-subscribe-x:hover {
  box-shadow: inset 0 0 0 99px rgba(0, 0, 0, 0.06);
}
.kb-subscribe-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.3px;
  color: var(--kb-text);
  margin: 14px 0 0;
}
.kb-subscribe-subtext {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--kb-text-3);
  margin: 8px 0 20px;
}
.kb-subscribe-email {
  width: 100%;
  height: 48px;
  padding: 0 16px;
  border-radius: 12px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface-2);
  font-family: var(--kb-font-family);
  font-size: 15px;
  color: var(--kb-text);
  outline: none;
}
.kb-subscribe-email:focus {
  border-color: var(--kb-accent-ink);
}
.kb-subscribe-email.is-invalid {
  border-color: var(--kb-red);
}
.kb-subscribe-error {
  font-size: 13px;
  color: var(--kb-red);
  margin-top: 8px;
}
.kb-subscribe-error[hidden] {
  display: none;
}
.kb-subscribe-submit {
  width: 100%;
  height: 48px;
  margin-top: 16px;
  border-radius: 12px;
  border: none;
  background: var(--kb-accent);
  color: #fff;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  cursor: pointer;
}
.kb-subscribe-submit:hover {
  box-shadow: inset 0 0 0 99px rgba(0, 0, 0, 0.08);
}
.kb-subscribe-submit:disabled {
  opacity: 0.6;
  cursor: default;
}
.kb-subscribe-form-state[hidden],
.kb-subscribe-success-state[hidden] {
  display: none;
}
.kb-subscribe-success-state {
  text-align: center;
  padding: 12px 0 6px;
}
.kb-subscribe-check-badge {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(26, 163, 74, 0.14);
  color: var(--kb-green);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}
.kb-subscribe-done-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 20px;
  color: var(--kb-text);
  margin: 0;
}
.kb-subscribe-done-note {
  font-size: 14px;
  color: var(--kb-text-3);
  margin: 6px 0 0;
}
.kb-subscribe-done-btn {
  margin-top: 20px;
  height: 44px;
  padding: 0 26px;
  border-radius: 12px;
  border: none;
  background: var(--kb-surface-2);
  color: var(--kb-text);
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 14px;
  cursor: pointer;
}

/* ─── Status / Changelog responsive ────────────────────────────────────────
   Handoff breakpoints (900/720/560) — co-located because these classes
   appear nowhere else; the shared chrome keeps kb.css's own 1180/820
   switches. */
@media (max-width: 900px) {
  .kb-status-pad,
  .kb-changelog-pad {
    padding: 36px 26px 46px;
  }
  .kb-status-hero {
    flex-direction: column;
    align-items: flex-start;
    gap: 22px;
  }
  .kb-status-hero-uptime {
    text-align: left;
  }
  .kb-changelog-filters {
    overflow-x: auto;
  }
}
@media (max-width: 820px) {
  .kb-subscribe-btn-label {
    display: none;
  }
  .kb-subscribe-btn {
    padding: 0 14px;
  }
}
@media (max-width: 720px) {
  .kb-changelog-entry {
    grid-template-columns: 1fr;
  }
  .kb-changelog-meta {
    position: static;
    margin-bottom: 14px;
  }
  .kb-changelog-dot {
    display: none;
  }
  .kb-changelog-body {
    border-left: none;
    padding-left: 0;
  }
  .kb-changelog-title {
    font-size: 38px;
  }
}
@media (max-width: 560px) {
  .kb-status-service-head {
    flex-wrap: wrap;
    gap: 10px;
  }
  .kb-status-scale {
    display: none;
  }
}

/* ─── Footer ("Powered by ellocharlie", on the frame) ──────────────────────
   On article pages the cover's sticky range is bounded by .kb-reveal, so
   the cover can never reach the footer — but keep position:relative +
   z-index:1 defensively (the footer must always paint above the cover
   layer if the geometry ever changes). */
.kb-footer {
  position: relative;
  z-index: 1;
  background: var(--kb-footer-bg, var(--kb-frame));
  backdrop-filter: var(--kb-footer-blur, none);
  -webkit-backdrop-filter: var(--kb-footer-blur, none);
  /* Separated from the content above it. Flush against the page's white card
     the two read as one block, and over a background image (0403) there was no
     gap for the image to show through at all. */
  margin-top: 28px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 24px;
  padding: 40px 56px;
}
.kb-footer-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}
/* The clap mark rides a solid white tile (ink-on-white asset) so it reads
   on any tenant frame colour. */
.kb-footer-mark {
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: #fff;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.kb-footer-mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 2px;
}
.kb-footer-powered {
  font-size: 14px;
  color: color-mix(in srgb, var(--kb-footer-ink, #fff) 82%, transparent);
}
.kb-footer-brand:hover .kb-footer-powered {
  color: var(--kb-footer-ink, #fff);
}
.kb-footer-powered b {
  font-weight: 600;
  color: var(--kb-footer-ink, #fff);
}
.kb-footer-links {
  display: flex;
  align-items: center;
  gap: 26px;
}
.kb-footer-links a {
  font-size: 14px;
  color: color-mix(in srgb, var(--kb-footer-ink, #fff) 82%, transparent);
  text-decoration: none;
}
.kb-footer-links a:hover {
  color: var(--kb-footer-ink, #fff);
}

/* ─── Access gate (standalone page, no chrome) ─────────────────────────────
   generateKBGatePage: signin / sent / denied states over an optional
   tenant background image/colour (default = the frame). */
.kb-gate-body {
  margin: 0;
}
.kb-gate {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--kb-frame);
}
/* Background layer — image wins over colour; either fills the viewport. */
.kb-gate-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.kb-gate-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 420px;
  background: var(--kb-surface);
  border-radius: 20px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
  padding: 40px 32px;
  text-align: center;
}
.kb-gate-logo {
  height: 40px;
  width: auto;
  max-width: 220px;
  object-fit: contain;
  margin: 0 auto 20px;
  display: block;
}
.kb-gate-title {
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 24px;
  letter-spacing: -0.5px;
  color: var(--kb-text);
  margin: 0 0 8px;
}
.kb-gate-desc {
  color: var(--kb-text-3);
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
}
.kb-gate-form {
  margin-top: 24px;
  text-align: left;
}
.kb-gate-email {
  width: 100%;
  height: 46px;
  padding: 0 14px;
  border-radius: 11px;
  border: 1px solid var(--kb-pill);
  background: var(--kb-surface);
  font-family: var(--kb-font-family);
  font-size: 15px;
  color: var(--kb-text);
  outline: none;
}
.kb-gate-email:focus {
  border-color: var(--kb-accent-ink);
}
.kb-gate-submit {
  width: 100%;
  height: 48px;
  margin-top: 12px;
  border-radius: 12px;
  background: var(--kb-accent);
  border: none;
  cursor: pointer;
  font-family: var(--kb-heading-font-family);
  font-weight: 500;
  font-size: 15px;
  color: #fff;
}
.kb-gate-submit:hover {
  box-shadow: inset 0 0 0 99px rgba(0, 0, 0, 0.08);
}
.kb-gate-alt {
  margin-top: 18px;
  font-size: 13.5px;
}
.kb-gate-alt a {
  color: var(--kb-accent-ink);
}
@media (max-width: 480px) {
  .kb-gate-card {
    padding: 32px 20px;
    border-radius: 16px;
  }
}

/* ─── Collapsible site nav (article pages ≥1181) ───────────────────────────
   The article page ships collapsed: a slim rail sits in the left gutter and
   the nav itself is a floating panel parked off-screen, sliding in on hover
   or keyboard focus. Clicking the rail button pins it, which restores the
   pre-collapse layout exactly.

   Gating: EVERY rule below is scoped to html.kb-nav-collapsible (SSR emits it
   on the article page alone) AND to ≥1181. The first keeps .kb-flow padding
   off the .kb-panel pages that share that element; the second keeps all of it
   clear of the ≤1180 drawer, whose rules are less specific and would
   otherwise lose. Do not lift either guard.

   Geometry: .kb-reveal stops centring in the VIEWPORT and centres inside a
   band bounded by the rail on the left and the TOC rail on the right. That is
   the whole point — a viewport-centred box reserves the larger gutter on both
   sides, so shrinking only the left one buys no width at all. The band is
   expressed as three custom properties because .kb-cover-controls has to
   derive its fixed `right` from the same numbers.

   The default token values reproduce the pre-collapse layout byte for byte
   (260 + 260 = the old `calc(100% - 520px)`, cap 1080), which is what makes
   html.kb-nav-pinned a true no-op rather than an approximation. */
/* Hidden by default at EVERY width — the ≥1181 block below is the only thing
   that shows it, so drawer mode (≤1180) never has to hide it again. */
.kb-nav-rail {
  display: none;
}

@media (min-width: 1181px) {
  html.kb-nav-collapsible {
    /* Left: 44px offset + 210px rail + 6px. Right: 44px + 200px TOC + 16px. */
    --kb-gutter-left: 260px;
    --kb-gutter-right: 260px;
    --kb-pane-max: 1080px;
    /* 100vw (not 100%) to match the pre-existing .kb-cover-controls basis. */
    --kb-band: calc(100vw - var(--kb-gutter-left) - var(--kb-gutter-right));
    --kb-pane-w: min(var(--kb-pane-max), var(--kb-band));
  }
  /* Collapsed: the left gutter only has to clear the 44px rail (44 offset +
     44 width + 24 air), which is what licenses the higher pane cap. */
  html.kb-nav-collapsible.kb-nav-collapsed {
    --kb-gutter-left: 112px;
    --kb-pane-max: 1320px;
  }

  /* The band. .kb-reveal keeps its own `margin: 0 auto`, so it centres inside
     this padding box instead of inside the viewport. */
  html.kb-nav-collapsible .kb-flow {
    padding-left: var(--kb-gutter-left);
    padding-right: var(--kb-gutter-right);
  }
  /* …but the footer is a full-bleed band, not part of the article column, and
     it is a CHILD of .kb-flow — so that padding inset it on article pages
     while the .kb-panel pages (home, category, search) kept it edge to edge.
     Cancelling with the same two tokens is exact at both gutter widths, so
     pinning the nav (which widens --kb-gutter-left to 260px) needs nothing
     extra. The footer's own 40/56 padding still holds its content in. */
  html.kb-nav-collapsible .kb-footer {
    margin-left: calc(-1 * var(--kb-gutter-left));
    margin-right: calc(-1 * var(--kb-gutter-right));
  }
  html.kb-nav-collapsible .kb-reveal {
    width: min(var(--kb-pane-max), 100%);
  }
  /* The sheet carries its OWN cap (1000px), so widening the pane alone leaves
     it behind with a band of dead cream down its right-hand side. Derive it
     from the pane cap — 80px is the sheet's two 40px cream flanks — so the two
     can never again drift apart. */
  html.kb-nav-collapsible .kb-sheet {
    width: min(calc(var(--kb-pane-max) - 80px), calc(100% - 80px));
  }

  /* Sheet's right edge = right gutter + the band's leftover air on one side +
     the sheet's own 40px flank; +18px is the offset the design already used.
     Reproduces both of the old branches: 478px at 1920 (the calc branch) and
     318px at 1181 (the max() floor). */
  html.kb-nav-collapsible .kb-cover-controls {
    right: calc(
      var(--kb-gutter-right) + (var(--kb-band) - var(--kb-pane-w)) / 2 + 58px
    );
  }

  /* ── The rail ────────────────────────────────────────────────────────────
     Hit area spans 0→88px so a pointer heading for the nav doesn't have to
     find a 44px strip; the visible affordance is inset at 44px, on the frame
     colour, in line with the header's other round icon buttons. */
  html.kb-nav-collapsible.kb-nav-collapsed .kb-nav-rail {
    display: block;
    position: fixed;
    left: 0;
    top: 84px;
    width: 88px;
    padding-left: 44px;
    z-index: 23;
  }
  .kb-nav-toggle {
    width: 44px;
    height: 44px;
    background: color-mix(in srgb, var(--kb-rail-ink, #fff) 12%, transparent);
    color: var(--kb-rail-ink, #fff);
    transition: background .18s ease;
  }
  .kb-nav-rail:hover .kb-nav-toggle,
  .kb-nav-toggle:hover {
    background: color-mix(in srgb, var(--kb-rail-ink, #fff) 22%, transparent);
  }
  /* Hairline echoing .kb-article-list's own left border — a quiet "there is a
     list behind this" cue without spelling it out in the gutter. */
  .kb-nav-rail-line {
    display: block;
    width: 2px;
    height: 132px;
    margin: 14px auto 0;
    border-radius: 2px;
    background: color-mix(in srgb, var(--kb-rail-ink, #fff) 22%, transparent);
    transition: background .18s ease;
  }
  .kb-nav-rail:hover .kb-nav-rail-line {
    background: color-mix(in srgb, var(--kb-rail-ink, #fff) 40%, transparent);
  }

  /* ── The floating panel ──────────────────────────────────────────────────
     Same slide-from-transform contract as the ≤1180 drawer, at the desktop
     rail's offsets. It genuinely overlaps the content pane, so it needs an
     opaque frame-coloured background and a shadow — unlike the pinned rail,
     which sits in the gutter over the frame itself. */
  html.kb-nav-collapsible.kb-nav-collapsed .kb-sitenav {
    left: 0;
    top: 76px;
    width: 300px;
    max-height: calc(100vh - 100px);
    padding: 20px 24px 24px 44px;
    background: var(--kb-frame);
    border-radius: 0 20px 20px 0;
    box-shadow: 8px 0 40px rgba(0, 0, 0, 0.28);
    transform: translateX(-100%);
    opacity: 0;
    pointer-events: none;
    transition: transform .28s ease, opacity .18s ease;
    z-index: 24;
  }
  html.kb-nav-collapsible.kb-nav-collapsed.kb-nav-peeked .kb-sitenav {
    transform: translateX(0);
    opacity: 1;
    pointer-events: auto;
  }
  /* The one narrow surface. Everywhere else the tree wraps (see the base
     .kb-category-title rule) — full titles in the 300px peek panel are the
     reason the collapse exists. */
  html.kb-nav-collapsible.kb-nav-pinned .kb-category-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* ── Pinned ──────────────────────────────────────────────────────────────
     Band geometry reverts to the pre-collapse values (the token defaults
     above), so the pane and the TOC land exactly where they always did. The
     one deliberate difference: the toggle stays on screen, as a column head
     above the tree, and the tree starts 56px lower to make room. Hiding it
     here would make pinning a one-way door — there would be no control left
     to un-pin with. */
  html.kb-nav-collapsible.kb-nav-pinned .kb-nav-rail {
    display: block;
    position: fixed;
    left: 44px;
    top: 84px;
    width: 210px;
    padding-left: 0;
    z-index: 23;
  }
  html.kb-nav-collapsible.kb-nav-pinned .kb-nav-rail-line {
    display: none;
  }
  html.kb-nav-collapsible.kb-nav-pinned .kb-sitenav {
    top: 140px;
    max-height: calc(100vh - 164px);
  }
}

/* ─── Responsive ───────────────────────────────────────────────────────────── */

/* ≤1340 — header tightens: search pill → round icon, Ask label shortens,
   shortcut chips hide. */
@media (max-width: 1340px) {
  .kb-search-pill {
    min-width: 0;
    width: 40px;
    height: 40px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
    border-color: transparent;
  }
  .kb-search-pill .kb-pill-label,
  .kb-search-pill .kb-pill-shortcut {
    display: none;
  }
  .kb-ask-label--full {
    display: none;
  }
  .kb-ask-label--short {
    display: inline;
  }
  .kb-ask-pill .kb-pill-shortcut {
    display: none;
  }
}

/* ≤1180 — rails + centre nav retire; the site nav becomes the drawer;
   panels widen into the gutters. */
@media (max-width: 1180px) {
  .kb-header-nav {
    display: none;
  }
  .kb-menu-btn {
    display: inline-flex;
  }
  /* Liquid nav: with the links in the drawer the bar tears into two islands,
     pinned to the corners. */
  .kb-header[data-liquid-nav="compact"] .kb-header-inner {
    justify-content: space-between;
    padding: 0 10px;
  }
  .kb-header[data-liquid-nav="compact"] .kb-header-cluster--left {
    padding-left: 4px;
  }
  .kb-toc {
    display: none;
  }

  /* The site-nav element (all variants) becomes the slide-in drawer.
     z-order when open: drawer 60 > backdrop 55 > header 30. */
  .kb-sitenav,
  .kb-sitenav--drawer-only {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(300px, 82vw);
    max-height: 100vh;
    overflow-y: auto;
    background: var(--kb-frame);
    padding: 24px 24px 28px;
    transform: translateX(-100%);
    transition: transform .3s ease;
    z-index: 60;
    box-shadow: 8px 0 40px rgba(0, 0, 0, 0.28);
  }
  html.kb-drawer-open .kb-sitenav {
    transform: translateX(0);
  }
  .kb-drawer-close {
    display: flex;
    position: absolute;
    top: 18px;
    right: 18px;
    width: 34px;
    height: 34px;
    background: rgba(255, 255, 255, 0.14);
  }
  .kb-sitenav-surfaces {
    display: block;
    margin: 30px 0 20px;
    padding-bottom: 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  }

  .kb-reveal {
    width: calc(100% - 40px);
  }
  /* Sheet fills the pane — the cream flanks retire at this width. */
  .kb-sheet {
    width: 100%;
  }
  .kb-panel {
    width: calc(100% - 40px);
  }
  .kb-cover-controls {
    right: 34px;
  }
  .kb-footer {
    padding-left: 40px;
    padding-right: 40px;
  }

  .kb-cover-grid {
    padding: 80px 40px 96px 56px;
  }
  .kb-cover-media {
    flex-basis: 250px;
    width: 250px;
  }
  .kb-title {
    font-size: 50px;
  }
}

/* ≤820 — cover stacks single-column; article/home paddings compress; the
   Ask pill becomes a round icon. */
@media (max-width: 820px) {
  .kb-header-inner {
    padding: 0 18px;
  }
  /* Kept as an icon, not hidden: nothing else opens the assistant, and a phone
     has no ⌘I. */
  .kb-ask-pill {
    width: 40px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
  }
  .kb-ask-pill .kb-pill-label {
    display: none;
  }

  .kb-cover {
    height: auto;
  }
  .kb-cover-grid {
    flex-direction: column;
    align-items: stretch;
    padding: 80px 24px 44px;
    gap: 0;
  }
  .kb-title {
    font-size: 36px;
    line-height: 1.1;
    letter-spacing: -0.8px;
  }
  .kb-cover-summary {
    margin-top: 24px;
    max-width: none;
  }
  .kb-cover-media {
    flex: none;
    align-self: center;
    width: 238px;
    margin: 26px auto 6px;
  }
  .kb-sheet {
    margin-top: -40px;
  }
  .kb-article {
    padding: 44px 24px 96px;
  }
  .kb-prose h1,
  .kb-prose h2 {
    font-size: 30px;
    line-height: 1.1;
    letter-spacing: -0.6px;
    margin-top: 64px;
  }
  .kb-prose h3 {
    font-size: 24px;
    margin-top: 48px;
  }
  .kb-prose blockquote {
    font-size: 22px;
  }
  .kb-feedback {
    padding: 26px 24px;
  }

  .kb-home-hero {
    padding: 56px 24px 44px;
  }
  .kb-home-title {
    font-size: 38px;
    letter-spacing: -1px;
  }
  .kb-home-tiles {
    padding: 38px 24px 96px;
  }
  .kb-catpage-hero {
    padding: 48px 24px;
  }
  .kb-catpage-title {
    font-size: 32px;
  }
  .kb-catpage-list {
    padding: 24px 16px 80px;
  }
}

/* ≤560 — narrowest: panels nearly full-bleed, tiles single-column. The header
   is [☰ tile] ··· [search, assistant, theme, Login]: the tenant name hides and
   the language switcher moves into the drawer, so search stays reachable on
   every page (it used to retire here, leaving articles with no search). */
@media (max-width: 560px) {
  .kb-header-inner {
    padding: 0 12px;
  }
  .kb-header-cluster--left {
    gap: 8px;
  }
  .kb-header-cluster--right {
    gap: 6px;
  }
  /* Visually hidden, not display:none — it is the logo link's name. */
  .kb-logo-name {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .kb-header .kb-lang-switcher {
    display: none;
  }
  .kb-sitenav-lang {
    display: block;
  }
  .kb-login-btn,
  .kb-auth-link {
    padding: 0 16px;
  }

  /* The bottom dock (styles above). It carries the sections and the page's main
     action, so the header hands those over; ☰ goes where its drawer would only
     repeat the dock (server flag), and the drawer drops its section links. */
  .kb-dock {
    position: fixed;
    left: 50%;
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: calc(100vw - 16px);
  }
  .kb-header[data-has-dock] .kb-search-pill,
  .kb-header[data-has-dock] .kb-subscribe-btn {
    display: none;
  }
  .kb-header[data-has-dock][data-drawer-surfaces-only] .kb-menu-btn {
    display: none;
  }
  .kb-header[data-has-dock][data-drawer-surfaces-only][data-liquid-nav="compact"] .kb-header-cluster--left {
    padding-left: 8px;
  }
  .kb-sitenav[data-has-dock] {
    padding-top: 64px;
  }
  .kb-sitenav[data-has-dock] .kb-sitenav-surfaces {
    display: none;
  }
  /* Nothing at the bottom of the page may end up under the dock. */
  body:has(.kb-dock) .kb-footer {
    padding-bottom: calc(40px + 70px + env(safe-area-inset-bottom, 0px));
  }
  body:has(.kb-dock) .kb-scroll-cue {
    bottom: calc(28px + 70px + env(safe-area-inset-bottom, 0px));
  }

  .kb-reveal,
  .kb-panel {
    width: calc(100% - 18px);
  }
  .kb-footer {
    padding-left: 24px;
    padding-right: 24px;
  }
  .kb-title {
    font-size: 31px;
  }
  .kb-home-title {
    font-size: 31px;
  }
  .kb-tile-grid {
    grid-template-columns: 1fr;
  }
  .kb-cover-controls {
    top: 150px;
    right: 20px;
  }
}

/* ≤480 — assistant panel goes full-width. */
@media (max-width: 480px) {
  .kb-assistant-panel {
    width: 100vw;
  }
}

/* <360 — without the dock, the smallest phones can't fit the whole right
   cluster: Login, search and the assistant win over the theme toggle (the page
   still follows the device setting, or a choice saved earlier — see
   theme-flash.js). */
@media (max-width: 359px) {
  /* Only without the dock: with it, Search / Subscribe have already left the
     header, so the toggle fits — and on Status / Changelog it is the right
     cluster's only button, whose loss left an empty island. */
  .kb-header:not([data-has-dock]) .kb-theme-toggle {
    display: none;
  }
  /* Five labelled tabs plus the round button need ~330px: icons only here. */
  .kb-dock-label {
    display: none;
  }
  .kb-dock-tab {
    min-width: 44px;
    padding: 0 6px;
  }
}

/* ─── Reduced motion ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  html {
    scroll-behavior: auto;
  }
  .kb-sitenav,
  .kb-nav-toggle,
  .kb-nav-rail-line,
  .kb-assistant-panel,
  .kb-search-modal-card,
  .kb-login-card,
  .kb-drawer-backdrop,
  .kb-toc-indicator,
  .kb-category-icon,
  .kb-category-content,
  .kb-tile {
    transition: none !important;
  }
  .kb-tile:hover {
    transform: none;
  }
  .kb-header-nav a[data-has-update="true"]::after,
  .kb-assistant-typing i {
    animation: none !important;
  }
}

/* ─── Print ────────────────────────────────────────────────────────────────── */
@media print {
  body {
    background: #fff;
  }
  .kb-header,
  .kb-dock,
  .kb-sitenav,
  .kb-nav-rail,
  .kb-toc,
  .kb-menu-btn,
  .kb-cover-controls,
  .kb-scroll-cue,
  .kb-drawer-backdrop,
  .kb-search-modal,
  .kb-assistant,
  .kb-login-modal,
  .kb-footer,
  .kb-feedback,
  .kb-cover-media {
    display: none !important;
  }
  .kb-flow {
    padding-top: 0;
  }
  .kb-reveal {
    width: 100%;
    background: #fff;
    border-radius: 0;
  }
  .kb-cover {
    position: static;
    height: auto;
    width: 100%;
    border-radius: 0;
    background: #fff;
  }
  .kb-cover-grid {
    padding: 0;
  }
  .kb-sheet {
    position: static;
    width: 100%;
    margin: 0;
    border-radius: 0;
    min-height: 0;
    box-shadow: none;
  }
  .kb-article {
    padding: 24px 0;
  }
  .kb-panel {
    width: 100%;
    border-radius: 0;
    min-height: 0;
  }
}
