/* The knowledge base at /guide.
 *
 * One set of rules serves two shells, and the shell decides both the frame and
 * the reading size:
 *
 * - .kb--app, inside the app (base.html). The guide is a page of the product,
 *   so it is set at the product's size -- 14px body, the same as every Settings
 *   row -- and framed in a bordered panel, because the app's header and sidebar
 *   have no edges of their own for content to sit against.
 * - .kb--public, the standalone site (guide_base.html). A document site, set
 *   larger for reading, on an open page with a glow behind it.
 *
 * Either way there is exactly one navigation column, and it belongs to the
 * guide. It used to open inside the app's own sidebar; see guide_tree.html for
 * why it does not any more.
 *
 * Three things this file deliberately does NOT do:
 *
 * 1. No second navigation rail. The guide used to stand up its own sidebar
 *    beside the app's, plus an "On this page" rail on the right -- three
 *    columns of navigation around one article. The tree carries all of it now:
 *    sections, articles, and the current article's own headings.
 * 2. No disclosure widget anywhere. An earlier version hid the article list in
 *    a closed <details> that CSS re-showed on desktop; Chrome overrules that
 *    through ::details-content, so the whole sidebar rendered and was
 *    invisible. Every section here is simply open.
 * 3. It does not redefine --bg/--ink/--panel under prefers-color-scheme.
 *    App-wide dark mode is unbuilt (DARK_MODE_PLAN.md), so that block made the
 *    guide the only dark surface in the product -- and inside the app shell it
 *    would have dragged the sidebar dark with it.
 */

/* ---------------------------------------------------------------- public shell */

.knowledge-base-body {
  min-height: 100dvh;
  background: var(--bg);
  color: var(--ink);
}

/* Takes the glow's overflow. `clip`, never `hidden`: hidden would make an
   ancestor a scroll container and break the sticky columns. */
.knowledge-base-body,
.app-main:has(> .kb) {
  overflow-x: clip;
}

.knowledge-base-header {
  position: sticky;
  top: 0;
  z-index: 10;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(12px);
}

.knowledge-base-header-inner {
  display: flex;
  max-width: 1320px;
  min-height: 64px;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 auto;
  padding: 0 28px;
}

.knowledge-base-header-left {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
}

.knowledge-base-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  font-size: var(--type-body-md);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  text-decoration: none;
}

.knowledge-base-brand img {
  border-radius: var(--radius-control);
}

.knowledge-base-crumb {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
  font-size: var(--type-body-md);
}

.knowledge-base-app-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: var(--radius-control);
  color: var(--muted);
  font-size: var(--type-body-sm);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  transition: background 140ms cubic-bezier(0.2, 0.8, 0.2, 1), color 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.knowledge-base-app-link.is-primary {
  background: var(--button-soft);
  color: var(--button-hover);
}

.knowledge-base-app-link.is-primary:hover,
.knowledge-base-app-link.is-primary:focus-visible {
  background: var(--button-container);
}

/* The keyboard-only escape hatch past the tree. Both shells carry one. */
.kb-skip {
  position: absolute;
  left: -9999px;
  z-index: 30;
  padding: 10px 16px;
  border-radius: var(--radius-control);
  background: var(--button);
  color: #ffffff;
  font-size: var(--type-body-sm);
  font-weight: 600;
  text-decoration: none;
}

.kb-skip:focus {
  left: 24px;
  top: 12px;
}

/* --------------------------------------------------- the location, in the header */

/* Matches .app-topbar h1's metrics -- see the note in guide_app_page.html for
   why this one is a <p>. The section is the quieter half so the pair reads as
   one location and not as two titles. */
