/* The documentation surface: a persistent three-column reference shell.
 *
 * This replaces documentation.css, documentation-plans.css and documentation-responsive.css, which
 * between them carried fourteen bespoke box components - a mode card, a paths grid, a journey, a
 * workflow map, a foundation strip, a domain example, a billing route, a price grid, an action
 * list, a scope aside - each with its own paint, its own radius and its own responsive rules. The
 * page read as a stack of containers because it was one. The blocks here are a closed set the
 * generator knows, they share one measure, one rhythm and one rule weight, and structure is
 * carried by the rail and the hairline rather than by another border.
 *
 * Owned by frontend/docs/*.html (generated from scripts/docs-corpus.mjs). Shared chrome - the
 * masthead, the footer, the skip link - stays in editorial.css; this file changes only its
 * metrics for the docs shell, never its paint. */

.docs-page {
  --docs-nav-width: 260px;
  --docs-rail-width: 212px;
  /* 640px of 16px Inter is about 80 characters a line. Measured, not guessed: at the 720px the
     editorial articles use, these paragraphs ran to 91 characters, which is past the point where
     the eye reliably finds the next line and is a large part of why the one-page guide read as
     bulky. The lookup tables opt out of it below. */
  --docs-measure: 640px;
  /* The article's distance from the sidebar. dub.co/docs, which this shell is drawn from, holds
     its article 88px off the sidebar and lets the rail sit closer, so the text breathes on both
     sides between two visible columns. At 48 the slack all fell to the right: 48 from the
     sidebar and 200 to the rail read as a column hugging one edge with a hole beside it. */
  --docs-gutter: 88px;
  --docs-header: 60px;
  /* Sized to what the three columns need: the nav, a 640px measure with its gutters, and the
     rail. At 1512 the article track was 905px at 1440 and 960px at 1920 for a 640px paragraph,
     which put 265-353px of empty column between the text and the rail. 1360 gives the track
     840px - 760 for the article after its padding, 640 of that measure, and a 120px gutter to
     the rail that matches the policy pages'. The wide lookup tables that opt out of the measure
     get 760, which is within a hair of the width they were tuned at. */
  --docs-shell-width: 1360px;
  /* The reference is an application shell, not a centred document, so it keeps a frame of its
     own - wider, and held off the edge by a fixed inset rather than by centring. One token, read
     by the masthead, the shell and the footer, is what stops those three drifting apart: they
     had, by 48px, because the footer was still being centred on the editorial width. */
  --docs-inset: 24px;
  /* Every band is full-bleed and holds its content off the edge by this much: the fixed inset
     while the window is narrower than the shell, and the centring margin once it is wider. The
     masthead used the fixed 24px at every width while the shell capped at --docs-shell-width and
     centred, so above about 1560 the wordmark walked away from the sidebar it labels - 516px
     apart on a 2560 monitor. Nothing below 1440 showed it, which is why it was never seen. */
  --docs-frame-inset: max(var(--docs-inset), calc((100% - var(--docs-shell-width)) / 2));
  background: var(--editorial-paper);
}

/* The marketing grid wash is the landing page's atmosphere. A reference page is a sheet of type;
   it gets the paper and nothing behind it. */
.docs-page::before,
.docs-page body::before { display: none; }
body.docs-page::before { content: none; }

/* ------------------------------------------------------------------ masthead */

/* Full-bleed and shallow, because the sidebar beneath it is the navigation. The editorial
   masthead's 82px and 1280px centring belong to a page whose content is centred; here they would
   put the wordmark somewhere other than above the sidebar it labels. */
.docs-page .editorial-header {
  min-height: var(--docs-header);
  gap: 16px;
  padding-inline: var(--docs-frame-inset);
  box-shadow: none;
}
.docs-page .editorial-brand img { width: 104px; }
/* The search field now carries the auto margin that pushes the right-hand cluster over, so the
   nav sits directly beside it rather than starting a second one. */
.docs-page .editorial-header__nav { margin-left: 0; gap: 2px; }
.docs-page .editorial-header__nav a { min-height: 36px; padding: 0 10px; font-size: 14px; }
.docs-page .editorial-header__nav .editorial-header__cta { padding: 0 14px; }

/* The search field is the primary navigation on a reference site, so it sits in the masthead at
   reading width rather than behind an icon. It is a button, not an input: the dialog owns the
   real field, and two focusable text boxes for one search is a keyboard trap in waiting. */
.docs-search-trigger {
  min-height: 36px;
  /* Right, with the nav, not left against the wordmark. It sat beside the brand and read as part
     of the identity block; grouped with the actions it reads as one, which is what it is. */
  flex: 0 1 280px;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  padding: 0 8px 0 12px;
  border: 0;
  border-radius: 8px;
  color: var(--editorial-muted);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: box-shadow .15s ease, color .15s ease;
}
.docs-search-trigger:hover { color: var(--editorial-ink); box-shadow: var(--control-ring-hover); }
.docs-search-trigger__label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.docs-search-trigger kbd {
  padding: 2px 6px;
  border-radius: 8px;
  color: var(--editorial-muted);
  background: var(--editorial-paper);
  box-shadow: var(--control-ring);
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
}
.docs-search-trigger__icon,
.docs-search__icon {
  width: 14px;
  height: 14px;
  flex: none;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  opacity: .75;
}
.docs-search-trigger__icon::after,
.docs-search__icon::after {
  content: "";
  display: block;
  width: 6px;
  height: 1.5px;
  margin: 12px 0 0 8px;
  border-radius: 8px;
  background: currentColor;
  transform: rotate(45deg);
}

