/* ============================================================
   The app's authored CSS: the things that were never utilities.

   Document bodies, the markdown editor's full-screen mode, the rail's three
   states, the account menu, the range chip, the docs table of contents. All
   of it moved here verbatim when Tailwind was removed; it was already plain
   CSS living in the Tailwind entry file because no set of utilities could
   express it.

   It reads the brand through the same custom properties it always did, which
   is why those names survive in theme.css rather than being renamed to
   Bootstrap's.
   ============================================================ */

/* ============================================================
   Authored pages. Retuned to the ramp above, with the display face on
   headings and cobalt on links.

   Written here rather than reached for from a typography plugin: the body is
   built by DocumentBody from a fixed allow-list of tags, so the set of things
   that need styling is closed and small. Tables lead, because a financial
   summary is the main reason to write a page instead of attaching a
   spreadsheet.
   ============================================================ */
.document-body {
  color: var(--color-gray-700);
  font-size: 1rem;
  line-height: 1.7;
  letter-spacing: -0.02em;

  /* A source URL written out in full is longer than a phone is wide, and one
   * unbreakable word is enough to make the whole page scroll sideways. */
  overflow-wrap: break-word;
}

.document-body > * + * { margin-top: 1rem; }

/* The same rhythm one level in. Without this a blockquote of two paragraphs, or
 * a list item carrying more than a sentence, closes up into a single block. */
.document-body blockquote > * + *,
.document-body li > p + p,
.document-body-footnotes li > * + * { margin-top: 0.75rem; }

.document-body h1,
.document-body h2,
.document-body h3 {
  color: var(--color-navy);
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.1;
}

/* Set as a label rather than a smaller heading. At body size and body case an
 * h4 was only distinguishable by weight, which on a dense page is not enough. */
.document-body h4,
.document-body h5,
.document-body h6 {
  color: var(--color-navy);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.3;
  text-transform: uppercase;
}

/* A heading belongs to what follows it, so it sits close to that and far from
 * what it left behind. Every level, not just the first three — an h4 that
 * inherited the ordinary 1rem was drifting away from its own paragraph. */
.document-body > :is(h1, h2, h3, h4, h5, h6) + * { margin-top: 0.5rem; }
.document-body > * + :is(h1, h2, h3) { margin-top: 2.5rem; }
.document-body > * + :is(h4, h5, h6) { margin-top: 1.75rem; }

.document-body h1 { font-size: 1.75rem; }
.document-body h2 { font-size: 1.375rem; }
.document-body h3 { font-size: 1.125rem; }