.app-topbar .kb-topbar-title {
  display: flex;
  min-width: 0;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  overflow: hidden;
  color: var(--ink);
  font-size: var(--type-body-lg);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.kb-topbar-sep {
  color: var(--surface-container-highest);
  font-weight: 400;
}

.kb-topbar-section {
  overflow: hidden;
  color: var(--muted);
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ the layout */

/* The reading scale lives here as tokens rather than in the prose rules,
   because the two shells read at different sizes and everything else about
   them is identical. Defaults are the document-site scale; .kb--app steps the
   whole thing down to the app's. */
.kb {
  position: relative;
  --kb-h1: clamp(1.625rem, 1.35rem + 0.9vw, 1.875rem);
  --kb-lead: var(--type-body-lg);
  --kb-h2: var(--type-headline-sm);
  --kb-h3: var(--type-body-lg);
  --kb-body: var(--type-body-md);
  --kb-leading: 1.75;
  --kb-para-gap: 16px;
  --kb-list-gap: 8px;
  --kb-h2-gap: 52px;
  --kb-h3-gap: 30px;
}

/* Signed out the tree is the left column, so this shell owns the grid.
   ``isolation`` is here rather than on .kb because it exists for the glow,
   which is this shell's alone. On .kb it also made the app's card a stacking
   context, which trapped the Contents drawer inside it -- z-index 60 on the
   drawer could not beat a scrim outside a context the card had created. */
.kb--public {
  display: grid;
  isolation: isolate;
  grid-template-columns: 236px minmax(0, 1fr);
  column-gap: clamp(28px, 3.4vw, 56px);
  max-width: 1180px;
  margin: 0 auto;
  padding: clamp(24px, 3.4vw, 40px) 28px 88px;
}

.kb--public .kb-side {
  position: sticky;
  top: 88px;
  align-self: start;
  max-height: calc(100dvh - 112px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--surface-container-highest) transparent;
}

/* ------------------------------------------------------- the guide, in the app */

/* One panel holding both columns, matching the Settings card exactly -- same
   border, radius and shadow -- because that is what "a page of this app" looks
   like. `clip`, never `hidden`: hidden would make this a scroll container and
   the sticky tree inside it would stop sticking.

   960px, a little wider than Settings' 760, because it is carrying two columns
   rather than one. */
.kb--app {
  display: grid;
  grid-template-columns: 236px minmax(0, 1fr);
  max-width: 960px;
  margin: 0 auto 48px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.06);
  overflow: clip;
}

/* The tint is what says "navigation" now that this is not the app's sidebar;
   it is the same wash the Settings card uses for its own section headers.
   The CELL is tinted and stretches; the tree inside it is the sticky part. A
   sticky element cannot also stretch, so tinting the tree itself would have
   left the column white below wherever the list happened to end. */
.kb--app .kb-side {
  border-right: 1px solid var(--line);
  background: var(--panel-soft);
}

.kb--app .kb-tree {
  position: sticky;
  top: 84px;
  max-height: calc(100dvh - 108px);
  margin: 0;
  padding: 18px 12px 22px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--surface-container-highest) transparent;
}

.kb--app .kb-main {
  padding: 26px 34px 38px;
}

.kb-main {
  min-width: 0;
  /* Roughly 68 characters. The column is left-aligned under the header rather
     than centred in whatever is left over: centring moved the text away from
     the navigation it belongs to every time the window changed width. */
  max-width: 44rem;
}

/* In the app the cell is the column, so the measure is set on the article. */
.kb--app .kb-main {
  max-width: none;
}

.kb--app .kb-article {
  max-width: 35rem;
}

/* Settings' 14px body, and a heading ramp that ends just above the topbar's
   own 18px title rather than 12px above it. The guide used to be set at 16/1.75
   inside the app, which made it the largest text in the product. */
.kb--app {
  --kb-h1: 1.375rem;
  --kb-lead: var(--type-body-md);
  --kb-h2: 1.0625rem;
  --kb-h3: 0.9375rem;
  --kb-body: var(--type-body-sm);
  --kb-leading: 1.65;
  --kb-para-gap: 12px;
  --kb-list-gap: 6px;
  --kb-h2-gap: 34px;
  --kb-h3-gap: 22px;
}

.kb--app .kb-article-nav {
  margin-top: 44px;
}

.kb--app .kb-article-nav-title {
  font-size: var(--type-body-sm);
}

/* --------------------------------------------------------------------- the glow */

/* A glow, not a gradient: the light pools near the top of the reading area and
   falls off in every direction, so nothing draws a horizon across the page.
   The hue travels emerald -> cyan -> periwinkle between three widely spaced
   poles, blurred hard enough that they merge into one field rather than
   mottling where they overlap (the failure landing.css documents).
   The emerald pole sits INSIDE the column, not on the sidebar's edge: anchored
   at the edge it made that edge the brightest line on the page.
   Public shell only: behind the app's opaque panel it would show as a smudge
   around the card's edges and nowhere else. */