.docs-nav-toggle {
  min-height: 36px;
  display: none;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  border: 0;
  border-radius: 8px;
  color: var(--editorial-ink);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.docs-nav-toggle > span[aria-hidden] {
  width: 14px;
  height: 1.5px;
  background: currentColor;
  box-shadow: 0 5px currentColor, 0 -5px currentColor;
}

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

/* The drawer's backdrop, and a grid child only where the drawer exists. Left as an ordinary
   static div it took a cell of the three-column shell, pushing the article into the rail's track
   and 21px of the page off the right edge - a horizontal scrollbar on every desktop page. It is
   display:none everywhere except the widths that have a drawer to dim. */
.docs-scrim { display: none; }

.docs-shell {
  width: 100%;
  display: grid;
  grid-template-columns: var(--docs-nav-width) minmax(0, 1fr) var(--docs-rail-width);
  align-items: start;
  padding-inline: var(--docs-frame-inset);
}

/* The footer is the third band of this frame, so it is measured by the frame and not by the
   editorial width it would otherwise inherit. Left flush with the sidebar, right flush with the
   rail, exactly like the masthead above it. */
.docs-page .editorial-footer {
  width: 100%;
  padding-inline: var(--docs-frame-inset);
}

.docs-nav {
  position: sticky;
  top: var(--docs-header);
  max-height: calc(100vh - var(--docs-header));
  padding: 32px 24px 48px 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.docs-nav > nav { display: grid; gap: 24px; }
.docs-nav__group { display: grid; gap: 1px; }
.docs-nav__label {
  margin-bottom: 8px;
  padding-inline: 10px;
  color: var(--editorial-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.docs-nav a {
  min-height: 32px;
  display: flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 8px;
  color: var(--editorial-muted);
  font-size: 14px;
  line-height: 1.35;
  text-decoration: none;
  transition: color .12s ease, background-color .12s ease;
}
.docs-nav a:hover { color: var(--editorial-ink); background: var(--color-surface-sunken); }
.docs-nav a.is-current {
  color: var(--editorial-brand);
  background: var(--editorial-brand-soft);
  font-weight: 500;
}

/* The sidebar and the rail scroll independently of the page, so their scrollbars are part of the
   chrome rather than the document, and a permanent grey track between the rail and the prose
   reads as a divider that is not one. */
.docs-nav,
.docs-rail,
.docs-search__results { scrollbar-width: thin; scrollbar-color: var(--editorial-line) transparent; }
.docs-nav::-webkit-scrollbar,
.docs-rail::-webkit-scrollbar,
.docs-search__results::-webkit-scrollbar { width: 6px; }
.docs-nav::-webkit-scrollbar-thumb,
.docs-rail::-webkit-scrollbar-thumb,
.docs-search__results::-webkit-scrollbar-thumb { border-radius: 8px; background: var(--editorial-line); }
.docs-nav::-webkit-scrollbar-track,
.docs-rail::-webkit-scrollbar-track,
.docs-search__results::-webkit-scrollbar-track { background: transparent; }

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

.docs-main {
  min-width: 0;
  padding: 32px 32px 64px var(--docs-gutter);
}
.docs-main:focus-visible { outline-offset: -3px; }
/* The measure belongs to the prose, not to the column. Capping the article itself left the
   four-column lookup wrapping every cell to five lines while 120px of the main column sat empty
   beside it, so the cap is on the children and the wide blocks opt out of it. They still stop
   short of the rail; nothing bleeds into a sticky column. */
.docs-article > * { max-width: var(--docs-measure); }
.docs-article > .docs-table-wrap--wide,
.docs-article > .docs-procedure { max-width: none; }

.docs-breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  color: var(--editorial-muted);
  font-size: 13px;
}
.docs-breadcrumb a { color: inherit; text-decoration: none; }
.docs-breadcrumb a:hover { color: var(--editorial-brand); }

.docs-article h1 {
  margin: 0;
  color: var(--editorial-ink);
  font-size: 32px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.022em;
}
.docs-lede {
  margin: 12px 0 0;
  color: var(--editorial-muted);
  font-size: 16px;
  line-height: 1.62;
}
.docs-article p { margin: 0; font-size: 16px; line-height: 1.72; }
.docs-article h2,
.docs-article h3 {
  margin: 0;
  color: var(--editorial-ink);
  scroll-margin-top: calc(var(--docs-header) + 24px);
}
.docs-article h2 { font-size: 20px; font-weight: 600; letter-spacing: -.012em; }
.docs-article h3 { font-size: 16px; font-weight: 600; }

/* The vertical rhythm, stated once, at a weight that beats the per-element resets above it.
   A child-combinator universal rule does not: one element step in the paragraph reset outranks
   it, so every paragraph sat flush against the one before it and the lede ran into the first
   paragraph as a single wall of text. No contract can see that - it is a computed gap of zero,
   not a missing declaration. The :not() carries the extra class weight and each exception
   carries one more, so the cascade resolves by intent rather than by source order. */
.docs-article > :not(:first-child) { margin-top: 16px; }
.docs-article > .docs-lede { margin-top: 12px; }
.docs-article > h2:not(:first-child) { margin-top: 48px; }
.docs-article > h3:not(:first-child) { margin-top: 32px; }
/* A heading introduces the block under it; the pair is one unit and never drifts apart. */
.docs-article > :is(h2, h3) + * { margin-top: 16px; }
/* Prose links only. As `.docs-article a` this outranked every component that is itself a link -
   a card, a pager entry, a button - because one element step beats one class. The primary button
   rendered brand-on-brand and its label was invisible on the page, which no contract assertion
   could have seen. A component owns its own colour; this names the places a bare link appears. */
.docs-article :is(p, li, dd, td, th, figcaption, caption) a {
  color: var(--editorial-brand);
  text-decoration-thickness: 1px;
}
.docs-article code {
  padding: 1px 5px;
  border-radius: 8px;
  color: var(--editorial-ink);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
}
.docs-article strong { font-weight: 600; }

.docs-eyebrow {
  display: block;
  color: var(--editorial-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.docs-list { margin: 0; padding-left: 20px; display: grid; gap: 8px; }
.docs-list li { font-size: 16px; line-height: 1.7; }
.docs-list li::marker { color: var(--editorial-muted); }

/* ------------------------------------------------------------------ callout */

/* A wash and one mark, not a rail and not a border. Four tones, each a semantic role from the
   shared palette: note is structure, tip is primary, check is healthy, warn is attention. The
   tone is carried once - by the mark and the wash together - so the copy inside never has to
   repeat the severity the container already states. */
.docs-callout {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  gap: 12px;
  padding: 14px 16px;
  border-radius: 12px;
  background: var(--docs-callout-wash);
}
.docs-callout--note { --docs-callout-accent: var(--color-info); --docs-callout-wash: var(--color-info-soft); }
.docs-callout--tip { --docs-callout-accent: var(--color-brand); --docs-callout-wash: var(--color-brand-soft); }
.docs-callout--check { --docs-callout-accent: var(--color-success); --docs-callout-wash: var(--color-success-soft); }
.docs-callout--warn { --docs-callout-accent: var(--color-attention); --docs-callout-wash: var(--color-attention-soft); }
.docs-callout__mark {
  width: 16px;
  height: 16px;
  margin-top: 4px;
  border: 1.5px solid var(--docs-callout-accent);
  border-radius: 50%;
  position: relative;
}
.docs-callout__mark::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 2px;
  height: 7px;
  border-radius: 8px;
  background: var(--docs-callout-accent);
}
.docs-callout--check .docs-callout__mark::after {
  width: 7px;
  height: 3px;
  border: 1.5px solid var(--docs-callout-accent);
  border-top: 0;
  border-right: 0;
  border-radius: 0;
  background: none;
  transform: rotate(-45deg) translate(1px, -1px);
}
.docs-callout__body > strong { display: block; margin-bottom: 2px; font-size: 14px; font-weight: 600; }
.docs-callout__body p { margin: 0; font-size: 14px; line-height: 1.66; }
.docs-callout code { font-size: 12px; }

/* ------------------------------------------------------------------ steps */

/* The rail is the sequence. The numbers sit on it, the copy hangs off it, and nothing is boxed -
   which is what separates an ordered procedure from six cards that happen to be numbered. */
.docs-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
}
.docs-steps > li {
  position: relative;
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: 16px;
  padding: 0 0 24px 0;
}
.docs-steps > li:last-child { padding-bottom: 0; }
.docs-steps > li::before {
  content: "";
  position: absolute;
  top: 30px;
  bottom: 2px;
  left: 13px;
  width: 1px;
  background: var(--editorial-line);
}
.docs-steps > li:last-child::before { display: none; }
.docs-steps__marker {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--editorial-muted);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.docs-steps__body { padding-top: 2px; }
.docs-steps__body .docs-eyebrow { margin-bottom: 4px; }
.docs-steps__body > strong { display: block; font-size: 16px; font-weight: 600; }
.docs-steps__body p { margin: 4px 0 0; color: var(--editorial-muted); font-size: 14px; line-height: 1.66; }

/* ------------------------------------------------------------------ cards and columns */

.docs-cards { display: grid; gap: 12px; }
.docs-cards[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.docs-card {
  position: relative;
  display: grid;
  align-content: start;
  gap: 4px;
  padding: 16px;
  border-radius: 12px;
  color: inherit;
  background: var(--editorial-paper);
  box-shadow: var(--control-ring);
  text-decoration: none;
  transition: box-shadow .15s ease, transform .15s ease;
}
.docs-card:hover { box-shadow: inset 0 0 0 1px var(--editorial-brand); transform: translateY(-1px); }
.docs-card > strong { font-size: 16px; font-weight: 600; }
.docs-card > p { margin: 0; color: var(--editorial-muted); font-size: 14px; line-height: 1.6; }
.docs-card__go {
  position: absolute;
  top: 16px;
  right: 16px;
  color: var(--editorial-muted);
  opacity: 0;
  transition: opacity .15s ease, transform .15s ease;
}
.docs-card:hover .docs-card__go { color: var(--editorial-brand); opacity: 1; transform: translateX(2px); }
.docs-cards--tutorial .docs-card { padding: 18px 20px; }
/* A card is a link, but its title is a heading first: the blue belongs to the affordance on
   hover, not to four words of body copy sitting in a grid. */
.docs-card:hover > strong { color: var(--editorial-brand); }
.docs-card__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }

.docs-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.docs-column {
  display: grid;
  align-content: start;
  gap: 6px;
  padding: 18px 20px;
  border-radius: 12px;
  background: var(--color-surface-sunken);
}
.docs-column > strong { font-size: 16px; font-weight: 600; }
.docs-column > p { margin: 0; color: var(--editorial-muted); font-size: 14px; line-height: 1.6; }
.docs-column ul { margin: 4px 0 0; padding-left: 18px; display: grid; gap: 4px; }
.docs-column li { color: var(--editorial-muted); font-size: 13px; line-height: 1.55; }
.docs-column__go {
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  margin-top: 4px;
  color: var(--editorial-brand);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
}
.docs-column__go:hover { text-decoration: underline; }
.docs-column__go span { margin-left: 4px; }

/* ------------------------------------------------------------------ tags and states */

.docs-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 8px;
  color: var(--editorial-muted);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
}
.docs-tag--pro { color: var(--color-brand); background: var(--color-brand-soft); box-shadow: none; }
/* A plan name is not a status. Citrus lime is the healthy-delivery signal and spending it on a
   tier label would teach the reader the wrong thing about a colour they will meet again on a
   submission row, so the three plans read as a ladder in the one structural hue instead. */
.docs-tag--scale { color: #fff; background: var(--color-brand); box-shadow: none; }

/* A state is quoted here as the console renders it, so the colour is the console's semantic role
   and the word carries it - no second badge repeating what the sentence already says. */
.docs-state { font-weight: 600; }
.docs-state--success { color: var(--color-success); }
.docs-state--attention { color: var(--color-attention); }
.docs-state--failure { color: var(--color-danger); }
/* `.docs-table td strong` is one element step more specific than a state class, so it silently
   repainted every state in the lookup table to plain ink - the exact defect that table exists to
   prevent. Restated here at the higher weight rather than patched from somewhere further down. */
.docs-table td .docs-state--success { color: var(--color-success); }
.docs-table td .docs-state--attention { color: var(--color-attention); }
.docs-table td .docs-state--failure { color: var(--color-danger); }

/* ------------------------------------------------------------------ route */

.docs-route {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 20px;
  border-radius: 12px;
  background: var(--color-surface-sunken);
}
.docs-route__node { display: grid; gap: 2px; min-width: 0; }
.docs-route__node > strong { font-size: 14px; font-weight: 600; }
.docs-route__node > code {
  padding: 0;
  background: none;
  box-shadow: none;
  font-size: 13px;
  overflow-wrap: anywhere;
}
.docs-route__link {
  flex: 1;
  min-width: 24px;
  height: 1px;
  position: relative;
  background: linear-gradient(90deg, var(--editorial-line), var(--color-brand));
}
.docs-route__link::after {
  content: "";
  position: absolute;
  top: -3px;
  right: 0;
  width: 7px;
  height: 7px;
  border-top: 1.5px solid var(--color-brand);
  border-right: 1.5px solid var(--color-brand);
  transform: rotate(45deg);
}

/* ------------------------------------------------------------------ fields */

/* A labelled definition row replaces what used to be a grid of six little cards. The term is the
   thing you are scanning for; a card around it only adds edges between you and it. */
.docs-fields { margin: 0; display: grid; }
.docs-fields > div {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 24px;
  padding: 14px 0;
  border-top: 1px solid var(--editorial-line);
}
.docs-fields > div:last-child { border-bottom: 1px solid var(--editorial-line); }
.docs-fields dt { color: var(--editorial-ink); font-size: 14px; font-weight: 600; }
.docs-fields dd { margin: 0; color: var(--editorial-muted); font-size: 14px; line-height: 1.66; }

/* ------------------------------------------------------------------ prices */

.docs-prices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.docs-prices article {
  display: grid;
  gap: 4px;
  padding: 16px 20px;
  border-radius: 12px;
  background: var(--color-surface-sunken);
}
.docs-prices strong { font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
.docs-prices small { color: var(--color-brand); font-size: 12px; font-weight: 600; }
.docs-prices p { margin: 0; color: var(--editorial-muted); font-size: 13px; }

/* ------------------------------------------------------------------ tables */

.docs-table-wrap { border-radius: 12px; box-shadow: var(--control-ring); overflow: hidden; }
.docs-table-wrap--wide { overflow-x: auto; }
.docs-table-wrap--wide:focus-visible { outline-offset: 2px; }
/* The lookup tables are the reason this page exists; on a wide screen they borrow the rail's
   width rather than wrapping every cell to three lines inside the measure. */
.docs-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.docs-table caption {
  padding: 12px 16px;
  border-bottom: 1px solid var(--editorial-line);
  color: var(--editorial-muted);
  font-size: 12px;
  font-weight: 600;
  text-align: left;
}
.docs-table th,
.docs-table td { padding: 12px 16px; text-align: left; vertical-align: top; line-height: 1.6; }
.docs-table thead th {
  color: var(--editorial-muted);
  background: var(--color-surface-sunken);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .03em;
  white-space: nowrap;
}
.docs-table tbody tr + tr > * { border-top: 1px solid var(--editorial-line); }
.docs-table tbody th[scope="row"] { color: var(--editorial-ink); font-size: 14px; font-weight: 600; }
.docs-table td { color: var(--editorial-muted); }
.docs-table td strong,
.docs-table td a { color: var(--editorial-ink); }
.docs-table td a { color: var(--editorial-brand); }
.docs-table td::before { display: none; }

.docs-plans thead th:not(:first-child) { white-space: normal; min-width: 180px; }
.docs-plans__descriptor {
  display: block;
  margin-top: 4px;
  color: var(--editorial-muted);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* ------------------------------------------------------------------ code */

.docs-code {
  margin: 0;
  border-radius: 12px;
  background: var(--docs-code-paper, #0f1319);
  box-shadow: var(--control-ring);
  overflow: hidden;
}
.docs-code figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 12px 8px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  color: #9aa6b8;
  font-size: 12px;
  font-weight: 500;
}
.docs-code pre {
  margin: 0;
  padding: 16px;
  overflow-x: auto;
  color: #e6edf7;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.7;
}
.docs-code code { padding: 0; color: inherit; background: none; box-shadow: none; font-size: inherit; }
.docs-code__copy {
  min-height: 28px;
  padding: 0 10px;
  border: 0;
  border-radius: 8px;
  color: #c3ccdb;
  background: rgba(255, 255, 255, .07);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.docs-code__copy:hover { color: #fff; background: rgba(255, 255, 255, .14); }
.docs-code__copy:focus-visible { outline-offset: 2px; }

/* ------------------------------------------------------------------ accordion */

.docs-accordion { border-top: 1px solid var(--editorial-line); }
.docs-accordion details { border-bottom: 1px solid var(--editorial-line); }
.docs-accordion summary {
  min-height: 52px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 4px;
  color: var(--editorial-ink);
  font-size: 16px;
  font-weight: 500;
  list-style: none;
  cursor: pointer;
}
.docs-accordion summary::-webkit-details-marker { display: none; }
.docs-accordion summary:hover { color: var(--editorial-brand); }
.docs-accordion summary:focus-visible { outline-offset: -2px; border-radius: 8px; }
.docs-accordion__chevron {
  width: 8px;
  height: 8px;
  flex: none;
  margin-right: 6px;
  border-right: 1.5px solid var(--editorial-muted);
  border-bottom: 1.5px solid var(--editorial-muted);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}
.docs-accordion details[open] .docs-accordion__chevron { transform: rotate(225deg) translate(-2px, -2px); }
.docs-accordion__body { padding: 0 4px 16px; }
.docs-accordion__body p { margin: 0; color: var(--editorial-muted); font-size: 14px; line-height: 1.7; }

/* ------------------------------------------------------------------ actions */

.docs-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.docs-button {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  padding: 0 16px;
  border-radius: 8px;
  color: var(--editorial-ink);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: box-shadow .15s ease, background-color .15s ease;
}
.docs-button:hover { box-shadow: var(--control-ring-hover); }
.docs-button--primary {
  color: #fff;
  background: var(--color-brand);
  box-shadow: none;
}
.docs-button--primary:hover { background: var(--color-brand-deep); box-shadow: none; }

/* ------------------------------------------------------------------ pager and rail */

.docs-pager {
  max-width: var(--docs-measure);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 64px;
  padding-top: 32px;
  border-top: 1px solid var(--editorial-line);
}
.docs-pager__link {
  display: grid;
  gap: 2px;
  padding: 14px 16px;
  border-radius: 12px;
  color: inherit;
  box-shadow: var(--control-ring);
  text-decoration: none;
  transition: box-shadow .15s ease;
}
.docs-pager__link:hover { box-shadow: inset 0 0 0 1px var(--editorial-brand); }
.docs-pager__link:hover strong { color: var(--editorial-brand); }
.docs-pager__link span { color: var(--editorial-muted); font-size: 12px; }
.docs-pager__link strong { font-size: 14px; font-weight: 600; }
.docs-pager__link--next { text-align: right; }
.docs-help {
  max-width: var(--docs-measure);
  margin: 24px 0 0;
  color: var(--editorial-muted);
  font-size: 13px;
}
.docs-help a { color: var(--editorial-brand); }

.docs-rail {
  position: sticky;
  top: var(--docs-header);
  max-height: calc(100vh - var(--docs-header));
  display: grid;
  align-content: start;
  gap: 1px;
  padding: 32px 0 48px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.docs-rail__label {
  margin-bottom: 8px;
  padding-left: 12px;
  color: var(--editorial-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.docs-rail__link {
  min-height: 28px;
  display: flex;
  align-items: center;
  padding: 4px 0 4px 12px;
  border-left: 1px solid var(--editorial-line);
  color: var(--editorial-muted);
  font-size: 13px;
  line-height: 1.4;
  text-decoration: none;
  transition: color .12s ease, border-color .12s ease;
}
.docs-rail__link--h3 { padding-left: 24px; }
.docs-rail__link:hover { color: var(--editorial-ink); }
.docs-rail__link.is-current { color: var(--editorial-brand); border-left-color: var(--editorial-brand); }

/* ------------------------------------------------------------------ search dialog */

.docs-search {
  width: min(640px, calc(100vw - 32px));
  max-height: min(560px, calc(100vh - 96px));
  padding: 0;
  border: 0;
  border-radius: 16px;
  margin-top: 12vh;
  color: var(--editorial-ink);
  background: var(--editorial-paper);
  box-shadow: var(--control-ring), var(--editorial-shadow);
  overflow: hidden;
}
.docs-search::backdrop { background: rgba(8, 12, 20, .42); backdrop-filter: blur(2px); }
.docs-search__field {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px 0 20px;
  border-bottom: 1px solid var(--editorial-line);
}
.docs-search__field input {
  flex: 1;
  min-height: 56px;
  border: 0;
  padding: 0;
  color: inherit;
  background: none;
  font-size: 16px;
  outline: none;
}
.docs-search__field input::-webkit-search-cancel-button { display: none; }
.docs-search__close {
  min-height: 32px;
  padding: 0 8px;
  border: 0;
  border-radius: 8px;
  background: none;
  cursor: pointer;
}
.docs-search__close kbd {
  padding: 3px 7px;
  border-radius: 8px;
  color: var(--editorial-muted);
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  font-family: inherit;
  font-size: 11px;
}
.docs-search__results { max-height: 420px; padding: 8px; overflow-y: auto; overscroll-behavior: contain; }
.docs-search__result {
  display: grid;
  gap: 2px;
  padding: 10px 12px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
}
.docs-search__result:hover,
.docs-search__result.is-active { background: var(--color-surface-sunken); }
.docs-search__result strong { font-size: 14px; font-weight: 600; }
.docs-search__result span { color: var(--editorial-muted); font-size: 12px; }
.docs-search__result mark { color: var(--editorial-brand); background: none; font-weight: 600; }
.docs-search__empty { margin: 0; padding: 24px 20px 28px; color: var(--editorial-muted); font-size: 14px; }
.docs-search__empty a { color: var(--editorial-brand); }

/* ------------------------------------------------------------------ dark */

/* Paint only. The composition, the measure and the rhythm are the same document in both themes. */
[data-theme="dark"] .docs-search-trigger kbd { background: var(--color-surface); }
[data-theme="dark"] .docs-code { --docs-code-paper: #0b0e13; }
[data-theme="dark"] .docs-card { background: var(--color-surface); }
[data-theme="dark"] .docs-card:hover { box-shadow: inset 0 0 0 1px var(--color-brand); }
[data-theme="dark"] .docs-button--primary,
[data-theme="dark"] .docs-tag--scale { color: #06111f; }
[data-theme="dark"] .docs-search::backdrop { background: rgba(0, 0, 0, .62); }

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

/* Below the rail's width the page is two columns, not three: the headings inside a page are a
   short list and the sidebar is the navigation worth keeping. */
/* 1280 rather than 1180: three columns need 260 + 88 + 640 + 32 + 212 plus the page gutters,
   and below that the rail was being kept at the paragraphs' expense - 541px of measure at 1181.
   Once the rail goes the article centres in what is left, so the slack sits on both sides of
   the text rather than all of it to the right, which is how the reference degrades too. */
@media (max-width: 1280px) {
  .docs-shell { grid-template-columns: var(--docs-nav-width) minmax(0, 1fr); }
  .docs-rail { display: none; }
  .docs-main { padding-inline: 40px; }
  /* The article box is the measure here and centres in the track, so the text sits with equal
     room either side. Centring the children instead does nothing: the lede, the headings and
     the callouts each set their own margin shorthand at equal or higher specificity, and a
     margin-inline on `> *` loses to every one of them. The wide lookup tables take the measure
     in this band; it is the tablet range, and they wrap rather than overflow. */
  .docs-article { max-width: var(--docs-measure); margin-inline: auto; }
}

@media (max-width: 900px) {
  .docs-page { --docs-gutter: 0px; --docs-inset: 16px; }
  .docs-shell { grid-template-columns: minmax(0, 1fr); }
  .docs-nav-toggle { display: inline-flex; }
  /* The links go; the nav stays. assets/theme-control.js appends the theme button into this nav,
     so hiding the whole thing took the only theme control on the page with it and left a phone
     reader no way out of the mode they were in. Hide what is duplicated in the sidebar and the
     footer, keep what is not. */
  .docs-page .editorial-header__nav > a { display: none; }
  .docs-page .editorial-header__nav { gap: 0; }
  /* One cluster on the right, not three controls spread across the bar. The wordmark owns the
     left; search, theme and menu sit together against the right edge with a single small gap. */
  .docs-page .editorial-header { gap: 8px; }
  .docs-search-trigger { flex: 0 0 auto; margin-left: auto; }
  /* Three controls sitting together are one set of controls. theme.css paints the theme button
     as a bare icon, which is right on the article masthead where its neighbours are text links,
     and wrong here between two filled pills - the geometry already matched at 44x44 and 8px, so
     what a reader saw was one of the three missing its surface. Same two tokens as its
     neighbours, not a new colour, so it follows the theme with them. */
  .docs-page .theme-toggle {
    background: var(--color-surface-sunken);
    box-shadow: var(--control-ring);
  }
  .docs-page .editorial-header__nav { gap: 0; }
  /* The section label sits between the wordmark and the search field, and at this width there is
     room for two of the three. The breadcrumb under the heading already says where the reader is. */
  .docs-page .editorial-brand__divider,
  .docs-page .editorial-brand__section { display: none; }
  .docs-page .editorial-brand img { width: 92px; }
  .docs-search-trigger__label { font-size: 14px; }
  .docs-search-trigger kbd { display: none; }
  /* The sidebar is a disclosure on a phone, not an off-canvas drawer: a drawer needs a scrim, a
     focus trap and a close affordance to be usable, and a list this short does not earn them. */
  /* A drawer, not a section of the page.

     This was a plain block inserted into the flow, and on a 390x844 screen that meant opening the
     menu pushed 1,437px of links above the article: the heading moved to y=981, the document grew
     from 3,776px to 5,213px, and a reader who opened the menu had to scroll through twenty-five
     items to get back to what they were reading. Measured, and reported as the menu being stuck.

     It is a fixed panel over the page now, with its own scroll, the way every reference site of
     this shape does it. The page underneath does not move, and closing it puts the reader exactly
     where they were. */
  .docs-nav {
    position: fixed;
    z-index: 70;
    top: var(--docs-header);
    left: 0;
    width: min(324px, 88vw);
    height: calc(100dvh - var(--docs-header));
    max-height: none;
    padding: 12px 12px 32px;
    border-right: 1px solid var(--editorial-line);
    background: var(--editorial-paper);
    box-shadow: var(--editorial-shadow);
    overflow-y: auto;
    overscroll-behavior: contain;
    visibility: hidden;
    transform: translateX(-100%);
    /* Visibility flips instantly on the way in and waits for the slide on the way out. Listing it
       as a transitioned property instead made it an animated one, and a browser reports an
       animating visibility as still hidden until the step passes - so the script's own "is the
       drawer ready to take focus" test was false for the whole animation, and focus never moved
       into the drawer on a tap. */
    transition: transform .22s ease, visibility 0s linear .22s;
  }
  body:has([data-docs-nav-toggle][aria-expanded="true"]) .docs-nav {
    visibility: visible;
    transform: none;
    transition: transform .22s ease, visibility 0s;
  }
  /* The page behind a drawer does not scroll; a reader dragging the list should not find the
     article moving under it. */
  body:has([data-docs-nav-toggle][aria-expanded="true"]) { overflow: hidden; }
  .docs-scrim:not([hidden]) {
    display: block;
    position: fixed;
    z-index: 65;
    inset: var(--docs-header) 0 0;
    background: rgba(8, 12, 20, .45);
    opacity: 0;
    /* Transparent is not absent. assets/docs-shell.js drops the hidden attribute as soon as it
       runs - the scrim has to exist before it can be dismissed - so from that moment this was a
       full-viewport layer at z-index 65 answering every tap below the masthead, with the drawer
       shut. Everything under it was untouchable on a phone: article links, the pager, the whole
       footer. It was invisible to every check because it is invisible, and the things a sweep
       does tap sit above it - the masthead controls, the drawer itself at z-index 70, and the
       search dialog in the top layer. It takes pointer events only while it is dimming
       something. */
    pointer-events: none;
    transition: opacity .22s ease;
  }
  body:has([data-docs-nav-toggle][aria-expanded="true"]) .docs-scrim { opacity: 1; pointer-events: auto; }
  /* Tighter than the desktop rail: twenty-five items at desktop spacing is four screens of
     scrolling inside the drawer. Still 44px, because the pointer is coarse. */
  .docs-nav > nav { gap: 18px; }
  .docs-nav__group { gap: 0; }
  .docs-nav a { min-height: 44px; font-size: 16px; }
  .docs-main { padding: 24px 0 48px; }
  .docs-article h1 { font-size: 24px; }
  .docs-cards[data-cols="2"],
  .docs-columns,
  .docs-prices,
  .docs-pager { grid-template-columns: minmax(0, 1fr); }
  .docs-fields > div { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  /* Every cell already carries its column name, so a table becomes a labelled stack rather than
     a horizontal scroll a thumb has to find. */
  .docs-table-wrap { border-radius: 12px; }
  .docs-table-wrap--wide { overflow-x: visible; }
  .docs-table,
  .docs-table tbody,
  .docs-table tr { display: block; }
  .docs-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .docs-table tr { padding: 12px 16px; }
  .docs-table tbody tr + tr { border-top: 1px solid var(--editorial-line); }
  .docs-table tbody tr + tr > * { border-top: 0; }
  .docs-table th,
  .docs-table td { display: block; padding: 6px 0; }
  .docs-table tbody th[scope="row"] { padding-top: 0; font-size: 16px; }
  .docs-table td::before {
    display: block;
    margin-bottom: 2px;
    color: var(--editorial-muted);
    content: attr(data-label);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
  }
  .docs-plans thead th:not(:first-child) { min-width: 0; }
  .docs-route { flex-direction: column; align-items: stretch; gap: 8px; }
  .docs-route__link { width: 1px; min-width: 0; height: 20px; margin-left: 1px; background: linear-gradient(180deg, var(--editorial-line), var(--color-brand)); }
  .docs-route__link::after { top: auto; right: auto; bottom: 0; left: -3px; border-top: 0; border-right: 1.5px solid var(--color-brand); border-bottom: 1.5px solid var(--color-brand); }
  .docs-search { margin-top: 0; width: 100vw; max-height: 100vh; height: 100vh; border-radius: 0; }
  .docs-search__results { max-height: calc(100vh - 120px); }
  .docs-procedure > li { grid-template-columns: 28px minmax(0, 1fr); gap: 12px; padding-bottom: 32px; }
  .docs-procedure > li::before { top: 34px; left: 14px; }
  .docs-procedure__marker { width: 28px; height: 28px; font-size: 13px; }
  .docs-procedure__body > h2 { font-size: 18px; }
  /* A phone column is narrower than any console capture, so the caption does the work the
     full-size link does on a pointer device. */
  .docs-figure__zoom > span { opacity: 1; }
}

@media (max-width: 420px) {
  .docs-nav-toggle__text { display: none; }
  /* Wordmark, search, theme and menu will not fit across 320px as four labelled controls. The
     search field keeps its icon and loses its words; it is still a 44px target and still the
     first thing after the wordmark. */
  .docs-search-trigger { flex: 0 0 auto; min-width: 44px; justify-content: center; padding-inline: 10px; }
  .docs-search-trigger__label { display: none; }
  .docs-steps > li { grid-template-columns: 26px minmax(0, 1fr); gap: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .docs-card,
  .docs-card__go,
  .docs-accordion__chevron,
  .docs-nav a,
  .docs-rail__link,
  .docs-pager__link,
  .docs-search-trigger,
  .docs-figure__zoom > span,
  .docs-button { transition: none; }
  .docs-card:hover { transform: none; }
}

/* ------------------------------------------------------------------ touch */

/* Where the pointer is coarse, every control is at least 44px regardless of how compact the
   desktop chrome is. The sweep found nine controls under it - the search field, the menu button,
   the breadcrumb, both button styles, the column link, the copy button and the dialog's own
   controls - all of them sized for a mouse and all of them reachable on a phone. Density comes
   from the pointer, never from the surface. */
@media (pointer: coarse) {
  .docs-search-trigger,
  .docs-nav-toggle,
  .docs-search__close { min-height: 44px; }
  .docs-nav-toggle { min-width: 44px; justify-content: center; }
  .docs-button,
  .docs-column__go,
  .docs-code__copy { min-height: 44px; }
  .docs-breadcrumb { gap: 4px; }
  /* Padded out and pulled back by the same amount, so the target is 44 square without the
     breadcrumb appearing indented from the heading it sits above. */
  .docs-breadcrumb a,
  .docs-breadcrumb > span:not([aria-hidden]) {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding-inline: 8px;
  }
  .docs-breadcrumb > :first-child { margin-left: -8px; }
  .docs-rail__link { min-height: 44px; }
  .docs-search__result { padding-block: 14px; }
  .docs-pager__link { min-height: 44px; }
}

/* ------------------------------------------------------------------ figures */

/* A tutorial is screenshot-led, so the figure is the one block that earns a frame: a console
   capture on paper with no edge reads as part of the page rather than as a picture of a
   different screen. */
.docs-figure { margin: 0; display: grid; gap: 8px; }
.docs-figure__zoom {
  position: relative;
  display: block;
  border-radius: 12px;
  background: var(--color-surface-sunken);
  box-shadow: var(--control-ring);
  overflow: hidden;
}
.docs-figure__zoom img { width: 100%; height: auto; }
.docs-figure__zoom > span {
  position: absolute;
  right: 8px;
  bottom: 8px;
  min-height: 28px;
  display: inline-flex;
  align-items: center;
  padding: 0 10px;
  border-radius: 8px;
  color: #fff;
  background: rgba(11, 13, 18, .78);
  font-size: 12px;
  font-weight: 500;
  opacity: 0;
  transition: opacity .15s ease;
}
.docs-figure__zoom:hover > span,
.docs-figure__zoom:focus-visible > span { opacity: 1; }
.docs-figure figcaption { color: var(--editorial-muted); font-size: 13px; line-height: 1.6; }
.docs-figure figcaption code { font-size: 12px; }

/* ------------------------------------------------------------------ procedure */

/* The long-form step. Same rail and same numerals as `.docs-steps`, but each step carries a
   heading the reader can link to and a body of full blocks, so the marker is larger and the
   spacing is a section's rather than a list item's. Not boxed: seven boxed steps down a page is
   the stack of containers this whole surface was rebuilt to stop. */
.docs-procedure {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
}
.docs-procedure > li {
  position: relative;
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 20px;
  padding-bottom: 48px;
}
.docs-procedure > li:last-child { padding-bottom: 0; }
.docs-procedure > li::before {
  content: "";
  position: absolute;
  top: 40px;
  bottom: 8px;
  left: 16px;
  width: 1px;
  background: var(--editorial-line);
}
.docs-procedure > li:last-child::before { display: none; }
.docs-procedure__marker {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--editorial-brand);
  background: var(--editorial-brand-soft);
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.docs-procedure__body { min-width: 0; display: grid; gap: 16px; align-content: start; }
.docs-procedure__body > .docs-eyebrow { margin-bottom: -8px; }
.docs-procedure__body > h2 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -.012em; }
/* The body is a grid, so the article's flow rule does not reach inside it and the gap is one
   value rather than a margin on every block type the step might contain. */
.docs-procedure__body > * { margin: 0; }

/* ------------------------------------------------------------------ page meta */

/* Four facts in a row under the title. Not a panel beside the heading, which is where they were
   and where they competed with it; and not a route, which means something specific here. */
.docs-meta {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 32px;
  padding: 14px 20px;
  border-radius: 12px;
  background: var(--color-surface-sunken);
}
.docs-meta > div { display: grid; gap: 2px; }
.docs-meta dt {
  color: var(--editorial-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.docs-meta dd { margin: 0; font-size: 14px; font-weight: 600; }

/* ------------------------------------------------------------------ procedure width */

/* Prose keeps the measure; evidence does not. A 1600px console capture rendered at the width of
   a line of text is orientation rather than evidence, and these tutorials are screenshot-led. So
   the procedure takes the whole working column and only its reading blocks are capped - the same
   split the lookup tables already make, applied one level deeper. */
.docs-article > .docs-procedure { max-width: none; }
.docs-procedure__body > :is(p, ul, ol, dl, .docs-callout, .docs-cards, .docs-columns) {
  max-width: var(--docs-measure);
}

/* ------------------------------------------------------------------ masthead stability */

/* The theme button used to be appended to this nav after first paint, so the masthead grew by a
   button width on every page load and the icon visibly appeared late. Space was reserved for it
   here, which stopped the growth but not the flicker - a placeholder is still an empty box where
   a control should already be. The button is in the parsed markup now and this surface loads
   assets/theme-control.js directly after the header instead of deferring it, so there is nothing
   to reserve and nothing to pop in. See scripts/docs-shell.mjs. */

/* ------------------------------------------------------------------ persistence */

/* ------------------------------------------------------------------ masthead */

/* There was a reservation here holding space for the theme button, because assets/theme-control.js
   used to build it after first paint. scripts/docs-shell.mjs ships the button in the markup now,
   so there is nothing to reserve: it is painted with the rest of the header, in the first frame,
   showing the correct icon. */

/* ------------------------------------------------------------------ client-side navigation */

/* A navigation inside the reference swaps the article and leaves the chrome alone, so nothing
   announces the change to a screen reader the way a real page load would. This says the new
   page's name and is never seen. */
.docs-route-announcer {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------------ footer, on a phone */

/* 730px of footer under a reference page on an 844px screen - most of a screenful, below content
   that already has a twenty-five item sidebar of its own. The links stay, because they are the
   only way off this surface; what goes is the marketing line, which says nothing a reader at the
   foot of a documentation page needs, and the padding around it. */
@media (max-width: 900px) {
  .docs-page .editorial-footer { gap: 24px; padding-block: 32px 40px; }
  .docs-page .editorial-footer__intro p { display: none; }
  .docs-page .editorial-footer__intro { display: grid; gap: 16px; justify-items: start; }
  .docs-page .footer-link-group span { margin-bottom: 0; }
  /* Flowed, not gridded. In a two-column grid the row is as tall as its tallest group, so
     "Workspace" - two links - was stretched to 237px because "Docs" beside it has five. Columns
     let the groups fill both tracks evenly instead, which is the same links in far less height. */
  .docs-page .footer-links {
    display: block;
    columns: 2;
    column-gap: 16px;
  }
  /* The group keeps the grid editorial.css gives it. Overriding it to `block` to make it flow let
     the label and the links run together inline - "WORKSPACE Dashboard" on one line - because the
     links are inline-flex. Multi-column flows a grid just as happily. */
  .docs-page .footer-link-group {
    break-inside: avoid;
    margin-bottom: 12px;
  }
}