.document-body a {
  color: var(--color-cobalt);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.document-body a:hover { color: var(--color-cobalt-hover); }

.document-body strong { color: var(--color-navy); font-weight: 600; }

.document-body ul,
.document-body ol { padding-left: 1.25rem; }

.document-body ul { list-style: disc; }
.document-body ol { list-style: decimal; }

/* Depth has to be readable from the marker alone. Nested decimals were the
 * worst of it: a "1." inside a "2." reads as a sibling until you count the
 * indent. */
.document-body ul ul { list-style: circle; }
.document-body ul ul ul { list-style: square; }
.document-body ol ol { list-style: lower-alpha; }
.document-body ol ol ol { list-style: lower-roman; }

.document-body li::marker { color: var(--color-beige-300); }
.document-body li + li { margin-top: 0.25rem; }
.document-body li > ul,
.document-body li > ol { margin-top: 0.25rem; }

.document-body blockquote {
  border-left: 3px solid var(--color-beige-200);
  padding-left: 1rem;
  color: var(--color-gray-600);
}

/* The colour is stated, and that is the whole reason this line exists.
 * Bootstrap's reboot sets `code { color: var(--bs-code-color) }`, a pink this
 * brand uses nowhere, arriving on an investor-facing page through a selector no
 * template mentions and no palette token feeds. Setting the background without
 * the colour left it there, in both themes. `.docs-code` names its colour for
 * the same reason; this is the pair to it that got missed. */
.document-body code {
  background-color: var(--color-beige-100);
  border-radius: 0.25rem;
  padding: 0.125rem 0.3rem;
  font-size: 0.8125rem;
  color: var(--color-navy);
}

.document-body pre {
  background-color: var(--rb-code-bg);
  border-radius: 0.75rem;
  color: var(--rb-code-fg);
  overflow-x: auto;
  padding: 1rem;
  font-size: 0.8125rem;
  line-height: 1.6;
}

.document-body pre code { background-color: transparent; color: inherit; padding: 0; }

.document-body hr { border-color: var(--color-beige-200); margin-block: 2rem; }

/* A wide table scrolls inside its own box rather than making the page scroll
 * sideways on a phone. DocumentBody wraps every table in this, and makes the
 * box focusable so the scroll is reachable from the keyboard.
 *
 * White rather than the page's beige, so the fades below have one surface to
 * come to rest on whichever ground the body is rendered against. */
.document-body-table {
  overflow-x: auto;
  background-color: var(--color-white);
  border: 1px solid var(--color-beige-200);
  border-radius: 0.75rem;

  /* Half a column sliced off at the edge, with nothing to say it can be
   * reached, is how a financial table loses its right-hand years on a phone.
   *
   * Four background layers, no JavaScript. The two `local` ones are opaque
   * covers that scroll with the table; the two `scroll` ones are the fades,
   * pinned to the box. Where there is nothing further to scroll to in a
   * direction, that side's cover comes to rest on top of its fade and hides
   * it — so a fade shows exactly while there is more table that way, and a
   * table that already fits shows neither. */
  background-image:
    linear-gradient(to right, var(--color-white) 40%, transparent),
    linear-gradient(to left, var(--color-white) 40%, transparent),
    linear-gradient(to left, var(--rb-table-fade), transparent),
    linear-gradient(to right, var(--rb-table-fade), transparent);
  background-position: left center, right center, right center, left center;
  background-repeat: no-repeat;
  background-size: 2.5rem 100%, 2.5rem 100%, 1.5rem 100%, 1.5rem 100%;
  background-attachment: local, local, scroll, scroll;
}

/* The fade is a hint, not an instruction. On a phone, where the table is
 * narrower than the columns by a wide margin and there is no scrollbar to
 * notice, say it out loud as well. DocumentBody writes the line; it is worth
 * the room it takes only at that width. */
.document-body-table-hint { display: none; }

@media (max-width: 40rem) {
  .document-body > .document-body-table-hint {
    display: block;
    color: var(--color-gray-600);
    font-size: 0.75rem;
    line-height: 1.4;
    margin-top: 0.375rem;
  }
}

.document-body-table:focus-visible {
  outline: 2px solid var(--color-cobalt);
  outline-offset: 2px;
}

.document-body table {
  border-collapse: collapse;
  font-size: 0.9375rem;
  min-width: 100%;
}

/* Read-only workbook preview. It keeps spreadsheet coordinates and wide rows
 * instead of squeezing a financial model into a prose column or slicing it
 * into PDF pages. Values are server-rendered; the tabs only choose a sheet. */
.rb-spreadsheet-preview {
  overflow: hidden;
  border: 1px solid var(--rb-hairline);
  border-radius: var(--rb-radius-card);
  background: var(--rb-canvas);
}

.rb-sheet-tabs {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  padding: 0.5rem;
  border-bottom: 1px solid var(--rb-hairline);
  background: var(--rb-subtle);
  scrollbar-width: none;
}

.rb-sheet-tabs::-webkit-scrollbar { display: none; }

.rb-sheet-tab {
  flex: 0 0 auto;
  padding: 0.45rem 0.75rem;
  border: 0;
  border-radius: 0.55rem;
  background: transparent;
  color: var(--rb-ink-muted);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

.rb-sheet-tab[aria-selected="true"] {
  background: var(--rb-canvas);
  color: var(--rb-ink);
  box-shadow: inset 0 0 0 1px var(--rb-hairline);
}

.rb-sheet-tab:focus-visible,
.rb-spreadsheet-grid:focus-visible {
  outline: 2px solid var(--rb-accent);
  outline-offset: -2px;
}

.rb-sheet-title {
  padding: 0.65rem 0.875rem;
  border-bottom: 1px solid var(--rb-hairline);
  background: var(--rb-subtle);
  color: var(--rb-ink);
  font-size: 0.8125rem;
  font-weight: 600;
}

.rb-spreadsheet-grid {
  max-width: 100%;
  overflow-x: auto;
}

.rb-spreadsheet-table {
  width: max-content;
  min-width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  color: var(--rb-ink);
  font-size: 0.8125rem;
  line-height: 1.35;
}

.rb-spreadsheet-table th,
.rb-spreadsheet-table td {
  min-width: 7rem;
  max-width: 24rem;
  height: 2rem;
  padding: 0.35rem 0.55rem;
  overflow: hidden;
  border-right: 1px solid var(--rb-hairline);
  border-bottom: 1px solid var(--rb-hairline);
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A cell is paper in both themes, the way a rendered PDF page is. The fill and
 * the text colour come off the workbook where it set them, and where it did
 * not, they are the sheet's own white and near-black rather than the canvas
 * and the ink: a workbook that fills every forecast column white, and none of
 * its labels, put near-white ink on white fills after dark. Only the cells
 * are paper; the row and column headers are the viewer's chrome. */
.rb-spreadsheet-table td {
  border-right-color: var(--rb-paper-hairline);
  border-bottom-color: var(--rb-paper-hairline);
  background: var(--rb-sheet-fill-color, var(--rb-paper));
  color: var(--rb-sheet-text-color, var(--rb-paper-ink));
}

.rb-spreadsheet-table thead th,
.rb-spreadsheet-table tbody th {
  position: sticky;
  z-index: 1;
  min-width: 2.75rem;
  width: 2.75rem;
  background: var(--rb-subtle);
  color: var(--rb-ink-faint);
  font-weight: 500;
  text-align: center;
}

.rb-spreadsheet-table thead th { top: 0; }
.rb-spreadsheet-table tbody th { left: 0; }
.rb-spreadsheet-table .rb-sheet-corner {
  left: 0;
  z-index: 2;
}

.rb-spreadsheet-table .rb-sheet-number {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.rb-spreadsheet-table .rb-sheet-bold { font-weight: 700; }
.rb-spreadsheet-table .rb-sheet-italic { font-style: italic; }
.rb-spreadsheet-table .rb-sheet-underline { text-decoration: underline; }
.rb-spreadsheet-table .rb-sheet-align-left { text-align: left; }
.rb-spreadsheet-table .rb-sheet-align-center { text-align: center; }
.rb-spreadsheet-table .rb-sheet-align-right { text-align: right; }
.rb-spreadsheet-table .rb-sheet-align-justify { text-align: justify; }

.rb-spreadsheet-table-compact th,
.rb-spreadsheet-table-compact td {
  min-width: 6rem;
  max-width: 18rem;
  font-size: 0.75rem;
}

.rb-sheet-limit {
  padding: 0.65rem 0.875rem;
  border-top: 1px solid var(--rb-hairline);
  background: var(--rb-subtle);
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
}

.document-body th,
.document-body td {
  border-bottom: 1px solid var(--color-gray-100);
  padding: 0.625rem 1rem;
  text-align: left;
  vertical-align: top;
}

/* A section's heading, its description and its download, on one line where
 * there is room and on two where there is not.
 *
 * It was a group beside a control with `justify-content-between`. On a phone
 * the group took the full width as soon as the description wrapped, so the
 * control fell to a third line at the left margin: a download arrow sitting on
 * its own under a paragraph, belonging to nothing visible.
 *
 * The action is pushed right by `margin-left: auto` rather than by the parent
 * spacing its children, which is what lets the description drop to its own line
 * without taking the action with it. Below the fold-point the description
 * claims a whole line and reorders under the two things that fit beside each
 * other; above it, nothing has changed. */
.rb-section-head-action { margin-left: auto; }

@media (max-width: 40rem) {
  .rb-section-head-note { flex-basis: 100%; order: 3; }
  .rb-section-head-action { order: 2; }
}

/* The settings page: an index that holds, and the cards it points at.
 *
 * Eight sections is past what a page can be scanned for, and settings is where
 * somebody arrives already knowing what they came to change. Each is its own
 * page now and this rail is how you get between them.
 *
 * Two columns only where there is room for two. Below `lg` it stacks above the
 * content rather than disappearing: when these were anchors, a list of links
 * directly above the things they link to was the same list twice and worth
 * dropping on a phone. Now it is the only way to reach the other seven. */
.rb-settings { display: grid; gap: 2rem; }

@media (min-width: 992px) {
  .rb-settings { grid-template-columns: 13rem minmax(0, 1fr); align-items: start; }

  .rb-settings-index {
    position: sticky;
    /* Clear of the top bar, which is what the anchors below also allow for. */
    top: 1.5rem;
  }
}

.rb-settings-index ul { margin: 0; padding: 0; list-style: none; }

.rb-settings-index-link {
  display: block;
  padding: 0.375rem 0.625rem;
  border-radius: 0.5rem;
  color: var(--rb-ink-muted);
  font-size: 0.875rem;
  text-decoration: none;
}

.rb-settings-index-link:hover {
  background-color: var(--rb-wash);
  color: var(--rb-ink);
}

/* Which page you are on. A rail of eight links with nothing marked is a rail
   that answers "where else" and not "where". */
.rb-settings-index-link.is-current {
  background-color: var(--rb-wash);
  color: var(--rb-ink);
  font-weight: 600;
}

.rb-settings-index-link:focus-visible {
  outline: 2px solid var(--color-cobalt);
  outline-offset: 1px;
}

/* The row of controls above a table: Copy, and Expand.
 *
 * What these replaced was a breakout. A page's tables were widened to 92rem
 * inside a 768px prose column on the theory that a financial table wants the
 * room. Measured against a real room afterwards, its forty tables are two to
 * five columns wide and not one of them overflowed the column, so every table
 * hung 192px off both edges of the prose it was written between and stretched
 * to fill width it had no use for. The page stopped reading as a page, and the
 * tables that genuinely are too wide were no better off: 92rem with a scrollbar
 * is not the answer to ten columns, the whole window is.
 *
 * So a table sits in the column with the text, on the same margins, and the two
 * things a reader actually wanted from the width are controls instead: take it
 * away to a spreadsheet, or open it across the screen.
 *
 * Quiet by default, and always present rather than shown on hover: half the
 * readers of a data room are on a tablet, where there is no hover and a control
 * that only appears for a pointer is a control that does not exist. */
.document-body-table-tools {
  display: flex;
  justify-content: flex-end;
  gap: 0.25rem;
  margin-top: 1.25rem;
  margin-bottom: 0.375rem;
}

.rb-table-tool {
  border: 0;
  border-radius: 0.375rem;
  background-color: transparent;
  padding: 0.125rem 0.5rem;
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
  line-height: 1.5;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.rb-table-tool:hover {
  background-color: var(--rb-wash);
  color: var(--rb-ink);
}

.rb-table-tool:focus-visible {
  outline: 2px solid var(--color-cobalt);
  outline-offset: 1px;
}

/* The table the tools sit on owns the space above it, so the paragraph rule
 * that would also apply must not add a second gap. */
.document-body-table-tools + .document-body-table { margin-top: 0; }

/* A table across the whole window. Wider than `.rb-modal`'s 40rem, which is a
 * measure for a form, and no taller than it has to be: a four-row table opening
 * as a full-height panel would be a worse read than the page it came from. */
.rb-table-modal {
  width: min(96rem, calc(100vw - 2rem));
}

.rb-table-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-bottom: 1px solid var(--rb-hairline);
  padding: 0.875rem 1.25rem;
}

.rb-table-modal-close {
  border: 0;
  border-radius: 0.375rem;
  background-color: transparent;
  padding: 0.125rem 0.5rem;
  color: var(--rb-ink-muted);
}

.rb-table-modal-close:hover {
  background-color: var(--rb-wash);
  color: var(--rb-ink);
}

/* Both axes. A table that needed the whole window may still be taller than it,
 * and a hundred-row table is the case this was built for. */
.rb-table-modal-body {
  overflow: auto;
}

/* `.document-body` is on the dialog's body so the table is painted by the same
 * rules it is painted by on the page: the same type, rules and cell padding,
 * rather than a second answer to how a table looks. */
.rb-table-modal-body > table {
  min-width: 100%;
}

/* Where a document sits, along the top of the page and again at its foot.
 *
 * Sized and coloured like the back link it replaces rather than like a heading:
 * it is navigation a reader glances at, and the document's own title is the
 * loud thing on the page. */
.rb-trail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.9375rem;
  font-weight: 500;
  min-width: 0;
}

.rb-trail-link {
  color: var(--color-gray-600);
  text-decoration: none;
}

.rb-trail-link:hover {
  color: var(--color-navy);
  text-decoration: underline;
}

.rb-trail-link:focus-visible {
  outline: 2px solid var(--color-cobalt);
  outline-offset: 2px;
  border-radius: 0.125rem;
}

/* A section this audience cannot open. It still says where the document sits,
 * because a subsection can be granted while the root above it is not, and a
 * name with no link is better than a link that refuses. */
.rb-trail-here {
  color: var(--color-gray-600);
}

.rb-trail-sep {
  color: var(--color-gray-400);
}

/* A customer's mark beside their name, from `{{logo:domain}}`. Sized in `em` so
 * it tracks the text rather than the viewport, and nudged down by its optical
 * centre: a favicon is a square and sits high against a lowercase word if it is
 * baselined.
 *
 * `flex: none` because these live in a cell that also holds a name long enough
 * to wrap ("Banfield Pet Hospital (owned by Mars)"), and a squashed logo is
 * worse than a wrapped one. */
.document-body .rb-inline-logo {
  width: 1.15em;
  height: 1.15em;
  object-fit: contain;
  vertical-align: -0.22em;
  margin-right: 0.45em;
  flex: none;
}

/* Alignment comes from the markdown's own `|---:|`, folded to `align` by
 * DocumentBody because the sanitiser will not carry an inline style.
 *
 * Figures get tabular numerals and refuse to wrap: a currency column only
 * reads as a column when the digits line up and each number stays on one line.
 * Prose columns are left to wrap, which is what stops a table with a notes
 * column from scrolling for a mile. */
.document-body :is(th, td)[align="right"] {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.document-body :is(th, td)[align="center"] { text-align: center; white-space: nowrap; }

.document-body thead th {
  background-color: var(--color-beige-100);
  border-bottom: 1px solid var(--color-beige-200);
  color: var(--color-gray-600);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.document-body tbody tr:last-child th,
.document-body tbody tr:last-child td { border-bottom: 0; }

/* A caption is words a reader has to be able to read, not a marker. On this
 * ramp gray-500 lands at about 3.9:1 on white, which is under AA at this size;
 * gray-600 clears it. */
.document-body caption {
  caption-side: bottom;
  color: var(--color-gray-600);
  font-size: 0.75rem;
  padding-top: 0.5rem;
  text-align: left;
}

/* Footnotes. A room page carries the figures that do not reconcile in these,
 * so the jump has to land somewhere obvious — the sticky viewer header would
 * otherwise sit on top of whichever note was just followed. */
.document-body sup a {
  color: var(--color-cobalt);
  font-weight: 600;
  padding-inline: 0.125rem;
  text-decoration: none;
}

.document-body sup a:hover { text-decoration: underline; }

.document-body-footnotes {
  border-top: 1px solid var(--color-beige-200);
  color: var(--color-gray-600);
  font-size: 0.8125rem;
  margin-top: 2.5rem;
  padding-top: 1.25rem;
}

.document-body-footnotes ol { padding-left: 1.125rem; }
.document-body-footnotes li + li { margin-top: 0.5rem; }

.document-body-footnotes-title {
  color: var(--rb-ink);
  font-size: 0.875rem;
  font-weight: 600;
  margin: 0 0 0.75rem;
}

.document-body-footnotes li,
.document-body sup { scroll-margin-top: 6rem; }

.document-body-footnotes li:target {
  background-color: var(--color-blue-50);
  border-radius: 0.25rem;
  box-shadow: 0 0 0 0.375rem var(--color-blue-50);
}

.document-body-footnotes li.is-footnote-target,
.document-body sup.is-footnote-target {
  background-color: var(--color-blue-50);
  border-radius: 0.25rem;
  box-shadow: 0 0 0 0.375rem var(--color-blue-50);
  outline: none;
  transition: background-color 180ms ease, box-shadow 180ms ease;
}

/* ============================================================
   Authoring a page. Everything the toolbar does is a Tailwind class on the
   markup; what is left for CSS is the full-screen mode, which no set of
   utilities can express — a fixed box that takes over the viewport, with the
   textarea as the part of it that stretches.

   Worth having because the field is a window onto a document: a page with two
   or three tables in it is longer than any form-sized textarea, and editing it
   through a 26rem slot is the complaint that started this.
   ============================================================ */
.markdown-editor--expanded {
  border-radius: 0;
  border-width: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  left: 0;
  position: fixed;
  right: 0;
  top: 0;
  z-index: 40;
  overflow: hidden;

  /* A line of markdown is read the way any line of text is, so the text keeps a
   * measure instead of running the width of a wide screen. */
  --markdown-gutter: max(1rem, calc((100vw - 60rem) / 2));
}

.markdown-editor-toolbar {
  top: 0;
  border-radius: calc(1rem - 2px) calc(1rem - 2px) 0 0;
}

/* The document Save bar is already sticky. Keep authoring tools immediately
 * below it, rather than covering it or disappearing several pages above. */
.markdown-editor-toolbar--under-savebar { top: 5.5rem; }

.markdown-editor--expanded .markdown-editor-toolbar { top: 0; }

/* The toolbar sits back by a button's own padding, so the first button's letter
 * lands on the same left edge as the text under it. */
.markdown-editor--expanded .markdown-editor-toolbar {
  padding-inline: calc(var(--markdown-gutter) - 0.5rem);
}

.markdown-editor--expanded .markdown-editor-input {
  flex: 1 1 auto;
  min-height: 0;
  padding-inline: var(--markdown-gutter);
  resize: none;
}

/* The authored page edits in the typography it will be read in. It grows with
 * the document instead of trapping a long memo inside a textarea-sized slot. */
.markdown-editor-visual {
  min-height: 65vh;
  padding: clamp(1.25rem, 3vw, 3rem);
  cursor: text;
}

.markdown-editor-visual:focus { outline: 0; }

.markdown-editor-visual:empty::before {
  color: var(--rb-ink-faint);
  content: attr(data-placeholder);
  pointer-events: none;
}

.markdown-editor-visual table { cursor: text; }

/* Authored-page media stays one quiet block in the reading column. Screenshots
   are contained rather than cropped; a carousel therefore occupies the space
   of one image even when the source files have different proportions. */
.document-media-block {
  margin: 1.75rem 0;
  max-width: 100%;
}

.document-media-stage {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--bs-border-color);
  border-radius: 0.9rem;
  background: var(--bs-tertiary-bg);
}

.document-media-slide { margin: 0; }

.document-media-picture {
  display: block;
  width: 100%;
  max-height: min(68vh, 52rem);
  object-fit: contain;
  background: var(--bs-body-bg);
}

/* A carousel promises to occupy one slot in the document. Its source images
   can differ by a few pixels (or much more), but moving between them should not
   move every paragraph below the block. A standalone image keeps its natural
   ratio; only a multi-image block gets the stable presentation canvas. */
.document-media-carousel .document-media-picture { aspect-ratio: 16 / 9; }

.document-media-caption {
  padding: 0.7rem 1rem;
  border-top: 1px solid var(--bs-border-color);
  color: var(--bs-secondary-color);
  font-size: 0.8125rem;
  line-height: 1.45;
}

/* `rb-link` is also used on the larger pre-auth screens and therefore carries
   its own 15px size. In a caption the sentence owns the typography: a URL is a
   link within that sentence, not a larger control sitting beside it. */
.document-media-caption .rb-link {
  display: inline;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
}

/* A carousel always has a quiet footer, even when a slide has no caption. That
   gives its counter a stable baseline instead of making it float over the
   image on one slide and over text on the next. */
.document-media-carousel .document-media-caption {
  display: flex;
  align-items: center;
  min-height: 2.65rem;
  padding-right: 5rem;
}

.document-media-arrow {
  position: absolute;
  top: 50%;
  width: 2.5rem;
  height: 2.5rem;
  transform: translateY(-50%);
  border: 1px solid var(--rb-sheet-edge-strong);
  border-radius: 999px;
  background: var(--rb-slab);
  color: var(--rb-code-fg);
  box-shadow: 0 0.25rem 1rem var(--rb-shadow-soft);
}

.document-media-arrow-prev { left: 0.75rem; }
.document-media-arrow-next { right: 0.75rem; }

.document-media-count {
  position: absolute;
  right: 0.75rem;
  bottom: 0.45rem;
  display: inline-flex;
  align-items: center;
  height: 1.75rem;
  padding: 0 0.6rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 999px;
  background: var(--rb-canvas);
  color: var(--bs-secondary-color);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
}

.document-media-editor-label {
  margin-top: 0.45rem;
  color: var(--bs-secondary-color);
  font-size: 0.75rem;
}

.markdown-editor-visual .document-media-block {
  padding: 0.4rem;
  border-radius: 1rem;
  outline: 1px solid transparent;
}

.markdown-editor-visual .document-media-block:hover { outline-color: var(--bs-border-color); }

/* A chart on an authored page, drawn by `DocumentChart` as inline SVG.
 *
 * It stays in the prose column, as a table does, and for the same reason: the
 * charts a memo holds are a handful of quarters wide, and a figure that hangs
 * off both edges of the text reads as a different document. Below 30rem the
 * drawing keeps its proportions and scrolls in its own box rather than shrinking
 * its tick labels to nothing.
 *
 * Every mark carries its light colour as an attribute, for the exported file.
 * The rules below point the same marks at the theme's tokens, which is how one
 * piece of markup follows dark mode here and stays fixed there. */
.document-chart { margin: 1.75rem 0; }

.document-chart-title {
  color: var(--color-navy);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  margin-bottom: 0.5rem;
}

/* `.document-body ul` would give the legend bullets and an indent. */
.document-body .document-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  list-style: none;
  margin: 0 0 0.5rem;
  padding-left: 0;
  color: var(--rb-ink-body);
  font-size: 0.8125rem;
  line-height: 1.4;
}

.document-body .document-chart-legend li {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0;
}

.document-chart-key { flex: none; }

.document-chart-plot { overflow-x: auto; }

.document-chart-svg {
  display: block;
  width: 100%;
  min-width: 30rem;
  height: auto;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

/* The drawing's own white ground is for the exported file, which may open in a
 * dark window. On a page the page is the ground. */
.document-chart-bg { fill: transparent; }
.document-chart-grid { stroke: var(--rb-hairline); }
.document-chart-baseline { stroke: var(--rb-border-strong); }
:is(.document-chart-tick, .document-chart-category, .document-chart-unit, .document-chart-end) { fill: var(--rb-ink-muted); }
.document-chart-unit { font-weight: 600; }
.document-chart-ring { stroke: var(--bs-body-bg); }

.document-chart-series-1 { --rb-chart-series: var(--rb-chart-1); }
.document-chart-series-2 { --rb-chart-series: var(--rb-chart-2); }
.document-chart-series-3 { --rb-chart-series: var(--rb-chart-3); }
.document-chart-series-4 { --rb-chart-series: var(--rb-chart-4); }
.document-chart-series-5 { --rb-chart-series: var(--rb-chart-5); }
.document-chart-series-6 { --rb-chart-series: var(--rb-chart-6); }
.document-chart-series-7 { --rb-chart-series: var(--rb-chart-7); }
.document-chart-series-8 { --rb-chart-series: var(--rb-chart-8); }

/* By attribute, so a line keeps `fill="none"` and is not filled in as a shape.
 * A brand colour (`document-chart-custom`) matches neither rule on purpose: the
 * hex on the mark is the colour, in both themes. */
[class^="document-chart-series-"][fill]:not([fill="none"]) { fill: var(--rb-chart-series); }
[class^="document-chart-series-"][stroke] { stroke: var(--rb-chart-series); }

.document-body .document-chart-legend-axis { color: var(--rb-ink-muted); }

/* The quarter under the pointer, lifted so the reader sees which band the
 * tooltip is reading. `is-active` is the same lift when the styled tooltip is
 * running, since its overlay sits above the bands and takes their `:hover`. */
.document-chart-hit:hover,
.document-chart-hit.is-active { fill: var(--rb-wash); }

/* The styled tooltip's surface: one transparent rect over the plot, with no
 * `<title>` of its own, so the browser's tooltip for the band beneath cannot
 * open beside ours. */
.document-chart-overlay { cursor: crosshair; }

/* The tooltip sits on the figure rather than in the plot, whose sideways
 * scroll would clip it. */
.document-chart { position: relative; }

.document-chart-plot:focus-visible {
  outline: 2px solid var(--rb-accent);
  outline-offset: 2px;
  border-radius: 0.375rem;
}

/* One readout for every series at that category: the category, then a row
 * each with a short stroke of the series colour, its name and its value. The
 * value is the strong element, because the reader already has the series from
 * the legend and came here for the number. */
.rb-chart-tooltip {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 30;
  min-width: 11rem;
  max-width: min(20rem, calc(100% - 1rem));
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 0.625rem;
  background: var(--rb-canvas);
  box-shadow: 0 8px 24px var(--rb-shadow-drop);
  color: var(--rb-ink);
  font-size: 0.8125rem;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  opacity: 1;
  transition: opacity 90ms ease-out;
}

.rb-chart-tooltip[hidden] { display: block; opacity: 0; visibility: hidden; }

.rb-chart-tooltip-title {
  margin: 0 0 0.3rem;
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
}

.document-body .rb-chart-tooltip-rows,
.rb-chart-tooltip-rows {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.2rem 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.document-body .rb-chart-tooltip-rows li,
.rb-chart-tooltip-rows li { display: contents; }

.rb-chart-tooltip-key {
  width: 0.75rem;
  height: 0.1875rem;
  border-radius: 999px;
  background: var(--rb-chart-series, currentColor);
}

.rb-chart-tooltip-name { color: var(--rb-ink-body); overflow-wrap: anywhere; }
.rb-chart-tooltip-value { font-weight: 600; text-align: right; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .rb-chart-tooltip { transition: none; }
}

/* A series line that asked for something the chart could not do. The chart is
 * still drawn under it, so it reads as a note on the chart rather than as the
 * chart having failed. */
.document-chart-notice {
  margin-bottom: 0.75rem;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--rb-danger-edge);
  border-radius: 0.75rem;
  background: var(--rb-danger-wash);
  font-size: 0.8125rem;
  line-height: 1.45;
}

.document-body .document-chart-notice-reasons { margin: 0.25rem 0 0; padding-left: 1.1rem; }
.document-body .document-chart-notice-reasons li { margin-top: 0; }

.document-chart-caption {
  color: var(--bs-secondary-color);
  font-size: 0.8125rem;
  line-height: 1.45;
  margin-top: 0.5rem;
}

.document-chart-numbers { margin-top: 0.5rem; }

.document-chart-numbers > summary {
  width: fit-content;
  color: var(--color-cobalt);
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 500;
}

.document-chart-numbers[open] > summary { margin-bottom: 0.5rem; }

.document-chart-numbers caption {
  caption-side: top;
  color: var(--bs-secondary-color);
  font-size: 0.75rem;
  padding: 0.5rem 0.75rem 0;
  text-align: left;
}

/* Only the founder sees this; a reader is shown the table instead. */
.document-chart-error {
  padding: 0.85rem 1rem;
  border: 1px solid var(--rb-danger-edge);
  border-radius: 0.75rem;
  background: var(--rb-danger-wash);
  font-size: 0.875rem;
  line-height: 1.45;
}

.document-chart-error-title { color: var(--rb-danger); font-weight: 600; }
.document-chart-error-reason { margin-top: 0.25rem; }

.document-chart-block {
  position: relative;
  margin: 1.75rem 0;
  padding: 0.4rem;
  border-radius: 1rem;
  outline: 1px solid var(--bs-border-color);
}

.document-chart-block > .document-chart { margin: 0; }

/* Always visible rather than on hover, so it can be found on a touch screen. */
.document-chart-edit {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  padding: 0.2rem 0.65rem;
  border: 1px solid var(--rb-border-strong);
  border-radius: var(--rb-radius-pill);
  background: var(--bs-body-bg);
  color: var(--rb-ink);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
}

.document-chart-edit:hover { background: var(--rb-subtle); }

.document-chart-pending {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 10rem;
}

.document-chart-loading { color: var(--bs-secondary-color); font-size: 0.8125rem; }

.rb-chart-dialog { width: min(48rem, calc(100vw - 2rem)); }

.rb-chart-grid-box {
  max-height: 45vh;
  overflow: auto;
  border: 1px solid var(--bs-border-color);
  border-radius: 0.75rem;
}

.rb-chart-grid { border-collapse: separate; border-spacing: 0; width: 100%; }

.rb-chart-grid :is(th, td) {
  padding: 0.25rem;
  border-bottom: 1px solid var(--rb-hairline);
  vertical-align: middle;
}

.rb-chart-grid thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--rb-subtle);
}

.rb-chart-grid input { min-width: 6.5rem; }
.rb-chart-grid .rb-chart-grid-head { font-weight: 600; }
.rb-chart-grid :is(th, td):last-child { width: 2rem; }
.rb-chart-grid-remove:disabled { opacity: 0.35; }

/* A series' mark, colour and axis, under its name in the grid's header. */
.rb-chart-series-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.25rem;
  font-weight: 400;
}

.rb-chart-series-controls .form-select { width: auto; min-width: 5.5rem; }

.rb-chart-swatch-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border: 1px solid var(--bs-border-color);
  border-radius: 0.5rem;
  background: var(--rb-canvas);
}