.kb--public::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -170px;
  left: -8%;
  right: -12%;
  height: 760px;
  pointer-events: none;
  background:
    radial-gradient(34% 40% at 28% 34%, rgba(52, 211, 153, 0.30), rgba(52, 211, 153, 0) 70%),
    radial-gradient(36% 42% at 56% 24%, rgba(103, 232, 249, 0.19), rgba(103, 232, 249, 0) 72%),
    radial-gradient(34% 40% at 94% 46%, rgba(147, 197, 253, 0.26), rgba(147, 197, 253, 0) 70%);
  filter: blur(80px);
}

/* ------------------------------------------- the Contents bar and its drawer */

/* All three are drawer-only furniture. Off at every width by default; the
   stacked-width block near the bottom of this file turns them on, and only
   once knowledge-base.js has marked the frame with data-drawer. */
.kb-drawer-bar,
.kb-side-head,
.kb-scrim {
  display: none;
}

.kb-drawer-button {
  display: flex;
  width: 100%;
  min-height: 48px;
  align-items: center;
  gap: 10px;
  border: 0;
  background: none;
  color: var(--button-hover);
  font-family: var(--font-ui);
  font-size: var(--type-body-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.kb-drawer-button svg {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

.kb-drawer-count {
  overflow: hidden;
  color: var(--muted);
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.kb-drawer-count::before {
  content: "\00b7";
  margin-right: 8px;
  color: var(--surface-container-highest);
}

.kb-side-head-title {
  color: var(--ink);
  font-size: var(--type-body-sm);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.kb-drawer-close {
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.kb-drawer-close svg {
  width: 20px;
  height: 20px;
}

/* ------------------------------------------------------------------- the tree */

.kb-tree {
  display: block;
  margin: 2px 0 4px;
}

/* Sentence case, not the small caps the rest of the app labels groups with:
   test_guide_labels_are_not_small_caps holds the line that uppercase strips
   the word shapes a reader scans by, and with every section open there are now
   four of these to scan past rather than one. */
.kb-tree-group {
  padding: 0 10px;
  margin: 20px 0 4px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.kb-tree-group:first-child {
  margin-top: 0;
}

.kb-tree-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.kb-tree-article {
  display: block;
  padding: 6px 10px;
  border-radius: var(--radius-control);
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.35;
  text-decoration: none;
  transition: background 140ms cubic-bezier(0.2, 0.8, 0.2, 1), color 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.kb-tree-article:hover,
.kb-tree-article:focus-visible {
  background: var(--panel);
  color: var(--button-hover);
}

.kb--public .kb-tree-article:hover,
.kb--public .kb-tree-article:focus-visible {
  background: var(--panel-soft);
}

.kb-tree-article.is-active {
  background: var(--button-soft);
  color: var(--button-hover);
  font-weight: 600;
}

/* The article's own sections -- where the separate "On this page" rail went. */
.kb-tree-headings {
  display: grid;
  margin: 2px 0 6px;
  padding: 0 0 0 16px;
  list-style: none;
}

.kb-tree-heading {
  display: block;
  padding: 4px 8px 4px 12px;
  border-left: 1px solid var(--line);
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.35;
  text-decoration: none;
  transition: color 140ms cubic-bezier(0.2, 0.8, 0.2, 1), border-color 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.kb-tree-heading:hover,
.kb-tree-heading:focus-visible {
  color: var(--ink);
}

/* Set by knowledge-base.js as the reader moves down the article. Without JS
   these are still working jump links. */
.kb-tree-heading.is-current {
  border-left-color: var(--button);
  color: var(--button-hover);
  font-weight: 600;
}

/* --------------------------------------------------------------- the article */

/* Every size here comes from the --kb-* tokens at the top of the file, so the
   in-app guide can read at the app's size and the public one at a document
   site's without a second copy of these rules. */
.knowledge-base-prose h1 {
  margin: 0;
  color: var(--ink);
  font-size: var(--kb-h1);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.2;
  text-wrap: balance;
}

.knowledge-base-prose {
  font-size: var(--kb-body);
  line-height: var(--kb-leading);
}

.knowledge-base-prose > h1 + p {
  margin-top: var(--kb-para-gap);
  color: var(--muted);
  font-size: var(--kb-lead);
  line-height: 1.6;
}

.knowledge-base-prose h2 {
  margin: var(--kb-h2-gap) 0 0;
  color: var(--ink);
  font-size: var(--kb-h2);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
  scroll-margin-top: 96px;
  text-wrap: balance;
}

.knowledge-base-prose h3 {
  margin: var(--kb-h3-gap) 0 0;
  color: var(--ink);
  font-size: var(--kb-h3);
  font-weight: 600;
  line-height: 1.4;
  scroll-margin-top: 96px;
}

.knowledge-base-prose p,
.knowledge-base-prose li {
  color: var(--muted);
}

.knowledge-base-prose p {
  margin: var(--kb-para-gap) 0 0;
}

.knowledge-base-prose strong {
  color: var(--ink);
  font-weight: 600;
}

.knowledge-base-prose ul,
.knowledge-base-prose ol {
  margin: var(--kb-para-gap) 0 0;
  padding-left: 1.25rem;
}

.knowledge-base-prose ul li::marker {
  color: var(--surface-container-highest);
}

/* Steps, not decoration -- an ordered list's numbers are content. */
.knowledge-base-prose ol li::marker {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.knowledge-base-prose li + li {
  margin-top: var(--kb-list-gap);
}

.knowledge-base-prose a {
  color: var(--button-hover);
  font-weight: 500;
  text-decoration-color: color-mix(in srgb, var(--button-hover) 35%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.knowledge-base-prose a:hover {
  text-decoration-color: currentColor;
}

/* Screenshots and the strategy chart. Elevation is declared once -- a hairline,
   no shadow -- so a wide light image does not sit under a ghost edge.
   Every one is a link to the full-size file; see _AnchoredRenderer.image. */
.kb-figure {
  display: block;
  margin: calc(var(--kb-para-gap) + 10px) 0 0;
}

.kb-figure-link {
  position: relative;
  display: block;
  border-radius: var(--radius-panel);
  cursor: zoom-in;
  overflow: hidden;
}

.knowledge-base-prose img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
}

.kb-figure-zoom {
  position: absolute;
  right: 10px;
  bottom: 10px;
  display: grid;
  width: 30px;
  height: 30px;
  place-items: center;
  border-radius: var(--radius-control);
  background: color-mix(in srgb, var(--navy) 72%, transparent);
  color: #ffffff;
  transition: background 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.kb-figure-link:hover .kb-figure-zoom,
.kb-figure-link:focus-visible .kb-figure-zoom {
  background: var(--navy);
}

.kb-figure-zoom .ct-symbol {
  width: 1rem;
  height: 1rem;
  font-size: 1rem !important;
}

.knowledge-base-prose table {
  display: block;
  width: 100%;
  margin-top: 20px;
  border-collapse: collapse;
  overflow-x: auto;
  font-size: var(--type-body-sm);
}

.knowledge-base-prose th,
.knowledge-base-prose td {
  padding: 11px 14px 11px 0;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  text-align: left;
  vertical-align: top;
}

.knowledge-base-prose th {
  color: var(--ink);
  font-size: var(--type-body-sm);
  font-weight: 600;
}

.knowledge-base-prose tbody td:first-child {
  color: var(--ink);
  font-weight: 600;
}

/* ------------------------------------------------------------- boxed rules */

/* Written as ``:::{rule} Rule 1`` in the Markdown -- raw HTML in an article is
   escaped, so this is the sanctioned way to ask for a box. See _RuleCallout in
   guide_content.py.

   The number rides a band across the head of the card instead of leading the
   heading, so the sidebar entry and the anchor keep the rule's own words:
   "Never gamble with real money", not "Rule #1: Never Gamble With Real Money",
   which reads as a filename in a 200px rail. */
.kb-rule {
  margin: var(--kb-h2-gap) 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--panel);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  overflow: hidden;
}

.kb-rule-band {
  margin: 0;
  padding: 11px 22px;
  border-bottom: 1px solid var(--button-container);
  background: var(--button-soft);
  color: var(--button-hover);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.kb-rule-body {
  padding: 20px 22px 24px;
}

/* The heading is the card's first line. Its usual 52px lead-in is the gap
   above the card, which the card itself already carries. */
.knowledge-base-prose .kb-rule-body > :first-child {
  margin-top: 0;
}

/* --------------------------------------------------------------- step lists */

/* ``:::{steps}`` around an ordered list. Opt-in rather than a restyle of every
   ol in the guide: most of them are short runs inside a section, and a column
   of numbered chips would make each one look like the article's spine. */
.kb-steps ol {
  display: grid;
  gap: 18px;
  margin: var(--kb-para-gap) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: kb-step;
}

/* The chip is positioned out of the flow rather than made a flex sibling: a
   flex item is created for every child, so a step opening with a bold clause
   put that clause in a column of its own and ran the rest beside it. */
.kb-steps li {
  position: relative;
  padding-left: 44px;
  counter-increment: kb-step;
}

/* The grid's gap owns the spacing between steps. */
.kb-steps li + li {
  margin-top: 0;
}

.kb-steps li::before {
  content: counter(kb-step);
  position: absolute;
  top: 1px;
  left: 0;
  display: grid;
  width: 28px;
  height: 28px;
  place-items: center;
  border-radius: 999px;
  background: var(--button-container);
  color: var(--button-hover);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Both blocks step down with the rest of the type inside the app shell. */
.kb--app .kb-rule-band {
  padding: 9px 18px;
  font-size: 12.5px;
}

.kb--app .kb-rule-body {
  padding: 16px 18px 20px;
}

.kb--app .kb-steps ol {
  gap: 14px;
}

.kb--app .kb-steps li {
  padding-left: 36px;
}

.kb--app .kb-steps li::before {
  width: 24px;
  height: 24px;
  font-size: 12px;
}

/* ------------------------------------------------------- article-to-article nav */

.kb-article-nav {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-top: 64px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

.kb-article-nav-link {
  display: grid;
  gap: 4px;
  color: var(--ink);
  text-decoration: none;
}

.kb-article-nav-link.is-next {
  grid-column: 2;
  justify-items: end;
  text-align: right;
}

.kb-article-nav-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
  font-size: var(--type-body-sm);
  font-weight: 500;
}

.kb-article-nav-title {
  font-size: var(--type-body-md);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.35;
  transition: color 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.kb-article-nav-link:hover .kb-article-nav-title,
.kb-article-nav-link:focus-visible .kb-article-nav-title {
  color: var(--button-hover);
}

.kb-article-nav .ct-symbol {
  font-size: 1rem !important;
  width: 1rem;
  height: 1rem;
  transition: transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.kb-article-nav-link.is-prev:hover .ct-symbol {
  transform: translateX(-2px);
}

.kb-article-nav-link.is-next:hover .ct-symbol {
  transform: translateX(2px);
}

/* --------------------------------------------------------- browser surfaces */

.kb ::selection,
.kb-tree ::selection,
.knowledge-base-header ::selection {
  background: var(--button-container);
  color: var(--button-hover);
}

.kb--public .kb-side::-webkit-scrollbar,
.kb--app .kb-tree::-webkit-scrollbar {
  width: 8px;
}

.kb--public .kb-side::-webkit-scrollbar-thumb,
.kb--app .kb-tree::-webkit-scrollbar-thumb {
  border: 2px solid transparent;
  border-radius: 999px;
  background: var(--surface-container-highest);
  background-clip: content-box;
}

.kb a:focus-visible,
.kb-tree a:focus-visible,
.knowledge-base-header a:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Programmatic focus from the skip link only -- it must not draw a ring the
   way a keyboard-focused control does. */
.kb-main:focus {
  outline: none;
}

/* ------------------------------------------------------------------ responsive */

/* Two columns stop fitting well before the app sidebar gives its 240px back:
   at 1080 the article column is already down to about 400px. Article first,
   tree under it -- "what else is there" is an end-of-page question. */
@media (max-width: 1080px) {
  .kb--app {
    grid-template-columns: minmax(0, 1fr);
  }

  .kb--app .kb-main {
    order: 1;
    padding: 24px 20px 30px;
  }

  .kb--app .kb-article {
    max-width: none;
  }

  .kb--app .kb-side {
    order: 2;
    border-right: 0;
    border-top: 1px solid var(--line);
  }

  .kb--app .kb-tree {
    position: static;
    max-height: none;
    padding: 18px 14px 22px;
    overflow: visible;
  }

  /* --- and, with the script running, the tree becomes a drawer instead --- */

  /* The bar sits under the app topbar, which is still sticky at this width.
     Full-bleed, so it reads as a bar and not as a control floating in the
     page's gutter. */
  .kb-drawer-bar {
    position: sticky;
    top: 64px;
    z-index: 16;
    display: block;
    margin: -4px calc(-1 * clamp(20px, 3vw, 40px)) 16px;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    background: var(--panel);
  }

  .kb-drawer-bar[hidden] {
    display: none;
  }

  .kb-drawer-button {
    padding: 0 clamp(20px, 3vw, 40px);
  }

  /* The same element that was the foot of the card, lifted out of the flow.
     Nothing is duplicated and nothing is moved in the DOM: without the
     attribute (no script) these rules simply do not apply and the tree stays
     where the grid put it. */
  /* The card clips its own rounded corners, which is right while the tree is
     a tinted block at its foot -- and wrong the moment that block becomes a
     fixed drawer, because `clip` takes fixed descendants with it. With the
     drawer there is no tint inside the card to clip. */
  .kb--app[data-drawer] {
    overflow: visible;
  }

  .kb--app[data-drawer] .kb-side {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 60;
    width: min(320px, 86vw);
    border-top: 0;
    border-right: 1px solid var(--line);
    background: var(--panel);
    box-shadow: 0 0 40px rgba(15, 23, 42, 0.28);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* visibility, not opacity: a translated-off-screen panel is still in the
       tab order, and the first Tab on the page would land inside it. */
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1), visibility 200ms;
  }

  .kb--app[data-drawer][data-drawer-open] .kb-side {
    visibility: visible;
    transform: none;
  }

  .kb--app[data-drawer] .kb-side-head {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 8px 10px 18px;
    border-bottom: 1px solid var(--line);
    background: var(--panel);
  }

  .kb--app[data-drawer] .kb-tree {
    padding: 14px 12px 20px;
  }

  /* The one place the tree is a thumb target rather than a pointer target. */
  .kb--app[data-drawer] .kb-tree-article {
    min-height: 44px;
    padding: 12px 10px;
    font-size: var(--type-body-sm);
  }

  .kb--app[data-drawer] .kb-tree-heading {
    min-height: 40px;
    padding: 10px 8px 10px 12px;
    font-size: 13px;
  }

  .kb--app[data-drawer][data-drawer-open] ~ .kb-scrim {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: block;
    background: color-mix(in srgb, var(--navy) 45%, transparent);
  }
}

@media (max-width: 900px) {
  /* No sticky topbar at this width, so the bar pins to the top of the window
     itself -- and the page's padding is 16px rather than the clamp. */
  .kb-drawer-bar {
    top: 0;
    margin: -4px -16px 16px;
  }

  .kb-drawer-button {
    padding: 0 16px;
  }
}

@media (max-width: 980px) {
  .kb--public {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
  }

  /* Article first; the tree follows it, where "what else is there" belongs. */
  .kb--public .kb-side {
    position: static;
    order: 2;
    max-height: none;
    margin-top: 48px;
    padding-top: 24px;
    border-top: 1px solid var(--line);
  }

  .kb--public .kb-main {
    order: 1;
    max-width: none;
  }
}

@media (max-width: 720px) {
  .kb--public {
    padding: 20px 16px 72px;
  }

  /* The card keeps its edge but loses the inset it cannot afford. */
  .kb--app {
    margin-bottom: 32px;
  }

  .kb--app .kb-main {
    padding: 20px 16px 26px;
  }

  .knowledge-base-header-inner {
    min-height: 56px;
    padding: 0 16px;
  }

  .knowledge-base-brand {
    font-size: var(--type-body-sm);
  }

  .knowledge-base-brand img {
    width: 28px;
    height: 28px;
  }

  /* No room for it beside the wordmark and the action; the tree at the foot of
     the page still says where you are. */
  .knowledge-base-crumb {
    display: none;
  }

  .knowledge-base-prose h2 {
    margin-top: 40px;
  }

  .kb-article-nav {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .kb-article-nav-link.is-next {
    grid-column: 1;
    justify-items: start;
    text-align: left;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kb *,
  .kb-tree *,
  .kb-side,
  .kb-drawer-bar *,
  .knowledge-base-header * {
    transition-duration: 1ms !important;
  }
}