.rb-chart-swatch-button:hover { border-color: var(--rb-border-strong); }

/* A palette swatch takes its colour from the same token the marks use, so it
 * is the dark step after dark. */
.rb-chart-swatch {
  display: block;
  width: 1rem;
  height: 1rem;
  border-radius: 0.3rem;
  background: var(--rb-chart-series, transparent);
}

.rb-chart-axis-toggle {
  display: inline-flex;
  padding: 0.125rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 999px;
  background: var(--rb-canvas);
}

.rb-chart-axis-toggle button {
  border: 0;
  border-radius: 999px;
  background: transparent;
  padding: 0.15rem 0.5rem;
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
}

.rb-chart-axis-toggle button[aria-pressed="true"] { background: var(--rb-subtle); color: var(--rb-ink); box-shadow: 0 1px 2px var(--rb-wash); }
.rb-chart-axis-toggle button:disabled { opacity: 0.4; }

/* The palette, opened from a swatch. A native popover, so it is in the top
 * layer and the grid's scroll box cannot clip it; placed beside its button by
 * the editor, which is why the UA's centring is taken off. */
.rb-chart-swatches {
  position: fixed;
  inset: auto;
  margin: 0;
  display: none;
  grid-template-columns: repeat(4, 1.9rem);
  gap: 0.3rem;
  padding: 0.45rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 0.75rem;
  background: var(--rb-canvas);
  box-shadow: 0 12px 32px var(--rb-shadow-drop);
}

.rb-chart-swatches:popover-open { display: grid; }

.rb-chart-swatch-choice {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0.5rem;
  background: transparent;
}

.rb-chart-swatch-choice .rb-chart-swatch { width: 1.2rem; height: 1.2rem; }
.rb-chart-swatch-choice:hover { background: var(--rb-subtle); }
.rb-chart-swatch-choice[aria-pressed="true"] { border-color: var(--rb-ink); }

.rb-media-dialog { width: min(38rem, calc(100vw - 2rem)); }

.rb-media-review-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.65rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 0.75rem;
}

.rb-media-review-thumb {
  width: 5rem;
  height: 3.5rem;
  flex: 0 0 auto;
  border-radius: 0.5rem;
  background: var(--bs-tertiary-bg);
  object-fit: cover;
}

.markdown-editor--expanded .markdown-editor-visual {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-inline: var(--markdown-gutter);
}

.rb-editor-modes {
  display: inline-flex;
  gap: 0.125rem;
  padding: 0.125rem;
  border-radius: 999px;
  background: var(--rb-subtle);
}

.rb-editor-mode {
  border: 0;
  border-radius: 999px;
  background: transparent;
  padding: 0.25rem 0.625rem;
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
}

.rb-editor-mode-active {
  background: var(--rb-canvas);
  color: var(--rb-ink);
  box-shadow: 0 1px 2px var(--rb-wash);
}

/* The page behind it must not scroll under the fixed box. */
.markdown-editor-open {
  overflow: hidden;
}

/* The tools scroll sideways on a narrow screen. No scrollbar for it: a bar of
 * twelve buttons with a track under it reads as a broken layout, and the row is
 * short enough that what is off the end is obvious from the half-clipped
 * button at the edge. */
.markdown-editor-tools {
  scrollbar-width: none;
}

.markdown-editor-tools::-webkit-scrollbar {
  display: none;
}

/* ============================================================
   The rail: shown or hidden.

   The class is applied by an inline script in <head> before the first paint
   and by `sidebar_controller` afterwards; see `layouts/_sidebar_state` for why
   both. There used to be a third, icons-only state at 4.5rem, with the labels
   taken off screen and a hover tip drawn from `data-label`. It is gone from
   both surfaces: a column of glyphs named nothing to anyone who did not already
   know them, and the room's tree lost its branches. `.is-collapsed` is no
   longer written anywhere, so nothing here reads it.
   ============================================================ */
.app-sidebar { width: 15rem; }
.app-sidebar.is-hidden { display: none !important; }

/* The workspace switcher's menu has to escape the rail, and the nav below it
 * is a scroll container, so the head is not. */
.app-sidebar .sidebar-head { overflow: visible; }

/* By class rather than by id, because there are two of these: the founder's
 * nav and the room's contents rail run on the same chassis
 * (`layouts/_nav_rail`). */
.app-sidebar .sidebar-nav { overflow-y: auto; overflow-x: hidden; }

/* The room's wordmark at the head of its contents rail. A flex item's
 * `min-width: auto` is its intrinsic width, so a long workspace name drawn in
 * place of a logo would push past the rail's hairline instead of truncating. */
.rb-viewer-brand > * { min-width: 0; }

/* ============================================================
   The docs pages — zero Tailwind.

   `docs/_shell` and `docs/_toc` are written in Bootstrap utilities plus the
   classes below: the proof that a real surface runs on the ported framework
   rather than Bootstrap sitting in the build unused.

   What Bootstrap covers, Bootstrap does (d-flex, d-none/d-lg-block, px-3,
   mb-2, list-unstyled). What is here is what it has no answer for: a column
   that sticks to the viewport, the tint-formula active state, the measure, and
   the reading typography.
   ============================================================ */
/* The gutter the rail's collapse toggle sits in.
 *
 * Every other page gets it from `page_frame_class`'s left padding; the docs
 * layout is a flex row starting at the content column's own left edge, so the
 * toggle was landing on top of the TOC's first heading. 3rem puts the TOC's
 * left edge where every other page's title starts, which is also what leaves
 * the toggle somewhere to be. Below `lg` the toggle is not rendered, so neither
 * is the gutter. */
@media (min-width: 64rem) {
  .docs-shell { padding-left: 3rem; }
}

.docs-measure { max-width: 46rem; }

/* Lands the docs title on the same centre line as every other page's — see
 * `page_frame_class`, which does the same job for the app side. A phone keeps
 * the extra half-step beneath its own header; at desktop the rail supplies the
 * edge and the title moves up with the rest of the app. */
.docs-column { padding-top: 2.0625rem; }

@media (min-width: 992px) {
  .docs-column { padding-top: 1.5625rem; }
}

/* The same screen title as every other page — `page_title_class` in Ruby, this
 * in CSS, because the docs shell carries no Tailwind. It ran at 1.875rem with
 * an eyebrow above it, which put the docs title 18px below the title on every
 * other page in the app. */
.docs-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.125rem;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--rb-ink);
}

.docs-lead {
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--rb-ink-muted);
}

.docs-note { font-size: 0.8rem; color: var(--rb-ink-muted); }

/* ---------- the TOC column ---------- */
.docs-toc {
  flex: 0 0 16rem;
  width: 16rem;
  align-self: flex-start;
  position: sticky;
  top: 0;
  max-height: 100vh;
  overflow-y: auto;
  border-right: 1px solid var(--rb-hairline);
}

.docs-toc-heading {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--rb-ink-muted);
}

.docs-toc-link {
  display: block;
  padding: 0.35rem 0.75rem;
  border-radius: 14px;
  font-size: 0.9rem;
  color: var(--rb-ink-body);
  text-decoration: none;
  transition: background 0.12s ease, color 0.12s ease;
}

.docs-toc-link:hover { background: var(--rb-wash); color: var(--rb-ink); }

/* The tint formula: the hue at 14% alpha behind its own 600 shade. */
.docs-toc-link.is-active {
  background: var(--rb-tint-wash);
  color: var(--rb-accent-text);
  font-weight: 600;
}

.docs-toc-anchors {
  margin: 0.25rem 0 0 0.75rem;
  padding-left: 0.35rem;
  border-left: 1px solid var(--rb-hairline);
}

.docs-toc-anchor {
  display: block;
  padding: 0.2rem 0.75rem;
  border-radius: 10px;
  font-size: 0.82rem;
  color: var(--rb-ink-muted);
  text-decoration: none;
}

.docs-toc-anchor:hover { background: var(--rb-wash); color: var(--rb-ink); }

/* ---------- the phone's page menu ---------- */
.docs-page-menu-summary {
  display: flex;
  cursor: pointer;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 14px;
  background: var(--rb-canvas);
  font-weight: 600;
  color: var(--rb-ink);
}

.docs-page-menu-caret { width: 1rem; height: 1rem; color: var(--rb-ink-faint); }

.docs-page-menu-list {
  padding: 0.5rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 14px;
  background: var(--rb-canvas);
}

.docs-jump {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  border-top: 1px solid var(--rb-hairline);
  scrollbar-width: none;
}

.docs-jump::-webkit-scrollbar { display: none; }

.docs-jump-link {
  white-space: nowrap;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 999px;
  font-size: 0.82rem;
  color: var(--rb-ink-muted);
  text-decoration: none;
}

/* ---------- the reading column ---------- */
.docs-body {
  color: var(--rb-ink-body);
  font-size: 0.95rem;
  line-height: 1.7;
}

/* Anchored from the TOC, so a heading must not arrive under the sticky mobile
 * header. Generous, because the phone header is the taller of the two cases. */
/* The format legend on the documents page: the same tiles the room leads its
 * rows with, beside the extensions they cover and what a reader gets.
 *
 * Six words at most and the grid is a fixed three, halving to two and then one,
 * because six divides by both and an `auto-fill` track leaves a hole the width
 * of a card on the counts in between, which reads as a card that failed to
 * load. */
.docs-formats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}

.docs-format {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.875rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 14px;
}

.docs-format-word { font-size: 0.9375rem; font-weight: 600; color: var(--rb-ink); }
.docs-format-ext { margin-top: 0.125rem; font-size: 0.8125rem; color: var(--rb-ink-body); }
.docs-format-reading { margin-top: 0.375rem; font-size: 0.75rem; color: var(--rb-ink-muted); }

@media (max-width: 60rem) {
  .docs-formats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 36rem) {
  .docs-formats { grid-template-columns: minmax(0, 1fr); }
}

.docs-section { scroll-margin-top: 6rem; }
.docs-section + .docs-section { margin-top: 2.5rem; }

.docs-body h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.4rem;
  letter-spacing: -0.03em;
  line-height: 1.15;
  color: var(--rb-ink);
}

.docs-body h3 {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--rb-ink);
}

/* The rhythm is set inside the section, not on `.docs-body`: every paragraph is
 * a child of a <section>, so `.docs-body > * + *` matches the sections and
 * nothing in them. */
.docs-section > * + * { margin-top: 0.875rem; }
.docs-section > :is(h2, h3) + * { margin-top: 0.625rem; }
.docs-section > * + h3 { margin-top: 1.5rem; }

.docs-body a { color: var(--rb-accent-text); text-decoration: underline; text-underline-offset: 2px; }
.docs-body a:hover { color: var(--rb-accent-text-strong); }
.docs-body strong { color: var(--rb-ink); font-weight: 600; }

.docs-body ul { list-style: disc; padding-left: 1.25rem; }
.docs-body ol { list-style: decimal; padding-left: 1.25rem; }
.docs-body li::marker { color: var(--rb-marker); }
.docs-body li + li { margin-top: 0.375rem; }

.docs-code {
  border-radius: 6px;
  background: var(--rb-hairline-soft);
  padding: 0.125rem 0.375rem;
  font-family: var(--bs-font-monospace);
  font-size: 0.8125rem;
  color: var(--rb-ink);
}

/* A table of endpoints is wider than a phone and always will be, so it scrolls
 * inside its own box rather than making the page scroll sideways. */
.docs-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--rb-hairline);
  border-radius: 12px;
}

.docs-body table { width: 100%; border-collapse: collapse; text-align: left; margin: 0; }

.docs-body th,
.docs-body td {
  padding: 0.6rem 1rem;
  vertical-align: top;
  border-top: 1px solid var(--rb-hairline);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* No fill, matching the app's other tables. */
.docs-body thead th {
  border-top: 0;
  color: var(--rb-ink-muted);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.docs-foot {
  border-top: 1px solid var(--rb-hairline);
  font-size: 0.82rem;
  color: var(--rb-ink-muted);
}

/* ============================================================
   The filter toolbar, ported from taskjane.

   Class names are taskjane's own (.page-header-filters-bar, .msg-chip,
   .contact-search) rather than new ones, so the two apps can be read against
   each other and a fix in one is findable in the other.

   In the components layer, so a template can still override any of it with a
   utility — which is the rule everywhere else in this file.

   The shape it replaces: a search field, a row of filter buttons and a count
   each taking a full line of the page, three stacked bands before the table
   started. One row now, and the counts live inside the chips they belong to
   rather than in a sentence above the table.
   ============================================================ */
  .page-header-filters-bar {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
    overflow: visible;
  }

  /* Everything in the row is locked to one height. The search input has a
   * larger font than the chips and Safari inflates it further, so an explicit
   * box-sized height is what actually keeps them even. */
  .page-header-filters-bar .msg-chip,
  .page-header-filters-bar .contact-search,
  .page-header-filters-bar .toolbar-control {
    height: 2.25rem;
    box-sizing: border-box;
  }

  /* Pushed to the far end of the row. */
  .page-header-filters-bar .network-toolbar-menus {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    flex-shrink: 0;
    margin-left: auto;
  }

  .msg-chip-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .msg-chip-row::-webkit-scrollbar { display: none; }

  .msg-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--rb-sheet-edge);
    background: var(--rb-sheet);
    color: var(--rb-ink-body);
    font-weight: 600;
    font-size: 0.82rem;
    white-space: nowrap;
    text-decoration: none;
    transition: background 0.12s ease, border-color 0.12s ease;
  }

  /* Only family and line-height are inherited. The `font` shorthand would also
   * reset size and weight, and this selector outranks the plain `.msg-chip`
   * one — a button chip would silently render at body size beside its anchor
   * neighbours. */
  button.msg-chip {
    cursor: pointer;
    font-family: inherit;
    line-height: inherit;
  }

  .msg-chip:hover {
    background: var(--rb-sheet-hover);
    color: var(--rb-ink);
  }

  /* The tint formula: the hue at 10% alpha behind its own 700 shade. */
  .msg-chip.is-active {
    border-color: var(--rb-tint-edge);
    background: var(--rb-tint-wash-soft);
    color: var(--rb-accent-text-strong);
  }

  /* The count belongs to the filter it counts, which is what stops it needing
   * a line of its own above the table. Muted by default — a total is metadata,
   * not an alert. */
  .msg-chip-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--rb-count-bg);
    color: var(--rb-count-fg);
    font-size: 0.62rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    flex-shrink: 0;
  }

  .msg-chip.is-active .msg-chip-count {
    background: var(--rb-tint-wash);
    color: var(--rb-accent-text-strong);
  }

  .contact-search {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--rb-sheet-edge-strong);
    background: var(--rb-sheet);
    flex: 0 0 240px;
    width: 240px;
    min-width: 0;
  }

  .contact-search:focus-within {
    border-color: var(--rb-tint-edge);
  }

  .contact-search-icon { color: var(--rb-ink-faint); flex-shrink: 0; }

  .contact-search-field {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    font-size: 0.82rem;
    color: var(--rb-ink);
  }

  .contact-search-field::placeholder { color: var(--rb-ink-faint); }

  .contact-search-clear {
    display: inline-flex;
    align-items: center;
    color: var(--rb-ink-faint);
    text-decoration: none;
    flex-shrink: 0;
  }

  .contact-search-clear:hover { color: var(--rb-ink-body); }

  /* Below the chips breakpoint the search takes the row and the chips scroll
   * under it, rather than the two fighting over one line. */
  @media (max-width: 63.99rem) {
    .page-header-filters-bar { flex-wrap: wrap; }
    .contact-search { flex: 1 1 100%; width: auto; }
    .page-header-filters-bar .network-toolbar-menus { margin-left: 0; }
  }

  /* On a phone they wrap instead. A sideways scroller is the right answer for a
   * table, which cannot be folded, and the wrong one for four pills: at 375px
   * the documents library showed "Any state", "Nothing on it yet" and half of
   * "Hidden" with its count off the edge, and the library's fourth state was
   * not on screen at all. A count you cannot see is worse than no count, and a
   * filter you cannot see does not exist.
   *
   * `flex-basis: 100%` so the chips take the line and the room and sort menus
   * keep their own, rather than being squeezed to the end of the last chip row. */
  @media (max-width: 35.99rem) {
    .msg-chip-row {
      flex: 1 1 100%;
      flex-wrap: wrap;
      overflow-x: visible;
    }
  }

/* The filters and the bulk bar share one band and swap on selection. Written
 * as CSS rather than toggled utilities so the swap is one class on the card
 * (`is-selecting`, set by bulk_select_controller) instead of two per element,
 * and so the idle state costs no JavaScript at all. */
.bulk-scope .bulk-active { display: none !important; }
.bulk-scope.is-selecting .bulk-idle { display: none !important; }
.bulk-scope.is-selecting .bulk-active { display: flex !important; }

/* The split chip, ported from taskjane: a label and a caret sharing one pill,
 * divided by a hairline. A three-option segmented control spends the width of
 * all three options saying which one is on; this spends the width of one.
 *
 * `.msg-chip-split-caret` is the only half that opens the menu, so the label
 * stays a plain summary target and the whole pill still reads as one control. */
  .msg-chip-split {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    height: 2.25rem;
    box-sizing: border-box;
    border-radius: 999px;
    border: 1px solid var(--rb-sheet-edge);
    background: var(--rb-sheet);
    transition: background 0.12s ease, border-color 0.12s ease;
    cursor: pointer;
    list-style: none;
  }

  .msg-chip-split::-webkit-details-marker { display: none; }
  .msg-chip-split:hover { background: var(--rb-sheet-hover); }

  .msg-chip-split-main {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0 0.55rem 0 0.85rem;
    color: var(--rb-ink-body);
    font-weight: 600;
    font-size: 0.82rem;
    white-space: nowrap;
  }

  .msg-chip-split-label { color: var(--rb-ink-muted); }

  .msg-chip-split-caret {
    display: inline-flex;
    align-items: center;
    padding: 0 0.5rem 0 0.4rem;
    border-left: 1px solid var(--rb-sheet-rule);
    color: var(--rb-ink-muted);
  }

/* ============================================================
   Toasts.

   Flash messages used to be a band inside `main`, above the page. Every notice
   pushed the whole page down by its own height, so the row you had just acted
   on moved out from under the cursor — and it moved back a moment later on the
   next navigation. The stack is fixed to the viewport instead: it confirms what
   happened without touching the layout of the thing that happened.

   Top right rather than centred: the page title and the primary action are what
   a founder is looking at after a form submit, and the centre of the top edge is
   where the title is.
   ============================================================ */
.rb-toast-stack {
  position: fixed;
  top: max(1rem, env(safe-area-inset-top, 0px));
  right: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: min(24rem, calc(100vw - 2rem));

  /* Over the preview banner (50), the menus (40) and the mobile header (30). */
  z-index: 60;

  /* The stack is taller than the toasts in it once one is dismissed; only the
   * toasts themselves should swallow clicks. */
  pointer-events: none;
}

.rb-toast {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  padding: 0.75rem 0.75rem 0.75rem 0.875rem;
  border: 1px solid var(--color-gray-200);
  border-radius: 0.75rem;
  background-color: var(--color-white);
  box-shadow: var(--shadow-card-lg);
  color: var(--color-gray-700);
  font-size: 0.875rem;
  line-height: 1.45;
  pointer-events: auto;
  animation: rb-toast-in 0.16s ease-out both;
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.rb-toast-leaving {
  opacity: 0;
  transform: translateY(-0.25rem);
}

@keyframes rb-toast-in {
  from { opacity: 0; transform: translateY(-0.375rem); }
  to { opacity: 1; transform: translateY(0); }
}

/* A dot, not a coloured panel. Which of two things this is matters less than
 * the sentence in it, and a red card for "Email can't be blank" reads as an
 * incident rather than a correction. */
.rb-toast-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  margin-top: 0.4375rem;
  border-radius: 999px;
  background-color: var(--color-cobalt);
}

.rb-toast-alert { border-color: var(--bs-danger-border-subtle); }
.rb-toast-alert .rb-toast-dot { background-color: var(--bs-danger); }

.rb-toast-close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: 0.375rem;
  background: transparent;
  color: var(--color-gray-400);
  transition: color 0.12s ease, background-color 0.12s ease;
}

.rb-toast-close:hover {
  background-color: var(--color-gray-100);
  color: var(--color-gray-700);
}

.rb-toast-close-icon {
  width: 0.875rem;
  height: 0.875rem;
}

@media (prefers-reduced-motion: reduce) {
  .rb-toast { animation: none; transition: none; }
  .rb-toast-leaving { opacity: 0; }
}

/* ── The folder tree's branches ─────────────────────────────────────────────
   Native <details>, like every other disclosure here, so collapse costs no JS
   and stays keyboard-reachable. The summary holds the chevron and the folder's
   own link side by side: the chevron (and the row's dead space) toggles, the
   name navigates, which is the split a file manager taught everyone. */
.rb-tree > summary { list-style: none; cursor: pointer; }
.rb-tree > summary::-webkit-details-marker { display: none; }

/* A row of the tree, and the kebab that sits over its right edge.
 *
 * The menu is a sibling of the row's link (or of the branch's `<summary>`),
 * positioned over it, rather than a child: a click anywhere inside a summary
 * toggles its details, so a menu nested in one would collapse the branch it
 * was opened from. On a branch the positioned ancestor is the whole `details`,
 * children included, and `top` is what keeps the button on the summary's line.
 *
 * The offsets are here rather than in utilities because they are a 24px button
 * being centred on a 28px row, which no spacing scale has a step for. */
.rb-tree-row { position: relative; }

.rb-tree-actions {
  position: absolute;
  top: 0.0625rem;
  right: 0.125rem;
  z-index: 5;
}

/* Only on the row you are pointing at.
 *
 * Not `rb-reveal`, which reveals on `:hover` of the container it sits in: a
 * branch's container holds everything inside it, so pointing at one document
 * lit the kebab of the folder above it and of the folder above that. `:has`
 * asks the narrower question — is the pointer on this row's own line — and the
 * two extra selectors keep it on screen while it is being used: while the
 * pointer is on the button itself, which is not on the row, and while its menu
 * stands open, which is when it must not vanish under the cursor.
 *
 * Behind the same `hover: hover` guard the rest of the app's reveals use: on a
 * touch screen there is no hover to reveal anything with, and a control that
 * cannot be reached is worse than one that is always drawn. */
@media (hover: hover) {
  .rb-tree-actions { opacity: 0; transition: opacity 0.12s ease; }

  .rb-tree-row:has(> details > summary:hover) > .rb-tree-actions,
  .rb-tree-row:has(> a:hover) > .rb-tree-actions,
  .rb-tree-actions:hover,
  .rb-tree-actions:focus-within,
  .rb-tree-actions:has(details[open]) { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .rb-tree-actions { transition: none; }
}

/* Drawn pointing down in the icon set; a closed branch turns it toward the
   name it is hiding. */
.rb-tree-chevron { color: var(--rb-ink-muted); transform: rotate(-90deg); transition: transform 0.12s ease; }
.rb-tree[open] > summary .rb-tree-chevron { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .rb-tree-chevron { transition: none; }
}

/* ── A row whose whole face is the link ─────────────────────────────────────
   The rooms list used to be clickable only on the title, which is a target the
   width of the word "Investor data room" on a row 900px wide, and every miss
   lands on nothing at all.

   Bootstrap's `.stretched-link` does the work: the anchor's ::after covers the
   nearest positioned ancestor, so the row becomes the target while the anchor
   stays the one real link — no nested interactive elements, and the keyboard
   still tabs to a name rather than to a row. The controls at the other end sit
   above it on `.z-2`, so they keep their own clicks.

   The wash is what says it is clickable at all. Without it the row is a target
   with no sign that it is one, which is worse than the small link it replaces. */
.rb-row-link { position: relative; transition: background-color 0.15s ease; }
.rb-row-link:hover { background-color: var(--rb-wash); }

/* Keyboard parity: tabbing to the name should light the row it belongs to the
   same way pointing at it does. */
.rb-row-link:focus-within { background-color: var(--rb-wash); }

/* A stretched row may still carry its own controls. Lift only those controls
   above the link's transparent hit area; the rest of the row remains one large
   target without inventing a second click handler or nesting links. */
.rb-row-link .rb-row-control,
.rb-row-link a:not(.stretched-link),
.rb-row-link button,
.rb-row-link input,
.rb-row-link summary {
  position: relative;
  z-index: 2;
}

/* An open row menu has to clear the rows beneath it. Some lists use a Bootstrap
   `.z-2` control cluster and the room lists use `.rb-row-control`; either one
   is a stacking context whose menu cannot escape until the cluster itself is
   lifted. `.z-2` is `!important`, so that override has to be as well. */
.rb-row-link:has(details.account-menu[open]) .z-2 { z-index: 40 !important; }
.rb-row-link:has(details.account-menu[open]) .rb-row-control { z-index: 40; }

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

/* ── Who a room is shared with ──────────────────────────────────────────────
   A row of overlapping coins in the room's header, one per person holding a
   link, and the whole row is a link to the room's Links tab.

   Overlapped rather than spaced, because this is one fact — who has it — and a
   line of separate circles reads as a list to work through. The ring is the
   page's own ground rather than a border colour: what makes an overlapping
   stack legible is each coin cutting the one behind it, and a grey rule around
   every circle draws attention to the seam instead of hiding it.

   The count sits in the last coin rather than after the row as text, so the
   stack keeps one shape whether it says four people or forty, and only four
   faces are ever drawn: past that a row of initials is a crowd to read rather
   than a fact to glance at, and the Links tab is where the list belongs.

   2.25rem is the height of the buttons it sits beside — 0.8125rem of padding,
   a 1.3125rem line and a border either side — because the three of them share
   one row and a coin a few pixels short of the pills reads as misaligned
   rather than as smaller. `min-width` rather than `width`, so the count coin
   grows for "+112" instead of squeezing it. */
.rb-avatars {
  display: inline-flex;
  align-items: center;
  padding-left: 0.5rem;
  text-decoration: none;
}

.rb-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.25rem;
  height: 2.25rem;
  padding: 0 0.25rem;
  margin-left: -0.5rem;
  border: 2px solid var(--rb-canvas);
  border-radius: 50rem;
  background-color: var(--rb-subtle);
  color: var(--rb-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

/* One coin at the head of a row, rather than a stack of them on a header.
 *
 * The overlap and the canvas ring above are what make four faces read as a
 * group; a single lead beside a name wants neither, and it takes the 2rem the
 * document rows' tiles are, so a section's two lists share one column of
 * squares. Same monogram, same fill: a person is drawn one way in this app. */
.rb-avatar-lead {
  min-width: 2rem;
  width: 2rem;
  height: 2rem;
  margin-left: 0;
  padding: 0;
  border: 0;
}

/* The overflow coin is the quietest of them: it is a number, not a person. */
.rb-avatar-rest {
  background-color: var(--rb-canvas);
  color: var(--rb-ink-muted);
  box-shadow: inset 0 0 0 1px var(--rb-hairline);
}

.rb-avatars:hover .rb-avatar { color: var(--rb-ink); }

/* The colour well on the branding form. A bare `input[type=color]` is a grey
   OS button in every browser and does not read as part of the form; this gives
   it the field's own border and radius so it sits beside the text inputs. */
.rb-colour-well {
  inline-size: 3rem;
  block-size: 2.5rem;
  padding: 0.2rem;
  border: 1px solid var(--rb-rule);
  border-radius: 0.5rem;
  background: var(--rb-surface);
  cursor: pointer;
}

/* The page strip under the time-on-each-page chart.
 *
 * Scrolls in its own box rather than making the page scroll sideways, which is
 * the rule every wide thing in this app follows. A fifty-page deck is a long
 * strip and that is fine: the useful reading is the first screenful, and the
 * rest is there for the founder who goes looking. */
.rb-page-strip {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding-bottom: 0.5rem;
}

.rb-page-thumb {
  flex: 0 0 auto;
  inline-size: 5.5rem;
  margin: 0;
}

.rb-page-thumb img,
.rb-page-thumb-blank {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  border: 1px solid var(--rb-rule);
  border-radius: 0.25rem;
  background: var(--rb-surface);
  display: block;
}

.rb-page-thumb figcaption {
  margin-top: 0.25rem;
  font-size: 0.6875rem;
  color: var(--rb-ink-soft);
  text-align: center;
}

/* A page nobody read. Dimmed rather than hidden: the gap is the finding. */
.rb-page-thumb-cold img { opacity: 0.35; }
.rb-page-thumb-cold figcaption { color: var(--rb-ink-faint); }

/* ---- Search ---- */

/* The search dialog sits near the top rather than centred: its height changes
 * with every keystroke, and a box that recentres as it grows jumps under the
 * pointer. Wider than the 40rem modal because a row is a title, a sentence and
 * a location side by side. */
.rb-search-dialog {
  width: min(46rem, calc(100vw - 2rem));
  margin: 8dvh auto auto;
  padding: 0;
}
.rb-search-dialog[open] { display: block; }

.rb-search-field {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border-bottom: 1px solid var(--rb-hairline);
}
.rb-search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  padding: 0.25rem 0;
  background: transparent;
  color: var(--rb-ink);
  font: inherit;
  font-size: 1.0625rem;
  outline: none;
}
.rb-search-input::placeholder { color: var(--rb-ink-faint); }
.rb-search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* A key hint. The `<kbd>` reboot styles it as a dark badge, which is a code
 * sample's idea of a key and not a hint beside a field. */
.rb-kbd {
  padding: 0.0625rem 0.4rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 0.375rem;
  background: var(--rb-subtle);
  color: var(--rb-ink-faint);
  font: inherit;
  font-size: 0.6875rem;
  line-height: 1.4;
}

.rb-search-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--rb-hairline);
}
.rb-search-chip {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--rb-hairline);
  border-radius: 999px;
  color: var(--rb-ink-muted);
  font-size: 0.8125rem;
  font-weight: 500;
  text-decoration: none;
}
.rb-search-chip:hover { color: var(--rb-ink); background: var(--rb-subtle); }
.rb-search-chip.is-active {
  border-color: var(--rb-accent-text);
  background: var(--rb-accent-wash);
  color: var(--rb-accent-text);
}

.rb-search-results {
  display: block;
  max-height: min(60dvh, 34rem);
  overflow-y: auto;
  padding: 0.5rem 0;
}
.rb-search-results[busy] { opacity: 0.6; }
.rb-search-empty { padding: 1rem 1.25rem; margin: 0; }

.rb-search-group + .rb-search-group { border-top: 1px solid var(--rb-hairline); margin-top: 0.5rem; padding-top: 0.5rem; }
.rb-search-label {
  margin: 0;
  padding: 0.5rem 1.25rem 0.25rem;
  color: var(--rb-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.rb-search-result {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding: 0.625rem 1.25rem;
  color: var(--rb-ink);
  text-decoration: none;
}
.rb-search-result:hover,
.rb-search-result:focus-visible,
.rb-search-result.is-active { background: var(--rb-subtle); color: var(--rb-ink); outline: none; }
.rb-search-icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.625rem;
  background: var(--rb-accent-wash);
  color: var(--rb-accent-text);
}
.rb-search-title { font-weight: 600; font-size: 0.9375rem; line-height: 1.3; }
.rb-search-snippet { margin-top: 0.125rem; color: var(--rb-ink-muted); font-size: 0.8125rem; line-height: 1.4; }
.rb-search-meta { margin-top: 0.125rem; color: var(--rb-ink-faint); font-size: 0.75rem; }
/* The chevron glyph points down; a row that opens something points on. */
.rb-search-go { flex-shrink: 0; color: var(--rb-ink-faint); transform: rotate(-90deg); }

/* The matched words. A wash rather than the browser's yellow, and the text's
 * own colour rather than black, so a mark reads in both themes. */
.rb-search-mark {
  padding: 0 0.1em;
  border-radius: 0.2em;
  background: var(--rb-accent-wash);
  color: inherit;
  font-weight: 600;
}

/* On the search page the panel is a card rather than a dialog: same insides,
 * no cap on the results. */
.rb-search-panel .rb-search-results { max-height: none; }
.rb-search-dialog .rb-search-results { max-height: min(60dvh, 34rem); }
