/* ==========================================================================
   FunnelCAD — app stylesheet
   The design language is docs/DESIGN.md: a CAD program for funnels. Ink on white with ONE blue
   (--accent) for selection, focus, links and the active state; square everywhere; dense; every
   number in IBM Plex Mono with tabular figures; one hard offset shadow on floating surfaces.
   The @font-face rules are css/fonts/fonts.css (generated by tools/fonts.mjs, self-hosted).
   test/design-tokens.test.mjs pins the load-bearing values and computes the contrast.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */

:root {
  /* Surfaces (DESIGN.md §2.1). The side panels and the tool strip are --panel, the design's
     #f6f7f8; their controls stay --surface, bounded by --line-ui (3.03:1 on --panel). */
  --bg: #f6f7f8;
  --panel: #f6f7f8;
  --surface: #ffffff;
  --surface-2: #fbfbfc;
  --band: #f1f2f4;
  --hover: #eceef1;
  --select: #eef3fd;
  --select-2: #e3ebfb;
  /* A translucent accent layer: the marquee and a drop target over the canvas. */
  --select-wash: rgba(27, 95, 217, 0.06);

  /* The menu bar is dark in BOTH themes. */
  --chrome: #17191c;
  --chrome-hover: #2b2e33;
  --chrome-text: #c7cad0;
  --chrome-title: #ffffff;
  /* On the dark bar: a rule, the save indicator's and the suffix's text (6.7:1 on --chrome), a
     control's boundary (5.6:1), the light Sign in button and the save indicator's tone squares
     (saved, saving, not saved), which the light theme's --ok and --danger are too dark for. */
  --chrome-line: #3a3e45;
  --chrome-muted: #9aa0a8;
  --chrome-line-ui: #8b9099;
  --chrome-button: #f3f4f6;
  --chrome-button-text: #15171a;
  --chrome-warn: #d9a441;
  --chrome-ok: #4ec77a;
  --chrome-danger: #f0736a;

  /* The one hard offset shadow (floating surfaces only) and the modal backdrop. */
  --drop: rgba(0, 0, 0, 0.14);
  --overlay: rgba(21, 23, 26, 0.36);

  /* Ink (§2.2). No text is lighter than --muted. On --band, --hover and --select the micro-labels
     step up to --text-2: --muted is 4.44:1 on --band. */
  --ink: #15171a;
  --ink-2: #33373d;
  --text-2: #5f646c;
  --muted: #6b7079;
  --accent: #1b5fd9;
  --accent-text: #ffffff;
  /* What sits on a solid --ink fill (a primary button, a checked box, a toast), and the ink fill
     under hover. The status squares on an ink toast take the other theme's status colour. */
  --on-ink: #ffffff;
  --ink-hover: #2b2e33;
  --on-ink-ok: #4ec77a;
  --on-ink-warn: #d9a441;
  --on-ink-danger: #f0736a;
  /* The unlit cells of the busy indicator on an ink fill (a toast, a primary button's busy face):
     --on-ink at 40 % (docs/PLANS.md §9.2; the lit cell clears 3:1 against it, test/contrast). */
  --on-ink-faint: rgba(255, 255, 255, 0.4);

  /* Lines (§2.3). --line-ui bounds an interactive control and must clear 3:1; --line and the
     softer steps are decorative. --edge draws the connectors on the canvas paper. */
  --line-ui: #8a8f98;
  --line: #c3c7cd;
  --line-mid: #d5d8dd;
  --line-soft: #e1e3e7;
  --edge: #5f646c;

  /* The share heatmap's five levels (docs/SHARING.md §12.4): an ink ramp of existing tokens, no new
     colour. Aliases on :root, so in dark they follow the dark values of the tokens they name. */
  --heat-0: var(--line-soft);
  --heat-1: var(--line);
  --heat-2: var(--line-ui);
  --heat-3: var(--text-2);
  --heat-4: var(--ink);

  /* Status (§2.4). --warn is text as well as a square, so it is the darker #8a6100 (5.5:1),
     not the amber tag (#a97400 is 4.05:1) — DESIGN.md §12. */
  --ok: #1f7a3d;
  --warn: #8a6100;
  --danger: #b42318;
  --ok-tint: rgba(31, 122, 61, 0.07);
  /* The scorecard's curves (§7.5): the area that pays for itself and the typical year's band (--ok-area),
     the rest of a year's profit (--ok-pale), a loss (--danger-area) and the band below €0 (--danger-band);
     the exported picture has them as solid colours (js/export.js FIGURE_FILL). */
  --ok-area: rgba(31, 122, 61, 0.55);
  --ok-pale: rgba(31, 122, 61, 0.18);
  --danger-area: rgba(180, 35, 24, 0.22);
  --danger-band: rgba(180, 35, 24, 0.5);
  --danger-tint: rgba(180, 35, 24, 0.06);

  /* Colour tags: the 3px bar and the 9px swatch share the colour; the tint is a translucent
     layer. A tag never enters a computation. */
  --tag-gray: #6e6e6e;
  --tag-gray-tint: rgba(110, 110, 110, 0.12);
  --tag-blue: #2f6fd0;
  --tag-blue-tint: rgba(47, 111, 208, 0.1);
  --tag-green: #1f7a3d;
  --tag-green-tint: rgba(31, 122, 61, 0.1);
  --tag-amber: #a97400;
  --tag-amber-tint: rgba(169, 116, 0, 0.12);
  --tag-red: #b42318;
  --tag-red-tint: rgba(180, 35, 24, 0.1);
  --tag-purple: #6b46c1;
  --tag-purple-tint: rgba(107, 70, 193, 0.1);
  --tag-teal: #0f766e;
  --tag-teal-tint: rgba(15, 118, 110, 0.1);

  /* Canvas paper (§2.5): a 16px minor and an 80px major grid. */
  --grid-minor: rgba(30, 50, 80, 0.045);
  --grid-major: rgba(30, 50, 80, 0.105);

  /* Type (§3). Both faces self-hosted in css/fonts/. */
  --font: 'IBM Plex Sans', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Metrics (§4). The four rows of the shell and its side columns; controls are 24px, buttons,
     the tool strip and dialogs 26px. Below 1120px the tree column goes and the sheet narrows.
     The side columns are 240 and 380px since the owner's decision of 2026-09-28 (user feedback:
     the panels were too narrow to read; they were 208 and 316px). */
  --menubar-h: 28px;
  --strip-h: 40px;
  --cmdline-h: 26px;
  --tree-w: 240px;
  --sheet-w: 380px;
  /* The label cell of a sheet row (§4.5): the design's 92px, 108px at the desktop's type (§3.1);
     100px in the 340px sheet, so the eight tag swatches (8 x 20 + 7 x 4 = 188px) still stand in
     one line beside it. */
  --field-label-w: 108px;
  --control-h: 24px;
  --control-h-lg: 26px;
  --gap: 8px;
  --shadow: 8px 8px 0 var(--drop);

  color-scheme: light;
}

/* The desktop type scale (§3.1; the owner's decision of 2026-09-28 from user feedback: the
   desktop's type was too small to read). Every size of the chrome is written
   `var(--fs-…, <compact size>)`: from 760px up the token is set and the text is one step larger;
   below it (the phone layout of §9) the token is not, and the fallback — the compact size the
   phone was designed at — stands, exactly as before. The canvas cards are not on this scale: their
   rules keep literal sizes (their geometry, ports, measured heights and the export depend on it),
   and .fb-world pins the size its contents inherit. */
@media (min-width: 760px) {
  :root {
    --fs-xs: 11px;  /* micro-labels, captions, keys — the compact 8.5–10.5px */
    --fs-sm: 13px;  /* secondary text, units, hints, values — the compact 11–11.5px */
    --fs-md: 14px;  /* body, fields, lists, menus — the compact 12–13px */
    --fs-lg: 16px;  /* titles — the compact 14–15px */
    --fs-xl: 18px;  /* the compact 16px */
    --fs-2xl: 22px; /* page titles — the compact 18–20px */
  }
}

/* The dark palette answers two of the three states of the theme switch (js/theme.js): the
   system on a dark system — no data-theme, the media query decides — and an explicit dark pick
   on any system; `:not([data-theme="light"])` keeps an explicit light pick light on a dark one.
   CSS cannot OR a media query with a selector, so the two blocks below repeat the same
   declarations: keep them in pair (test/theme.test.mjs fails when they differ). A
   theme-dependent colour is a token here, never a component rule. The conditions sit in
   :where() so both blocks weigh as much as the bare :root: a later :root that changes a token
   (a breakpoint, print) still wins in every theme. The dark values are derived — the design is
   light only — and pass the same contrast checks (test/design-tokens.test.mjs). */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    --bg: #111214;
    --panel: #131417;
    --surface: #17191c;
    --surface-2: #1b1d20;
    --band: #1f2125;
    --hover: #25282c;
    --select: #16233f;
    --select-2: #1b2c50;
    --select-wash: rgba(91, 141, 239, 0.1);

    --chrome: #0b0c0d;
    --chrome-hover: #23262a;
    --chrome-text: #c7cad0;
    --chrome-title: #ffffff;
    --chrome-line: #3a3e45;
    --chrome-muted: #9aa0a8;
    --chrome-line-ui: #8b9099;
    --chrome-button: #f3f4f6;
    --chrome-button-text: #15171a;
    --chrome-warn: #d9a441;
    --chrome-ok: #4ec77a;
    --chrome-danger: #f0736a;

    --drop: rgba(0, 0, 0, 0.5);
    --overlay: rgba(0, 0, 0, 0.6);

    --ink: #eceef1;
    --ink-2: #c7cad0;
    --text-2: #a6abb3;
    --muted: #9097a0;
    --accent: #5b8def;
    --accent-text: #0b0c0d;
    --on-ink: #111214;
    --ink-hover: #c7cad0;
    --on-ink-ok: #1f7a3d;
    --on-ink-warn: #8a6100;
    --on-ink-danger: #b42318;
    --on-ink-faint: rgba(17, 18, 20, 0.4);

    --line-ui: #6b7079;
    --line: #3a3e45;
    --line-mid: #33373d;
    --line-soft: #2b2e33;
    --edge: #9097a0;

    --ok: #4ec77a;
    --warn: #d9a441;
    --danger: #f0736a;
    --ok-tint: rgba(78, 199, 122, 0.08);
    --ok-area: rgba(78, 199, 122, 0.5);
    --ok-pale: rgba(78, 199, 122, 0.18);
    --danger-area: rgba(240, 115, 106, 0.28);
    --danger-band: rgba(240, 115, 106, 0.55);
    --danger-tint: rgba(240, 115, 106, 0.08);

    --tag-gray: #9a9a9a;
    --tag-gray-tint: rgba(154, 154, 154, 0.16);
    --tag-blue: #6aa6f0;
    --tag-blue-tint: rgba(106, 166, 240, 0.16);
    --tag-green: #4ec77a;
    --tag-green-tint: rgba(78, 199, 122, 0.16);
    --tag-amber: #d9a441;
    --tag-amber-tint: rgba(217, 164, 65, 0.16);
    --tag-red: #f0736a;
    --tag-red-tint: rgba(240, 115, 106, 0.16);
    --tag-purple: #a78bfa;
    --tag-purple-tint: rgba(167, 139, 250, 0.16);
    --tag-teal: #43c4b6;
    --tag-teal-tint: rgba(67, 196, 182, 0.16);

    --grid-minor: rgba(255, 255, 255, 0.035);
    --grid-major: rgba(255, 255, 255, 0.08);

    color-scheme: dark;
  }
}

/* Keep in pair with the block above. */
:root:where([data-theme="dark"]) {
  --bg: #111214;
  --panel: #131417;
  --surface: #17191c;
  --surface-2: #1b1d20;
  --band: #1f2125;
  --hover: #25282c;
  --select: #16233f;
  --select-2: #1b2c50;
  --select-wash: rgba(91, 141, 239, 0.1);

  --chrome: #0b0c0d;
  --chrome-hover: #23262a;
  --chrome-text: #c7cad0;
  --chrome-title: #ffffff;
  --chrome-line: #3a3e45;
  --chrome-muted: #9aa0a8;
  --chrome-line-ui: #8b9099;
  --chrome-button: #f3f4f6;
  --chrome-button-text: #15171a;
  --chrome-warn: #d9a441;
  --chrome-ok: #4ec77a;
  --chrome-danger: #f0736a;

  --drop: rgba(0, 0, 0, 0.5);
  --overlay: rgba(0, 0, 0, 0.6);

  --ink: #eceef1;
  --ink-2: #c7cad0;
  --text-2: #a6abb3;
  --muted: #9097a0;
  --accent: #5b8def;
  --accent-text: #0b0c0d;
  --on-ink: #111214;
  --ink-hover: #c7cad0;
  --on-ink-ok: #1f7a3d;
  --on-ink-warn: #8a6100;
  --on-ink-danger: #b42318;
  --on-ink-faint: rgba(17, 18, 20, 0.4);

  --line-ui: #6b7079;
  --line: #3a3e45;
  --line-mid: #33373d;
  --line-soft: #2b2e33;
  --edge: #9097a0;

  --ok: #4ec77a;
  --warn: #d9a441;
  --danger: #f0736a;
  --ok-tint: rgba(78, 199, 122, 0.08);
  --ok-area: rgba(78, 199, 122, 0.5);
  --ok-pale: rgba(78, 199, 122, 0.18);
  --danger-area: rgba(240, 115, 106, 0.28);
  --danger-band: rgba(240, 115, 106, 0.55);
  --danger-tint: rgba(240, 115, 106, 0.08);

  --tag-gray: #9a9a9a;
  --tag-gray-tint: rgba(154, 154, 154, 0.16);
  --tag-blue: #6aa6f0;
  --tag-blue-tint: rgba(106, 166, 240, 0.16);
  --tag-green: #4ec77a;
  --tag-green-tint: rgba(78, 199, 122, 0.16);
  --tag-amber: #d9a441;
  --tag-amber-tint: rgba(217, 164, 65, 0.16);
  --tag-red: #f0736a;
  --tag-red-tint: rgba(240, 115, 106, 0.16);
  --tag-purple: #a78bfa;
  --tag-purple-tint: rgba(167, 139, 250, 0.16);
  --tag-teal: #43c4b6;
  --tag-teal-tint: rgba(67, 196, 182, 0.16);

  --grid-minor: rgba(255, 255, 255, 0.035);
  --grid-major: rgba(255, 255, 255, 0.08);

  color-scheme: dark;
}

/* ------------------------------------------------------------------- reset */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

[hidden] {
  display: none !important;
}

h1,
h2,
h3,
p,
dl,
dd,
dt,
ul,
ol {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* The fallback ring for anything focusable that has no rule of its own: inset, so it never
   moves a dense layout. Controls and buttons draw the §5 ring (border + inset shadow) instead. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

::selection {
  background: var(--accent);
  color: var(--accent-text);
}

* {
  scrollbar-width: thin;
  scrollbar-color: var(--line-ui) transparent;
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-thumb {
  background: var(--line-ui);
  border: 3px solid var(--bg);
}

*::-webkit-scrollbar-track {
  background: transparent;
}

/* Every figure is Plex Mono with tabular figures (§3). */
.num,
code,
kbd {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

kbd {
  font-size: inherit;
  font-weight: 500;
}

.muted {
  color: var(--muted);
}

/* The micro-label (§3.1): panel titles, section heads, group heads, the dialog path, captions.
   Mono, uppercase, tracked. On a --band, --hover or --select row it takes --text-2 (see the
   :root note on contrast). */
.fb-micro {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

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

/* §4: one grid filling the viewport — menu bar, tool strip, main (model tree | canvas | property
   sheet), command line. Below 760px the phone layout of §9 takes over (the block at
   the end of this file, js/mobile.js). */
.fb-app {
  position: relative;
  display: grid;
  width: 100%;
  min-width: 760px;
  height: 100vh;
  grid-template-columns: var(--tree-w) minmax(0, 1fr) var(--sheet-w);
  grid-template-rows: var(--menubar-h) var(--strip-h) minmax(0, 1fr) var(--cmdline-h);
  grid-template-areas:
    "menubar menubar menubar"
    "strip   strip   strip"
    "tree    main    sheet"
    "cmdline cmdline cmdline";
  background: var(--bg);
  overflow: hidden;
}

@supports (height: 100dvh) {
  .fb-app {
    height: 100dvh;
  }
}

.fb-menubar {
  grid-area: menubar;
}

.fb-toolstrip {
  grid-area: strip;
}

.fb-tree {
  grid-area: tree;
}

.fb-main {
  grid-area: main;
}

.fb-inspector {
  grid-area: sheet;
}

.fb-cmdline {
  grid-area: cmdline;
}

/* Below 1120px the model tree hides and the property sheet narrows to 340px (§4). Inserting
   stays in the tool strip and the Insert menu, the scenarios in Model ▸ Scenarios. */
@media (max-width: 1119.98px) {
  :root {
    --tree-w: 0px;
    --sheet-w: 340px;
    --field-label-w: 100px;
  }

  .fb-app {
    grid-template-columns: minmax(0, 1fr) var(--sheet-w);
    grid-template-areas:
      "menubar menubar"
      "strip   strip"
      "main    sheet"
      "cmdline cmdline";
  }

  .fb-app > .fb-tree {
    display: none;
  }
}

/* --------------------------------------------------------------- controls */

/* DESIGN.md §5. Every form control is styled by ELEMENT: a field in a new screen needs no class.
   24px tall (26px in the tool strip and dialogs), square, bounded by --line-ui, on --surface.
   Focus is the §5 ring — an accent border plus a 1px INSET accent shadow, a 2px ring inside the
   control that never moves the layout. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
input[type="url"],
input[type="tel"],
input[type="date"],
input:not([type]),
select,
textarea {
  width: 100%;
  min-width: 0;
  min-height: var(--control-h);
  margin: 0;
  padding: 0 6px;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  font: 400 var(--fs-md, 12px)/1 var(--font);
  appearance: none;
  transition: border-color 0.1s linear;
}

textarea {
  padding: 5px 6px;
  resize: vertical;
  line-height: 1.4;
}

input[type="number"],
input.num,
input[type="date"] {
  font-family: var(--mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* The drawn arrow: two gradients, the only gradient a control carries. */
select {
  padding-right: 20px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 11px) calc(50% + 1px), calc(100% - 7px) calc(50% + 1px);
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
  cursor: pointer;
}

input:hover,
select:hover,
textarea:hover {
  border-color: var(--text-2);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Error: the same ring in --danger. A form marks the field it names in its error box. */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger);
  box-shadow: inset 0 0 0 1px var(--danger);
}

input:disabled,
select:disabled,
textarea:disabled,
input[readonly] {
  border-color: var(--line-soft);
  background-color: var(--surface-2);
  color: var(--muted);
  cursor: default;
}

::placeholder {
  color: var(--muted);
  opacity: 1;
}

/* Checkbox (§5): a 14px square; checked is solid --ink with a tick in --on-ink. */
input[type="checkbox"],
input[type="radio"] {
  position: relative;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  margin: 0;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--surface);
  appearance: none;
  cursor: pointer;
  vertical-align: middle;
}

input[type="checkbox"]:checked {
  border-color: var(--ink);
  background: var(--ink);
}

input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--on-ink);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

/* The square radio (the scenario list): a 6px ink square inside the box. */
input[type="radio"]:checked {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 3px var(--surface);
  background: var(--ink);
}

input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* A field with its unit (§5): the unit box sits INSIDE the control's boundary, on --surface-2,
   so the field and its unit read as one control and share one focus ring. */
.fb-input {
  position: relative;
  display: flex;
  align-items: stretch;
  min-width: 0;
  min-height: var(--control-h);
  border: 1px solid var(--line-ui);
  background: var(--surface);
  transition: border-color 0.1s linear;
}

.fb-input:hover {
  border-color: var(--text-2);
}

.fb-input > input {
  flex: 1 1 auto;
  min-height: calc(var(--control-h) - 2px);
  border: none;
  background: transparent;
  text-align: right;
}

.fb-input > input:focus {
  box-shadow: none;
}

/* The − and + of a number field (§5 Stepper): drawn on the phone only (§9); on the desktop the
   arrows step the field. */
.fb-step {
  display: none;
}

.fb-input:focus-within {
  border-color: var(--accent);
}

/* Drawn above the field and the unit box, so the ring runs round both. */
.fb-input:focus-within::after {
  content: '';
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 0 1px var(--accent);
  pointer-events: none;
}

.fb-input:has(> input[aria-invalid="true"]) {
  border-color: var(--danger);
}

.fb-input:has(> input[aria-invalid="true"])::after {
  content: '';
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 0 1px var(--danger);
  pointer-events: none;
}

/* The design's unit cell: --band behind an 11px mono unit, a --line-soft rule towards the figure.
   On --band the unit steps up to --text-2 (§2.2: --muted is 4.44:1 there). */
.fb-unit {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  padding: 0 6px;
  border-left: 1px solid var(--line-soft);
  background: var(--band);
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  /* On the figure's baseline: an 11px unit centred in the box sits a pixel above 12px digits,
     and 2px of top padding move the centre down by one. */
  padding-top: 2px;
  white-space: nowrap;
}

/* A field of the property sheet (§4.5): label left, control right, in one 24px row. The label
   cell carries the scenario's accent square; «Reset to Base» and a hint shown as news take the
   row under the control. A field of several lines (.is-stacked) puts its label above. */
.field {
  display: grid;
  grid-template-columns: var(--field-label-w, 92px) minmax(0, 1fr);
  align-items: center;
  column-gap: 6px;
  row-gap: 3px;
  margin: 0;
}

.field.is-stacked {
  display: block;
}

.field > .fb-field-head {
  grid-column: 1;
  min-width: 0;
}

.field > :not(.fb-field-head):not(.fb-override-reset):not(.fb-hint) {
  grid-column: 2;
  min-width: 0;
}

/* A range From – To (a source's views, visits, CPM or CPC, a link's wait; formats 8 and 9): one row of
   the grid as every field — the label in its column, and in the value column the two numbers with an
   en dash between them, sharing the column, the unit once, in the second's box. The line of what they
   mean and Use my data… sit under them in the value column. */
.fb-range {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Each box grows from its fixed parts (the unit box, the phone's − and +), so the two inputs get the
   same width whatever the unit. */
.fb-range > .fb-input {
  flex: 1 1 auto;
}

.fb-range > .fb-input > input {
  width: 0;
}

.fb-range__dash {
  flex: 0 0 auto;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
}

.field.fb-range-field > .fb-range-hint.is-shown {
  grid-column: 2;
}

/* A link's wait (format 9, "Takes from … to … days"): under its line the one way to the person's own
   data, or back from it, as a link-shaped button. With data the two ends are the data's own — the
   recessed read-only cell of §2.1, the numbers in ink: they are real, only not typed. */
.fb-takes-actions {
  margin-top: 3px;
  line-height: 16px;
}

.fb-takes-actions .btn-link {
  font-size: var(--fs-sm, 11px);
}

.fb-range-field.is-data .fb-input:has(> input[readonly]) {
  border-color: var(--line-soft);
  background: var(--surface-2);
}

.fb-range-field.is-data .fb-input > input[readonly] {
  background-color: transparent;
  color: var(--ink);
}

/* Use my data… (§6): the paste in mono, the read line under it, what was left out in muted. */
.fb-lag-data .fb-modal-body > .field {
  margin-top: 12px;
}

.fb-lag-data textarea {
  min-height: 150px;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.fb-lag-data .fb-lag-data__status {
  margin-top: 6px;
}

.fb-lag-data .fb-modal-body p.fb-lag-data__read {
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11.5px);
}

.fb-lag-data .fb-lag-data__status p + p {
  margin-top: 2px;
}

.field-label {
  display: block;
  margin-bottom: 4px;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
}

/* A label with an explanation behind it: dotted, the explanation its tooltip. */
.field-label.has-hint {
  text-decoration: underline dotted var(--line-ui);
  text-underline-offset: 3px;
  cursor: help;
}

.fb-hint {
  margin-top: 3px;
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

/* In a field the hint is the label's tooltip and the control's description, not a line of text —
   until it is news (.is-shown): why a credit no longer counts, how far a scenario is from Base. */
.field > .fb-hint:not(.is-shown) {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.field > .fb-hint.is-shown {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--text-2);
}

.field > .fb-override-reset {
  grid-column: 2;
  justify-self: end;
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
}

/* ---------------------------------------------------------------- buttons */

/* §5.1. .btn is 26px, bounded by --line-ui on --surface; hover is a --hover fill. */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--control-h-lg);
  padding: 0 10px;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  font: 400 var(--fs-md, 12px)/1 var(--font);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color 0.1s linear, background-color 0.1s linear;
}

.btn:hover {
  background: var(--hover);
}

.btn:active {
  background: var(--select-2);
}

.btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* An inactive component is outside 1.4.11: a quiet boundary and --muted text. */
.btn:disabled {
  border-color: var(--line-mid);
  background: var(--surface);
  color: var(--muted);
  cursor: default;
}

/* A button that is waiting on its own work (drawing the export picture). It keeps the focus —
   disabling a focused control drops the focus to <body> — and its look: aria-disabled carries the
   news to assistive technology, and from 150 ms its busy face (the indicator over its hidden label,
   .is-busy-face, docs/PLANS.md §9.2) says it to the eye. A dimmed button was the static text of
   before in another form. */
.btn[aria-busy="true"] {
  cursor: progress;
}

/* Solid INK, never blue: the accent is for selection, focus and links. */
.btn-primary {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
  font-weight: 500;
}

.btn-primary:hover,
.btn-primary:active {
  border-color: var(--ink-hover);
  background: var(--ink-hover);
}

/* On an ink fill the ring needs a surface gap to read: accent border, a surface line inside. */
.btn-primary:focus-visible {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 2px var(--surface);
}

.btn-primary:disabled {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
  opacity: 0.4;
}

/* A dialog's primary action is full width and carries its shortcut in mono on the right. */
.btn-block {
  display: flex;
  width: 100%;
  min-height: 32px;
}

.btn .fb-kbd {
  margin-inline-start: auto;
  padding-inline-start: 8px;
  font-family: var(--mono);
  font-size: var(--fs-xs, 10.5px);
  font-weight: 500;
  opacity: 0.75;
}

.btn-block .fb-kbd {
  position: absolute;
  right: 10px;
}

.btn-danger:hover:not(:disabled) {
  border-color: var(--danger);
  color: var(--danger);
}

.btn-icon {
  width: var(--control-h-lg);
  min-width: var(--control-h-lg);
  padding: 0;
  font-family: var(--mono);
  font-size: var(--fs-md, 13px);
}

/* A link-shaped button: no box, ink underlined text; the accent on hover (§5.1). */
.btn-link {
  display: inline;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-md, 12px);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.btn-link:hover {
  background: none;
  color: var(--accent);
}

.btn-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: none;
}

.btn-link:disabled {
  color: var(--muted);
  text-decoration: none;
}

/* Segmented group (§5.1): one boundary, dividers between segments, the pressed one solid ink. */
.btn-seg {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.btn-seg > button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: calc(var(--control-h-lg) - 2px);
  margin: 0;
  padding: 0 10px;
  border: 0;
  border-inline-start: 1px solid var(--line-soft);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-md, 12px)/1 var(--font);
  cursor: pointer;
}

.btn-seg > button:first-child {
  border-inline-start: 0;
}

.btn-seg > button:hover {
  background: var(--hover);
}

.btn-seg > button[aria-pressed="true"],
.btn-seg > button[aria-checked="true"],
.btn-seg > button[aria-selected="true"] {
  background: var(--ink);
  color: var(--on-ink);
}

.btn-seg > button:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* The mono shortcut beside a tool's name (Select V, Pan H). */
.btn-seg .fb-kbd {
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  opacity: 0.7;
}

/* ------------------------------------------------------ badges and meters */

/* §5.2. Mono 9.5px uppercase in a 1px box. The colour says the kind: --ok for a confirmation,
   --ink for a plan, --muted for a state label. */
.fb-badge {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 2px 5px;
  border: 1px solid currentColor;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-badge.is-ok {
  color: var(--ok);
}

.fb-badge.is-ink {
  color: var(--ink);
}

.fb-badge.is-warn {
  color: var(--warn);
}

.fb-badge.is-danger {
  color: var(--danger);
}

/* The segmented meter (§5.2): N square segments with 2px gaps; the filled ones are --ok when
   the rule passes and --warn while it does not. ui.js builds it (segmentedMeter). */
.fb-segmeter {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fb-segmeter__track {
  display: flex;
  gap: 2px;
}

.fb-segmeter__seg {
  flex: 1 1 0;
  height: 3px;
  background: var(--line-soft);
}

.fb-segmeter__seg.is-on {
  background: var(--warn);
}

.fb-segmeter.is-ok .fb-segmeter__seg.is-on {
  background: var(--ok);
}

.fb-segmeter__caption {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--warn);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.fb-segmeter.is-ok .fb-segmeter__caption {
  color: var(--ok);
}

.fb-segmeter__caption > :last-child:not(:first-child) {
  color: var(--muted);
}

/* The 6px status square (the save state, the toast, the edited mark). */
.fb-status-square {
  display: inline-block;
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background: var(--muted);
}

.fb-status-square.is-ok {
  background: var(--ok);
}

.fb-status-square.is-warn {
  background: var(--warn);
}

.fb-status-square.is-danger {
  background: var(--danger);
}

/* §7.3: an input the active scenario gives a value of its own — a small accent square beside its
   field, the status squares' size. [hidden] must win over the display. */
.fb-override-dot {
  display: inline-block;
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background: var(--accent);
}

.fb-override-dot[hidden] {
  display: none;
}

/* The label cell of a field: the label and, while a scenario overrides it, the accent square. */
.fb-field-head {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 4px;
}

.field > .fb-field-head {
  margin-bottom: 0;
}

.fb-field-head .field-label.is-inline {
  min-width: 0;
  margin-bottom: 0;
  overflow-wrap: anywhere;
}

.fb-override-reset[hidden],
.fb-scenario-note[hidden] {
  display: none;
}

/* The first line of the property sheet while a scenario is active, where its fields edit it:
   «Editing scenario “X”», what that means in its tooltip. */
.fb-scenario-note {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 15px;
}

.fb-scenario-note .fb-override-dot {
  transform: translateY(-1px);
}

/* A scenario looked at, not changed, on Free (docs/PLANS.md §5.5): the line's Upgrade… after it. */
.fb-scenario-note__upgrade {
  flex: 0 0 auto;
  margin-inline-start: auto;
  font-size: var(--fs-sm, 11px);
}

.fb-scenario-note__upgrade[hidden] {
  display: none;
}

/* ------------------------------------------------------------------ menus */

/* §4.1 / §6. A menu or dropdown is a floating surface: --surface, a 1px --line outline and the
   one hard shadow. Rows are 24px: the label on the left, a mono shortcut on the right. */
.fb-menu {
  position: absolute;
  z-index: 200;
  min-width: 200px;
  padding: 3px 0;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
}

.fb-menu__item {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 24px;
  margin: 0;
  padding: 0 10px 0 6px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  /* 16px, not 1: the label clips its overflow for the ellipsis, and a box one em tall cut the
     descenders of g and y off every menu, and of the Cyrillic letters too. */
  font: 400 var(--fs-md, 12px)/16px var(--font);
  text-align: start;
  white-space: nowrap;
  cursor: pointer;
}

.fb-menu__item:hover {
  background: var(--hover);
}

.fb-menu__item:focus-visible {
  outline: none;
  background: var(--hover);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-menu__item.is-current {
  background: var(--select-2);
}

/* The one leading column of every row (docs/COMMENTS.md §32.5): a square for the chosen radio item
   (theme, language, scenario), a tick for a checked toggle (snap, grid), a swatch, or an action's
   glyph — one of them. Empty otherwise, so the labels line up. */
.fb-menu__mark {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 12px;
  height: 12px;
  font: 600 var(--fs-sm, 11px)/1 var(--mono);
}

/* Insert ▸ Source …: the tool strip's glyph of the same block, 11px, in the one column; a context
   menu's or a ⋯ menu's action its own glyph there (DESIGN §6). */
.fb-menu__mark .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-menu__item[role="menuitemradio"][aria-checked="true"] .fb-menu__mark::before {
  content: '';
  width: 6px;
  height: 6px;
  background: currentColor;
}

/* View ▸ Select · Pan: the strip's glyph in the gutter, and the tool in use drawn pressed as the
   strip draws it — the glyph in --on-ink on an --ink square — instead of the radio square. */
.fb-menu__item[role="menuitemradio"] .fb-menu__mark.has-icon::before {
  content: none;
}

.fb-menu__item[role="menuitemradio"][aria-checked="true"] .fb-menu__mark.has-icon {
  width: 16px;
  height: 16px;
  margin: -2px;
  background: var(--ink);
  color: var(--on-ink);
}

/* A checked option's tick is the family's glyph, shown only while it is checked. */
.fb-menu__item[role="menuitemcheckbox"] .fb-menu__mark .fb-ico {
  visibility: hidden;
}

.fb-menu__item[role="menuitemcheckbox"][aria-checked="true"] .fb-menu__mark .fb-ico {
  visibility: visible;
}

/* A submenu's arrow: the family's chevron, 9px, in the shortcut column. */
.fb-menu__sub {
  display: flex;
  align-items: center;
}

.fb-menu__sub .fb-ico {
  width: 9px;
  height: 9px;
}

.fb-menu__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A row that draws its own mark (the Boards page's Folders menu: a folder's square, a label's
   colour) draws it in the gutter's 12px column, and shows its choice there — no second, radio
   square beside it; the chosen row is 600, as in the sidebar. */
.fb-menu__label.has-lead {
  display: flex;
  align-items: center;
  gap: 6px;
}

.fb-menu__item:has(> .fb-menu__label.has-lead) > .fb-menu__mark {
  display: none;
}

.fb-menu__item[aria-checked="true"] > .fb-menu__label.has-lead {
  font-weight: 600;
}

.fb-menu__label.has-lead > span:last-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-menu__lead {
  display: inline-flex;
  flex: 0 0 auto;
  justify-content: center;
  width: 12px;
}

.fb-menu__item[aria-expanded="true"] {
  background: var(--hover);
}

.fb-menu__item:disabled,
.fb-menu__item[aria-disabled="true"] {
  background: transparent;
  color: var(--muted);
  cursor: default;
}

.fb-menu__hint {
  flex: 0 0 auto;
  margin-left: 16px;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10.5px);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* A value beside the label (the account menu's board count, the language) sits in the hint's
   column; a submenu's ▸ follows it closely. */
.fb-menu__meta + .fb-menu__hint {
  margin-left: 6px;
}

/* A disabled item says why in the shortcut's column (a context menu: "only receives", "no rate"). */
.fb-menu__why {
  color: var(--muted);
  font-weight: 400;
}

/* Tag ▸: the colour itself in the gutter, a 10px square; "No color" an empty one in a hairline. */
.fb-menu__swatch {
  width: 10px;
  height: 10px;
  box-sizing: border-box;
  border: 1px solid var(--fb-swatch, var(--line-ui));
  background: var(--fb-swatch, transparent);
}

/* The chosen colour is bounded in --ink, as the sheet's swatch is; no radio square beside it. */
.fb-menu__item[aria-checked="true"] .fb-menu__mark.has-swatch::before {
  content: none;
}

.fb-menu__item[aria-checked="true"] .fb-menu__swatch {
  outline: 1px solid var(--ink);
  outline-offset: 1px;
}

/* A context menu's first line: what it is about, in mono, not an item (STP-04 · Free check). */
.fb-menu__title {
  max-width: 280px;
  padding: 4px 10px 5px 24px;
  overflow: hidden;
  color: var(--text-2);
  font: 500 var(--fs-xs, 10.5px)/16px var(--mono);
  text-overflow: ellipsis;
  white-space: nowrap;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 3px;
}

/* A group's title inside a menu, as the property sheet draws its section titles (COMMENTS §32.6). */
.fb-menu__title.is-section {
  font-size: var(--fs-xs, 9.5px);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.fb-menu__item + .fb-menu__title,
.fb-menu__item + .fb-menu__group,
.fb-menu__group + .fb-menu__group {
  margin-top: 3px;
}

.fb-menu__sep {
  height: 1px;
  margin: 3px 0;
  border: 0;
  background: var(--line-soft);
}

.fb-menu__head {
  min-width: 232px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-menu__head-email {
  margin-top: 5px;
  color: var(--ink);
  font: 500 var(--fs-md, 12px)/1.2 var(--mono);
  overflow-wrap: anywhere;
}

.fb-menu__head-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

/* Help ▸ Keyboard shortcuts: what a key does on the left, the key in mono on the right. */
.fb-keys {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 7px 16px;
  margin: 0;
  font-size: var(--fs-md, 12px);
}

.fb-keys dt {
  color: var(--ink-2);
}

.fb-keys dd {
  margin: 0;
  color: var(--ink);
  font: 500 var(--fs-sm, 11px)/1.4 var(--mono);
  text-align: right;
}

/* Help ▸ Keyboard shortcuts: the keys by where they work, two columns in the wide dialog. */
.fb-keys-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 28px;
  align-items: start;
}

/* The keys take at most a little under half the column and wrap: a long Russian combination
   (the Russian "Space + drag · scroll") must not squeeze its words into one per line. */
.fb-keys-grid .fb-keys {
  grid-template-columns: minmax(0, 1fr) minmax(0, max-content);
}

.fb-keys-grid .fb-keys dd {
  max-width: 13em;
}

.fb-keys-head {
  margin-bottom: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--line-soft);
}

@media (max-width: 719.98px) {
  .fb-keys-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Help ▸ Command line: the grammar as a dense table — mono usage and examples, 24px rows between
   --line-soft rules, micro-label column heads. */
.fb-cmdhelp {
  width: 100%;
  margin-top: 16px;
  font-size: var(--fs-md, 12px);
}

.fb-cmdhelp th,
.fb-cmdhelp td {
  padding: 4px 12px 4px 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink-2);
  font-weight: 400;
  line-height: 1.4;
  text-align: left;
  vertical-align: top;
}

.fb-cmdhelp thead th {
  padding-top: 0;
  border-bottom-color: var(--line);
  color: var(--muted);
  font-weight: 500;
}

.fb-cmdhelp .fb-cmdhelp__usage {
  color: var(--ink);
  font-size: var(--fs-sm, 11.5px);
  font-weight: 500;
  white-space: nowrap;
}

.fb-cmdhelp .fb-cmdhelp__example {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  white-space: nowrap;
}

.fb-cmdhelp__keys {
  margin-top: 14px;
}

/* ------------------------------------------------------------ error box */

/* §6: one plainly worded error above the fields — a 1px --danger box, a mono «!», --danger
   text. Never a toast for a form error. */
.fb-error-box {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr);
  gap: 8px;
  margin: 0;
  padding: 8px 10px;
  border: 1px solid var(--danger);
  background: var(--danger-tint);
  color: var(--danger);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
}

.fb-error-box::before {
  content: '!';
  font-family: var(--mono);
  font-weight: 600;
}

/* The same shape for a confirmation (the "email confirmed" banner). */
.fb-ok-box {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr);
  gap: 8px;
  margin: 0;
  padding: 8px 10px;
  border: 1px solid var(--ok);
  background: var(--ok-tint);
  color: var(--ok);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
}

.fb-ok-box::before {
  content: '✓';
  font-family: var(--mono);
  font-weight: 600;
}

/* The same shape for a neutral note ("Keep modelling meanwhile…"): a --line rule, an «i». */
.fb-info-box {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr);
  gap: 8px;
  margin: 0;
  padding: 8px 10px;
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
}

.fb-info-box::before {
  content: 'i';
  font-family: var(--mono);
  font-weight: 600;
}

/* The mono «OR WITH EMAIL» divider between provider buttons and a form. */
.fb-divider {
  display: flex;
  align-items: center;
  gap: 8px;
}

.fb-divider::before,
.fb-divider::after {
  content: '';
  flex: 1 1 auto;
  border-top: 1px solid var(--line-soft);
}

/* --------------------------------------------------------------- menu bar */

/* §4.1: 28px, --chrome in BOTH themes. The mark and the name, the menus, the document title in
   the middle, and on the right the storage badge, Export and the account control. */
.fb-menubar {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  padding: 0 10px;
  border-bottom: 1px solid var(--chrome);
  background: var(--chrome);
  color: var(--chrome-text);
  font-size: var(--fs-sm, 11.5px);
  white-space: nowrap;
  overflow: hidden;
}

.fb-brand {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  color: var(--chrome-title);
  font-size: var(--fs-sm, 11.5px);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
}

/* The brand is a link: on the canvas to Boards (docs/PLANS.md §10), on the Boards page to the site's
   home page (DESIGN §13). The lockup as it is, a 20px target like the crumb's, --chrome-hover under
   the pointer. */
.fb-brand__link {
  display: flex;
  align-items: center;
  height: 20px;
  margin: 0 -4px;
  padding: 0 4px;
  color: inherit;
  text-decoration: none;
}

.fb-brand__link:hover {
  background: var(--chrome-hover);
  color: var(--chrome-title);
}

/* The FunnelCAD mark and lockup (js/brand.js, js/brand-dom.js; DESIGN §14): the mark drawn for its
   size in currentColor, then "Funnel" in Plex Sans 600 and "CAD" in Plex Mono 500 in a 1.5px box —
   the border the same at every size. The words are for the eye; a screen reader reads the lockup's
   hidden FunnelCAD. */
.fb-mark {
  display: block;
  flex: 0 0 auto;
  overflow: visible;
}

.fb-lockup,
.fb-lockup__art {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}

.fb-lockup__word {
  font-family: var(--font);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
}

/* The box is an inset shadow, not a border: Chromium rounds a border's width down to a whole CSS
   pixel (1.5px drew as 1px at every DPR), and the concept's box is 1.5px at every size. The
   variants' padding is the text's 1px 2px plus the 1.5px the shadow is drawn inside. */
.fb-lockup__cad {
  border: 0;
  box-shadow: inset 0 0 0 1.5px currentColor;
  font-family: var(--mono);
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 1;
}

/* The menu bars: the 24 cut drawn at 16px (the owner's choice, §14), in --chrome-title (the brand's
   own colour on --chrome). */
.fb-lockup--bar .fb-lockup__art {
  gap: 4px;
}

.fb-lockup--bar .fb-mark {
  margin-right: 3px;
}

.fb-lockup--bar .fb-lockup__word {
  font-size: 12px;
}

.fb-lockup--bar .fb-lockup__cad {
  padding: 2.5px 3.5px;
  font-size: 9px;
}

/* The title block's product cell: the 24 cut over the words — the 92px cell holds no row of both
   (§12). js/export.js drawProduct draws the same cell into an exported sheet. */
.fb-lockup--sheet .fb-lockup__art {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  align-items: center;
  column-gap: 3px;
  row-gap: 2px;
  color: var(--ink);
}

.fb-lockup--sheet .fb-mark {
  grid-column: 1 / -1;
}

.fb-lockup--sheet .fb-lockup__word {
  font-size: 11px;
}

.fb-lockup--sheet .fb-lockup__cad {
  padding: 2.5px 3.5px;
  font-size: 8px;
}

/* Forced colours drop shadows, and a border or an outline would be rounded to 1px (LANDMINES): the
   box keeps its 1.5px inset shadow there, out of the forcing, in the system's own text colour — the
   user's palette still decides both the words and the box. */
@media (forced-colors: active) {
  .fb-lockup__cad {
    forced-color-adjust: none;
    color: CanvasText;
    box-shadow: inset 0 0 0 1.5px CanvasText;
  }
}

.fb-menubar__menus {
  flex: 0 0 auto;
  display: flex;
  gap: 1px;
}

.fb-menubar__item {
  height: 20px;
  padding: 0 7px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--chrome-text);
  font: inherit;
  cursor: pointer;
}

.fb-menubar__item:hover,
.fb-menubar__item.is-open {
  background: var(--chrome-hover);
  color: var(--chrome-title);
}

/* On --chrome the accent is too dark to see (§4.1): the menu bar rings in --chrome-title, the mark
   too — it is where the keyboard lands quietly after the account is deleted or a banner acts. */
.fb-menubar__item:focus-visible,
.fb-menubar__btn:focus-visible,
.fb-doc-title:focus-visible,
.fb-brand:focus-visible,
.fb-brand__link:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--chrome-title);
}

/* The document: the funnel's name (a rename button), the scenario below 1120px, the save state. */
.fb-menubar__doc {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
}

.fb-doc-title {
  min-width: 0;
  max-width: 100%;
  height: 20px;
  padding: 0 4px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--chrome-title);
  font: 500 var(--fs-sm, 11.5px)/20px var(--font);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.fb-doc-title:hover {
  background: var(--chrome-hover);
}

/* Below 1120px, where the scenarios panel is hidden, the scenario in effect when it is not Base
   (§4.1): mono --chrome-muted, a button that opens Model ▸ Scenarios. */
.fb-doc-suffix {
  display: none;
  flex: 0 1 auto;
  min-width: 0;
  height: 20px;
  padding: 0 4px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--chrome-text);
  font: 400 var(--fs-xs, 10.5px)/20px var(--mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.fb-doc-suffix:hover,
.fb-doc-suffix.is-open {
  background: var(--chrome-hover);
  color: var(--chrome-title);
}

.fb-doc-suffix:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--chrome-title);
}

@media (max-width: 1119.98px) {
  .fb-doc-suffix {
    display: block;
  }
}

/* The one save indicator (§4.1): a 6px tone square and the state in mono --chrome-muted, right
   after the title. It never gives way — the title truncates first; below 1100px it shortens to
   the time or a short word (the full words stay for a screen reader and in the tooltip). */
.fb-save {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--chrome-muted);
  font: 400 var(--fs-xs, 10.5px)/14px var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: default;
}

.fb-save .fb-status-square.is-ok {
  background: var(--chrome-ok);
}

.fb-save .fb-status-square.is-warn {
  background: var(--chrome-warn);
}

.fb-save .fb-status-square.is-danger {
  background: var(--chrome-danger);
}

.fb-save__short {
  display: none;
}

@media (max-width: 1099.98px) {
  .fb-save__full {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .fb-save__short {
    display: inline;
  }
}

.fb-menubar__end {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.fb-menubar__btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 20px;
  padding: 0 9px;
  border: 1px solid var(--chrome-line-ui);
  border-radius: 0;
  background: transparent;
  color: var(--chrome-title);
  font: 400 var(--fs-sm, 11.5px)/1 var(--font);
  cursor: pointer;
}

.fb-menubar__btn:hover,
.fb-menubar__btn.is-open {
  border-color: var(--chrome-text);
  background: var(--chrome-hover);
}

/* A chrome button that is off: drawn quiet. */
.fb-menubar__btn:disabled {
  border-color: var(--chrome-line-ui);
  background: transparent;
  color: var(--chrome-muted);
  cursor: default;
}

.fb-menubar__btn[aria-busy="true"] {
  cursor: progress;
}

.fb-menubar__btn.is-light {
  border-color: var(--chrome-button);
  background: var(--chrome-button);
  color: var(--chrome-button-text);
  font-weight: 500;
}

.fb-menubar__btn.is-light:hover {
  border-color: var(--chrome-title);
  background: var(--chrome-title);
}

.fb-menubar__btn.is-light:focus-visible {
  box-shadow: inset 0 0 0 1px var(--chrome), inset 0 0 0 2px var(--chrome-title);
}

/* Share (docs/SHARING.md §12.7): an outline button on --chrome; a shared board's link shows as the
   --chrome-ok square before `Shared`. Below 1100px the square and `Share` — the full words stay for a
   screen reader and the tooltip says the rest. [hidden] must win over the square's display. */
.fb-share-btn .fb-status-square.is-ok {
  background: var(--chrome-ok);
}

.fb-share-btn .fb-status-square[hidden] {
  display: none;
}

.fb-share-btn__full {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-share-btn__short {
  display: none;
}

@media (max-width: 1099.98px) {
  .fb-share-btn__full {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .fb-share-btn__short {
    display: inline;
  }
}

/* The name keeps its room (js/shell.js fitDoc): at any width, while it would be cut to less than
   140px, Share and then the save indicator take their short forms, as below 1100px, then Create
   account (Sign up), and last the account control keeps only its initials. */
.fb-menubar.is-share-short .fb-share-btn__full,
.fb-menubar.is-save-short .fb-save__full,
.fb-menubar.is-account-short .fb-menubar__account-label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.fb-menubar.is-share-short .fb-share-btn__short,
.fb-menubar.is-save-short .fb-save__short {
  display: inline;
}

/* Create account (DESIGN §4.1): its short word only while the name would be cut short (fitDoc), and
   off the bar while even that would. Either word, never both in the accessibility tree: the name
   read is the word on screen. */
.fb-signup-btn__short,
.fb-menubar.is-signup-short .fb-signup-btn__full,
.fb-menubar.is-signup-folded .fb-signup-btn {
  display: none;
}

.fb-menubar.is-signup-short .fb-signup-btn__short {
  display: inline;
}

/* A share link's primary action (docs/SHARING.md §32): its short word — Save a copy — only while the
   funnel's name would be cut short (fitDoc). Either word, never both in the accessibility tree. */
.fb-viewer-primary__short,
.fb-menubar.is-primary-short .fb-viewer-primary__full {
  display: none;
}

.fb-menubar.is-primary-short .fb-viewer-primary__short {
  display: inline;
}

/* …and, still too tight, Sign in leaves the viewer's bar: File ▸ Sign in keeps it (fitDoc). */
.fb-menubar.is-signin-folded .fb-signin-btn {
  display: none;
}

/* Save a copy to edit, signed out: the quiet third way — Try without an account — a link on its own
   line of the dialog, with what it means under it. */
.fb-viewer-save__quiet {
  display: grid;
  justify-items: start;
  gap: 2px;
  margin: 12px 0 0;
}

/* A share link's page (DESIGN §15): the name keeps its room before the status's short word does —
   the square alone, its words in the tooltip and for a screen reader — and before the wordmark:
   the mark alone, as on the phone's viewer header. */
.fb-menubar.is-save-square .fb-save__full {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.fb-menubar.is-save-square .fb-save__short,
.fb-menubar.is-brand-mark .fb-brand .fb-lockup__word,
.fb-menubar.is-brand-mark .fb-brand .fb-lockup__cad {
  display: none;
}

.fb-menubar.is-brand-mark .fb-brand .fb-mark {
  margin-right: 0;
}

/* A share link's page, a scenario in effect below 1120px (js/shell.js fitDoc): the Model menu has
   folded into the scenario's suffix, and the suffix gives its width before the name does, down to
   its dot (the scenario's name stays its text for a screen reader and is in its tooltip). */
.fb-menubar.is-suffix-yield .fb-doc-suffix {
  flex-shrink: 1000;
  min-width: calc(8px + 2ch);
}

/* The desktop step (§3.1) for the menu bar, the owner's call of 28.09: with the bigger type the
   28px bar looked cramped and the 16px lockup small. From 760px up the bar is 36px, its targets 28px,
   the menus and buttons at --fs-md and the lockup drawn at 20px; the phone's bar stays as it was. */
@media (min-width: 760px) {
  :root {
    --menubar-h: 36px;
  }

  .fb-menubar {
    font-size: var(--fs-md, 12px);
  }

  .fb-brand__link,
  .fb-menubar__item,
  .fb-menubar__btn,
  .fb-menubar__crumb,
  .fb-doc-title,
  .fb-doc-suffix {
    height: 28px;
  }

  .fb-menubar__item {
    padding: 0 9px;
  }

  .fb-menubar__btn {
    padding: 0 12px;
    font-size: var(--fs-md, 12px);
  }

  .fb-doc-title {
    font-size: var(--fs-md, 12px);
    line-height: 28px;
  }

  .fb-doc-suffix {
    line-height: 28px;
  }

  .fb-lockup--bar .fb-mark {
    width: 20px;
    height: 20px;
  }

  .fb-lockup--bar .fb-lockup__word {
    font-size: 15px;
  }

  .fb-lockup--bar .fb-lockup__cad {
    padding: 3px 4.5px;
    font-size: 11px;
  }

  .fb-menubar .fb-avatar {
    width: 18px;
    height: 18px;
    font-size: 10px;
  }
}

/* The initials of the signed-in account: a square, never a circle. */
.fb-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  background: var(--chrome-text);
  color: var(--chrome);
  font: 600 8px/1 var(--mono);
  letter-spacing: 0.02em;
}

/* The full menu bar needs 1100px (§4): below it the Insert menu gives way (the tool strip
   inserts every block by a click and a drag). */
@media (max-width: 1099.98px) {
  .fb-menubar__item[data-menu="insert"] {
    display: none;
  }
}

/* ------------------------------------------------------------- tool strip */

/* §4.2: 40px, --panel, a --line rule under it; groups between --line-mid rules, each opened by
   a micro-label. The controls are --surface, bounded by --line-ui (3:1 on --panel too). */
.fb-toolstrip {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 0 8px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  overflow: hidden;
  white-space: nowrap;
}

.fb-strip__group {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
}

.fb-strip__pair {
  gap: 0;
}

.fb-strip__pair > .btn + .btn {
  margin-left: -1px;
}

.fb-strip__rule {
  flex: 0 0 auto;
  width: 1px;
  height: 22px;
  background: var(--line-mid);
}

.fb-strip__micro {
  margin-right: 2px;
  font-size: var(--fs-xs, 9.5px);
}

.fb-strip__spring {
  flex: 1 1 auto;
}

/* Select V · Pan H (§4.2): one joined control — two bordered buttons sharing their middle rule
   (the design's margin-left: -1px), no gap between them; each a glyph, a word and its key. The
   pressed tool is solid ink with an ink border, drawn above its neighbour's rule. */
.fb-strip__tools {
  gap: 0;
}

.fb-tool {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px;
}

.fb-tool + .fb-tool {
  margin-left: -1px;
}

.fb-tool .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-tool[aria-pressed="true"] {
  z-index: 1;
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
}

.fb-tool[aria-pressed="true"]:hover {
  border-color: var(--ink-hover);
  background: var(--ink-hover);
}

.fb-tool:focus-visible {
  z-index: 2;
}

.fb-tool[aria-pressed="true"]:focus-visible {
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 2px var(--on-ink);
}

.fb-tool .fb-kbd {
  margin: 0;
  padding: 0;
  color: var(--muted);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  opacity: 1;
}

.fb-tool[aria-pressed="true"] .fb-kbd {
  color: var(--on-ink);
  opacity: 0.7;
}

.fb-insert {
  gap: 5px;
  padding: 0 7px;
}

.fb-insert .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-insert.is-dragging {
  opacity: 0.5;
}

/* A unit that leads its field (the € of a target or a price): before the number, its rule on the right. */
.fb-unit.is-lead {
  order: -1;
  border-left: 0;
  border-right: 1px solid var(--line-soft);
}

/* A language with longer words than the design's English can overflow the strip at a given
   width (§4.2): js/shell.js then drops the group word and the V/H hints (.is-narrow), then the insert
   labels one at a time from the right (.is-iconic) — only where they cannot fit. A hidden label
   stays the button's accessible name. */
.fb-insert.is-iconic .fb-insert__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.fb-toolstrip.is-narrow .fb-strip__micro,
.fb-toolstrip.is-narrow .fb-tool .fb-kbd {
  display: none;
}

/* ----------------------------------------------------------- command line */

/* §4.6: 26px, --surface, a --line rule above; the › prompt, a mono field and, when there is one,
   the last answer on the right. */
.fb-cmdline {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 0 10px;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.fb-cmdline__prompt {
  flex: 0 0 auto;
  color: var(--accent);
  font: 600 var(--fs-md, 12px)/1 var(--mono);
}

/* The line and its inline suggestion (§7.4): the suggestion sits under the transparent input in the
   same face and padding — the typed text invisible, the rest of the word in --muted after it. */
.fb-cmdline__field {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  min-width: 0;
  height: 22px;
}

.fb-cmdline__ghost {
  position: absolute;
  inset: 0;
  overflow: hidden;
  padding: 0 4px;
  color: var(--muted);
  font: 400 var(--fs-md, 12px)/22px var(--mono);
  white-space: pre;
  pointer-events: none;
}

.fb-cmdline__typed {
  visibility: hidden;
}

.fb-cmdline .fb-cmdline__input {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  height: 22px;
  min-height: 22px;
  padding: 0 4px;
  border: 0;
  background: transparent;
  font: 400 var(--fs-md, 12px) var(--mono);
}

.fb-cmdline .fb-cmdline__input:hover {
  border: 0;
}

.fb-cmdline .fb-cmdline__input:focus {
  border: 0;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-cmdline__result {
  flex: 0 0 auto;
  max-width: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-2);
  /* Taller than one em: it clips for the ellipsis, and 1 cut the descenders (g, y and their Cyrillic kin). */
  font: 400 var(--fs-xs, 10.5px)/14px var(--mono);
}

.fb-cmdline__result.is-error {
  color: var(--danger);
}

/* --------------------------------------------------------------- panels */

/* §4.3, §4.5: both side columns are --panel (the design's #f6f7f8); what sits on them — a field,
   a button, the identity header of a block, a note — stays --surface. */
.fb-tree,
.fb-inspector {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--panel);
  overflow: hidden;
}

.fb-tree {
  border-right: 1px solid var(--line);
}

.fb-inspector {
  border-left: 1px solid var(--line);
}

.fb-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

/* §4.5: PROPERTIES and how much is selected, 28px, above the identity of what is shown. */
.fb-panel-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 28px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line-mid);
  background: transparent;
}

/* A panel title is a micro-label (§3.1), in --ink: it names the panel. */
.fb-panel-title {
  margin: 0;
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The identity (§4.5): ONE line — a block's part number in the accent, then its name at 15px/600 as
   a field renamed in place; a link's two names; a selection's count. The tabs of a block under it,
   sitting on its bottom rule. The phone's Model sheet keeps a micro-label line over a name. */
.fb-sheet-id {
  flex: 0 0 auto;
  padding: 10px 10px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.fb-sheet-id[hidden] {
  display: none;
}

.fb-sheet-id:has(> .fb-tabs) {
  padding-bottom: 0;
}

.fb-sheet-id__line {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 500;
  line-height: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.fb-sheet-id__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.fb-sheet-id__code {
  flex: 0 0 auto;
  color: var(--accent);
  font: 500 var(--fs-xs, 10.5px)/20px var(--mono);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-sheet-id__title {
  min-width: 0;
  color: var(--ink);
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 20px;
  overflow-wrap: anywhere;
}

.fb-panel-sub {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-sheet-id__name {
  margin-top: 6px;
  color: var(--ink);
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 20px;
  overflow-wrap: anywhere;
}

/* The name in the header line: a field that reads as the 15px heading until it is pointed at or
   focused, as tall as its lines. */
textarea.fb-sheet-id__name-input {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 26px;
  margin: -3px -6px -3px 0;
  padding: 2px 5px;
  overflow: hidden;
  border-color: transparent;
  background: transparent;
  color: var(--ink);
  font: 600 var(--fs-lg, 15px)/20px var(--font);
  resize: none;
}

textarea.fb-sheet-id__name-input:hover {
  border-color: var(--line-ui);
}

textarea.fb-sheet-id__name-input:focus {
  border-color: var(--accent);
  background: var(--surface);
}

/* Properties · Notes · Tasks (the design's tabs, without counts: the card's footer has them): the active tab is a box in --panel with a
   --line border, an INSET 2px --ink bar on its top and no bottom rule, so it opens onto the panel
   below; the others are plain --text-2 words standing on the header's bottom rule. */
.fb-tabs {
  display: flex;
  margin-top: 10px;
  margin-bottom: -1px;
}

.fb-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid transparent;
  border-bottom-color: var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--text-2);
  font: 400 var(--fs-md, 12px)/1 var(--font);
  cursor: pointer;
}

.fb-tab:hover {
  color: var(--ink);
}

.fb-tab[aria-selected='true'] {
  border-color: var(--line);
  border-bottom-color: var(--panel);
  background: var(--panel);
  color: var(--ink);
  font-weight: 500;
  box-shadow: inset 0 2px 0 var(--ink);
}

.fb-tab:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-tab[aria-selected='true']:focus-visible {
  box-shadow: inset 0 2px 0 var(--ink), inset 0 0 0 1px var(--accent);
}

.fb-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

.fb-panel-body[hidden] {
  display: none;
}

/* A section (§4.5; the owner's request of 2026-10-02: "the headings of the areas are indistinguishable
   from the content, I lose track of the sections"): its head is a full-width --band under a 2px --ink
   rule — thicker than every row hairline —, the title in --ink, Mono 11px/700, with more space above it
   than between rows. The head stays at the top of the sheet's scroll area while its section scrolls
   (sticky inside its own section, so only one at a time). Sub-headings inside a section stay
   micro-labels in --text-2 (.fb-sc-adv__head, .fb-cost-model__title): one level lower. */
.fb-section {
  margin: 14px 0 0;
}

.fb-section:first-child {
  margin-top: 0;
}

.fb-section[hidden] {
  display: none;
}

.fb-section-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 30px;
  padding: 0 10px;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--line);
  background: var(--band);
}

.fb-section-title {
  margin: 0;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-section-hint {
  min-width: 0;
  overflow: hidden;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 400;
  letter-spacing: 0.06em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-section-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px 10px;
}

.fb-panel-actions {
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 10px;
  border-top: 1px solid var(--line-soft);
}

.fb-panel-actions .btn {
  flex: 1 1 auto;
}

/* A segmented choice in a field (source mode): the answers share the control's width. */
.fb-seg-field {
  display: flex;
}

.fb-seg-field > button {
  flex: 1 1 0;
  justify-content: center;
  min-height: calc(var(--control-h) - 2px);
  padding: 0 6px;
  font-size: var(--fs-sm, 11.5px);
}

/* The tab row fitted to the sheet (js/ui.js fitTabs): with Comments the words can be wider than the
   340px sheet or a 360px phone (the Russian words are longer). Snug first — less padding; then the
   Comments tab is its glyph (the word its tooltip and its name) and a long word may shorten. */
.fb-tabs.is-snug > .fb-tab {
  padding: 0 6px;
  gap: 4px;
}

.fb-tab > .fb-ico {
  display: none;
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
}

.fb-tabs.is-glyph > .fb-tab {
  min-width: 0;
}

.fb-tabs.is-glyph > .fb-tab > .fb-tab__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-tabs.is-glyph > .fb-tab[data-tab='comments'] {
  position: relative;
  flex: 0 0 auto;
}

.fb-tabs.is-glyph > .fb-tab[data-tab='comments'] > .fb-ico {
  display: block;
}

.fb-tabs.is-glyph > .fb-tab[data-tab='comments'] > .fb-tab__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* The count on a tab — the open threads on the sheet's Comments tab (COMMENTS §36): mono, in the
   tab's own colour, there only while there are any. */
.fb-tab__count {
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-variant-numeric: tabular-nums;
}

.fb-tab__count[hidden] {
  display: none;
}

/* The Comments tab's panel: the comments module stands its one panel in it (js/review-place.js), which
   scrolls its own list — the tab only gives it the sheet's height. */
.fb-sheet-comments {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.fb-sheet-comments[hidden] {
  display: none;
}

.fb-sheet-comments > .fb-comments {
  flex: 1 1 auto;
}

/* ------------------------------------------------------- notes and tasks */

/* §7.2: the Notes and Tasks tabs of a block's sheet (js/sheet-notes.js). */
.fb-sheet-tab {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
}

.fb-empty {
  margin: 0;
  padding: 10px;
  border: 1px dashed var(--line);
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  text-align: center;
}

.fb-empty[hidden],
.fb-note-list[hidden],
.fb-task-list[hidden],
.fb-segmeter[hidden],
.fb-note-form__error[hidden] {
  display: none;
}

.fb-note-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-note {
  border: 1px solid var(--line);
  background: var(--surface);
}

.fb-note.is-editing {
  padding: 8px;
  border-color: var(--line-ui);
}

/* The design's note head: 22px, the kind in an OUTLINED mono badge on the left, "MK · 09-15" on
   the right, a --line-soft rule under it. */
.fb-note__head {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 8px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-note__kind {
  flex: 0 0 auto;
  padding: 2px 4px;
  border: 1px solid var(--ink);
  color: var(--ink);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* §7.2: an ACTUAL is a measurement, the one kind in the status colour. */
.fb-note__kind.is-ok {
  border-color: var(--ok);
  color: var(--ok);
}

/* §7.2 (format 11): an OBSERVATION is what was noticed, no claim and no number — the plain badge of
   §5.2, stepped up from --muted to --text-2 so it holds on --band too (§2.2). */
.fb-note__kind[data-kind='observation'] {
  border-color: var(--text-2);
  color: var(--text-2);
}

.fb-note__meta {
  margin-left: auto;
  color: var(--muted);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-note__tools {
  display: flex;
  margin-right: -6px;
}

.fb-note__tools .fb-row-btn {
  width: 20px;
  min-width: 20px;
  height: 20px;
  min-height: 20px;
}

/* Out of sight, not out of reach: until the note is pointed at or holds the focus the two buttons
   are clipped to nothing, still in the tab order — tabbing onto one brings both back. */
@media (hover: hover) {
  .fb-note:not(:hover):not(:focus-within) .fb-note__tools {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* The edit and delete of a note or a task: an icon on no box until it is pointed at. */
.fb-row-btn {
  width: 22px;
  min-width: 22px;
  min-height: 22px;
  height: 22px;
  border-color: transparent;
  background: transparent;
  color: var(--text-2);
}

.fb-row-btn:hover:not(:disabled) {
  border-color: var(--line-ui);
  color: var(--ink);
}

.fb-row-btn:disabled {
  border-color: transparent;
}

.fb-row-btn .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-note__text {
  margin: 0;
  padding: 7px 8px;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fb-note__ref {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px 7px;
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-variant-numeric: tabular-nums;
}

.fb-note__rule {
  flex: 0 0 auto;
  width: 10px;
  border-top: 1px solid currentColor;
}

.fb-note__ref.is-gone {
  color: var(--muted);
}

.fb-note__jump {
  margin-left: auto;
  color: var(--accent);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
}

.fb-note__gone {
  margin-left: auto;
  font-family: var(--font);
  font-size: var(--fs-sm, 11px);
}

.fb-note__prompt {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 8px 8px;
}

.fb-note__prompt .btn {
  min-height: var(--control-h);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
}

.fb-note-form {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* The kind of a new note — which the design cannot choose — over the text as a note's head carries
   its badge: three chips in the badge's own face (mono 9.5px capitals, 2px 4px). The chosen one IS
   the badge the note will wear, outlined in ink (an actual in --ok); the others are quiet text with
   no box until pointed at. "Conversion…" on the right opens the conversion picker. */
.fb-note-form__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  min-height: 22px;
}

.fb-note-form__kinds {
  display: flex;
  gap: 4px;
}

.fb-note-chip {
  position: relative;
  min-height: 0;
  padding: 2px 4px;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--text-2);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}

.fb-note-chip:hover {
  border-color: var(--line-ui);
  color: var(--ink);
}

.fb-note-chip[aria-checked='true'] {
  border-color: var(--ink);
  color: var(--ink);
}

.fb-note-chip[data-kind='actual'][aria-checked='true'] {
  border-color: var(--ok);
  color: var(--ok);
}

.fb-note-chip[data-kind='observation'][aria-checked='true'] {
  border-color: var(--text-2);
  color: var(--text-2);
}

/* A note card's kind in its sheet (format 11): the same chips over its text, NONE first; they wrap
   rather than overflow a narrow sheet. On a share link they show the answer and change nothing. */
.fb-note-card__kinds {
  flex-wrap: wrap;
}

.fb-note-chip:disabled {
  cursor: default;
}

.fb-note-chip:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
  border-color: var(--accent);
}

.fb-note-form__ref {
  margin-left: auto;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
}

.fb-note-form__ref[hidden] {
  display: none;
}

.fb-note-form textarea {
  min-height: 62px;
  padding: 6px;
}

.fb-note-form__error {
  margin: 0;
  color: var(--danger);
  font-size: var(--fs-sm, 11px);
}

.fb-note-form__actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Format 12: what a link's measured rate counted — People and Of them went on, two whole numbers
   in the form's rows under the measured rate, and why. */
.fb-note-form__sample {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fb-note-form__sample[hidden] {
  display: none;
}

.fb-note-form__sample-hint {
  margin: 0;
}

/* ⌘↵ at the right edge, as the design sets it beside Add note. */
.fb-note-form__key {
  margin-left: auto;
  color: var(--muted);
  font: 400 var(--fs-xs, 10px)/1 var(--mono);
}

/* The design's Tasks tab: "2 OF 3 DONE" in mono, a 4px bar (ink on --line-soft, --ok once every
   task is done), then one bordered white list whose last row adds a task. */
.fb-task-progress[hidden],
.fb-task-add__more[hidden] {
  display: none;
}

.fb-task-progress__label {
  margin-bottom: 6px;
  color: var(--text-2);
  font: 500 var(--fs-xs, 10px)/1 var(--mono);
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
}

.fb-task-progress__bar {
  height: 4px;
  margin-bottom: 2px;
  background: var(--line-soft);
}

.fb-task-progress__fill {
  display: block;
  height: 4px;
  background: var(--ink);
}

.fb-task-progress.is-ok .fb-task-progress__fill {
  background: var(--ok);
}

.fb-task-box {
  border: 1px solid var(--line);
  background: var(--surface);
}

.fb-task-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-task {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) auto auto;
  align-items: start;
  column-gap: 8px;
  padding: 7px 8px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-task:hover {
  background: var(--bg);
}

.fb-task.is-editing {
  display: block;
  padding: 8px;
}

.fb-task.is-editing:hover {
  background: transparent;
}

/* The design's tick: a white 14px square in --muted, the tick drawn in ink. */
.fb-task > input[type='checkbox'] {
  margin-top: 1px;
  border-color: var(--muted);
}

.fb-task > input[type='checkbox']:checked {
  border-color: var(--muted);
  background: var(--surface);
}

.fb-task > input[type='checkbox']:checked::after {
  border-color: var(--ink);
}

.fb-task__text {
  min-width: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.35;
  overflow-wrap: anywhere;
  cursor: pointer;
}

.fb-task.is-done .fb-task__text {
  color: var(--muted);
  text-decoration: line-through;
}

/* The due day, "09-12" in mono on the right; a click opens the task on its date. */
.fb-task__due {
  min-height: 16px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  font: 400 var(--fs-xs, 10px)/16px var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

button.fb-task__due {
  cursor: pointer;
}

button.fb-task__due:hover {
  color: var(--ink);
  text-decoration: underline;
}

button.fb-task__due:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-task__due.is-overdue {
  color: var(--danger);
}

.fb-task__tools {
  display: flex;
  margin: -2px 0;
}

.fb-task__tools .fb-row-btn {
  width: 20px;
  min-width: 20px;
  height: 20px;
  min-height: 20px;
}

/* As in a note: edit and delete unseen until the row is pointed at or holds the focus — but in
   their place, so the day stays at the right edge and the text never re-wraps as the pointer
   moves over the list. Transparent, not hidden: Tab still reaches them and shows them. */
@media (hover: hover) {
  .fb-task:not(:hover):not(:focus-within) .fb-task__tools {
    opacity: 0;
  }
}

/* "+ Add a task, press Enter": the list's last row, a field without a box of its own. */
.fb-task-add {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 5px 8px;
}

.fb-task-add__line {
  display: flex;
  align-items: center;
  gap: 8px;
}

.fb-task-add__plus {
  flex: 0 0 auto;
  width: 16px;
  color: var(--muted);
  font: 400 var(--fs-md, 13px)/1 var(--mono);
  text-align: center;
}

.fb-task-add__line > input[type='text'] {
  flex: 1 1 auto;
  padding: 0 4px;
  border-color: transparent;
  background: transparent;
}

.fb-task-add__line > input[type='text']:hover {
  border-color: transparent;
}

.fb-task-add__line > input[type='text']:focus {
  border-color: var(--accent);
}

/* Once a task is typed: its due day and Add, under the text. */
.fb-task-add__more {
  display: flex;
  align-items: center;
  gap: 6px;
}

.fb-task-add > .fb-task-add__more {
  padding-left: 24px;
}

.fb-task-add__due-label {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  white-space: nowrap;
}

.fb-task-add__more > input[type='date'] {
  flex: 0 1 132px;
  width: auto;
}

.fb-task-add__more > .btn {
  margin-left: auto;
  min-height: var(--control-h);
}

.fb-task-edit {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* A task list's item on the canvas, edited in the sheet: text field, ↑ ↓ × (the tick is the card's). */
.fb-todo-row-edit {
  grid-template-columns: minmax(0, 1fr) auto auto auto;
}

.fb-todo-edit + .fb-extra-add {
  margin-top: 0;
}

/* ------------------------------------------------------- colour swatches */

/* The design's tag swatches (FunnelCAD.dc.html, GENERAL ▸ Tag): a 20px white square holding the
   colour 2px in from its edge, the chosen one bounded in --ink, the others by nothing — the colour
   is the boundary (§2.4 tags are all ≥ 3:1 on white). WCAG 2.2 2.5.8 by the spacing exception: 20px
   squares 4px apart put the centres 24px apart, so a 24px circle on each only touches its
   neighbour's. The row is 8 x 20 + 7 x 4 = 188px, which is the control column of the 316px sheet
   less 9px and exactly that of the 300px one with its 85px label cell. */
.fb-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.fb-swatch {
  width: 20px;
  height: 20px;
  padding: 2px;
  border: 1px solid transparent;
  border-radius: 0;
  background: linear-gradient(var(--fb-swatch, var(--surface)), var(--fb-swatch, var(--surface))) content-box, var(--surface);
  cursor: pointer;
  appearance: none;
}

.fb-swatch:hover {
  border-color: var(--line-ui);
}

/* The chosen tag is bounded in --ink (§4.5): the accent is for selection on the canvas. */
.fb-swatch[aria-pressed='true'] {
  border-color: var(--ink);
}

/* "No color": an empty square in a --line-ui hairline, crossed by one. */
.fb-swatch-none {
  background: linear-gradient(
      to top right,
      transparent calc(50% - 0.5px),
      var(--line-ui) calc(50% - 0.5px),
      var(--line-ui) calc(50% + 0.5px),
      transparent calc(50% + 0.5px)
    )
    content-box,
    var(--surface);
  box-shadow: inset 0 0 0 2px var(--surface), inset 0 0 0 3px var(--line-ui);
}

.fb-swatch[data-color='gray'],
.fb-menu__swatch[data-color='gray'],
.fb-tree__tag[data-color='gray'],
.fb-orow__tag[data-color='gray'] {
  --fb-swatch: var(--tag-gray);
}

.fb-swatch[data-color='blue'],
.fb-menu__swatch[data-color='blue'],
.fb-tree__tag[data-color='blue'],
.fb-orow__tag[data-color='blue'] {
  --fb-swatch: var(--tag-blue);
}

.fb-swatch[data-color='green'],
.fb-menu__swatch[data-color='green'],
.fb-tree__tag[data-color='green'],
.fb-orow__tag[data-color='green'] {
  --fb-swatch: var(--tag-green);
}

.fb-swatch[data-color='amber'],
.fb-menu__swatch[data-color='amber'],
.fb-tree__tag[data-color='amber'],
.fb-orow__tag[data-color='amber'] {
  --fb-swatch: var(--tag-amber);
}

.fb-swatch[data-color='red'],
.fb-menu__swatch[data-color='red'],
.fb-tree__tag[data-color='red'],
.fb-orow__tag[data-color='red'] {
  --fb-swatch: var(--tag-red);
}

.fb-swatch[data-color='purple'],
.fb-menu__swatch[data-color='purple'],
.fb-tree__tag[data-color='purple'],
.fb-orow__tag[data-color='purple'] {
  --fb-swatch: var(--tag-purple);
}

.fb-swatch[data-color='teal'],
.fb-menu__swatch[data-color='teal'],
.fb-tree__tag[data-color='teal'],
.fb-orow__tag[data-color='teal'] {
  --fb-swatch: var(--tag-teal);
}

/* ------------------------------------------------------------ model tree */

/* §4.3: the left column — MODEL TREE, a filter, the groups by part-number prefix with 24px rows
   (tag, part number, name; no figure, §1.8) — and the SCENARIOS panel at its foot. The
   tree takes the height that is left and scrolls; the scenarios scroll on their own after five
   rows. Built by js/tree.js. */
.fb-tree__head,
.fb-scen__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 28px;
  padding: 0 10px;
}

.fb-tree__head {
  border-bottom: 1px solid var(--line-mid);
}

.fb-tree__filter {
  flex: 0 0 auto;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line-mid);
}

.fb-tree__filter[hidden],
.fb-tree__list[hidden],
.fb-tree__empty[hidden] {
  display: none;
}

.fb-tree__filter-input {
  width: 100%;
}

.fb-tree__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 4px 0;
  overflow-x: hidden;
  overflow-y: auto;
}

.fb-tree__group,
.fb-tree__row,
.fb-scen__row {
  cursor: default;
  user-select: none;
}

/* A group holds its rows, so its ring goes on its head row, not around the whole group. */
.fb-tree__group:focus-visible {
  outline: none;
}

.fb-tree__ghead {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 10px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1;
  text-transform: uppercase;
}

.fb-tree__ghead .fb-ico {
  width: 8px;
  height: 8px;
}

.fb-tree__group[aria-expanded='false'] > .fb-tree__ghead .fb-ico {
  transform: rotate(-90deg);
}

.fb-tree__gcount {
  margin-left: auto;
}

/* On --hover a micro-label steps up to --text-2 (§2.2). */
.fb-tree__ghead:hover {
  background: var(--hover);
  color: var(--text-2);
}

.fb-tree__group:focus-visible > .fb-tree__ghead {
  background: var(--hover);
  color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-tree__row {
  display: grid;
  grid-template-columns: 9px 44px minmax(0, 1fr);
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px 0 18px;
}

.fb-tree__row:hover {
  background: var(--hover);
}

.fb-tree__row.is-selected {
  background: var(--select);
  box-shadow: inset 2px 0 0 var(--accent);
}

.fb-tree__row.is-selected:hover {
  background: var(--select-2);
}

.fb-tree__row:focus-visible {
  outline: none;
  background: var(--hover);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-tree__row.is-selected:focus-visible {
  outline: none;
  background: var(--select-2);
  box-shadow: inset 2px 0 0 var(--accent), inset 0 0 0 1px var(--accent);
}

/* The 9×9 tag swatch (§2.4); a block without a tag shows the empty square. */
.fb-tree__tag {
  width: 9px;
  height: 9px;
  border: 1px solid var(--fb-swatch, var(--line-ui));
  background: var(--fb-swatch, transparent);
}

/* A scorecard without a tag of its own is ink, as its card is outlined in ink (§4.4). */
.fb-tree__tag[data-color='none'][data-kind='SCR'] {
  border-color: var(--ink);
  background: var(--ink);
}

.fb-tree__code {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-tree__name {
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-tree__row.is-selected .fb-tree__code {
  color: var(--accent);
}

.fb-tree__row.is-selected .fb-tree__name {
  font-weight: 500;
}

/* A name being renamed in its row (F2): the field takes the name's cell, a little shorter than
   the row so its ring shows. */
input.fb-tree__edit {
  width: 100%;
  min-width: 0;
  height: 20px;
  padding: 0 4px;
}

.fb-tree__empty {
  padding: 12px 10px;
}

.fb-tree__empty-title {
  margin: 0 0 4px;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
}

/* ------------------------------------------------------------ scenarios */

.fb-scen {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--line);
}

/* 20px as in the design: its 24px target circle stays inside the 28px head (WCAG 2.5.8 spacing). */
.fb-scen__new {
  min-height: 20px;
  height: 20px;
  gap: 3px;
  padding: 0 6px;
  font-size: var(--fs-sm, 11px);
}

/* Five rows, then the list scrolls on its own (§4.3). */
.fb-scen__list {
  max-height: calc(5 * 24px);
  margin-bottom: 8px;
  overflow-y: auto;
}

.fb-scen__row {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 24px;
  padding: 0 10px;
}

.fb-scen__row:hover {
  background: var(--hover);
}

.fb-scen__row.is-active {
  background: var(--surface);
  box-shadow: inset 0 1px 0 var(--line-soft), inset 0 -1px 0 var(--line-soft);
}

.fb-scen__row:focus-visible {
  outline: none;
  background: var(--hover);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* The square radio of §5, drawn: the row is the radio, so the mark is not a control of its own. */
.fb-scen__radio {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-scen__radio.is-on {
  border-color: var(--ink);
  background: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--surface);
}

.fb-scen__name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-scen__row.is-active .fb-scen__name {
  font-weight: 500;
}

/* -------------------------------------------------------------- inspector */

.fb-readout {
  margin: 0;
  border: 1px solid var(--line-soft);
  background: var(--surface-2);
}

.fb-readout-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 8px;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-sm, 11px);
}

.fb-readout-row:last-child {
  border-bottom: none;
}

.fb-readout dt {
  display: flex;
  flex: 0 1 auto;
  min-width: 0;
  color: var(--muted);
  white-space: nowrap;
}

/* In a 248-272 px inspector a label such as "First subscriber, 90%" next to "longer than
   100 years" may not fit. The name gives way, cut with an ellipsis; the note (", 90%"),
   which tells two rows apart, and the value never shrink. The row's title names it in full. */
.fb-readout-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-readout-note {
  flex: none;
}

.fb-readout dd {
  flex: none;
  margin: 0;
  font-size: var(--fs-sm, 11px);
  text-align: right;
  white-space: nowrap;
}

/* COSTS (§4.5, format 16; the owner's mockups "2a Costs list on an offer" and "2b Add cost — inline
   form" of 2026-10-02): one list in place of the four cost fields. The section's head carries + Add
   cost (or, while the form is open, how many items the list has); a row is the item's label over its two
   tags and, on the right, the amount as its owner pays it over when and for whom; under the rows the
   grey box of what the model uses. */
.fb-section--costs > .fb-section-head {
  min-height: 34px;
}

.fb-section--costs > .fb-section-body {
  gap: 0;
  padding-top: 0;
}

.fb-costs__tools {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}

.fb-costs__add {
  min-height: var(--control-h);
  padding: 0 8px;
  gap: 5px;
  font-size: var(--fs-sm, 11.5px);
}

.fb-costs__add .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-costs__list {
  display: flex;
  flex-direction: column;
}

.fb-costs__empty {
  margin: 0;
  padding: 10px 0 2px;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.4;
}

.fb-cost {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  margin: 0;
  padding: 8px 0;
  border: 0;
  border-bottom: 1px solid var(--line-soft);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
}

.fb-cost.is-button {
  /* The hover wash runs to the sheet's edges; the text keeps the section's own inset. */
  width: calc(100% + 20px);
  margin: 0 -10px;
  padding: 8px 10px;
  cursor: pointer;
}

.fb-cost.is-button:hover {
  background: var(--hover);
}

.fb-cost.is-button:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}

.fb-cost__main {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.fb-cost__label {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  font-size: var(--fs-md, 12.5px);
  line-height: 16px;
}

.fb-cost__name {
  min-width: 0;
  overflow-wrap: anywhere;
}

.fb-cost__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

/* A tag of a row: how often (on --band), per customer or visitor (the accent on its wash), fixed
   (outlined). Mono, uppercase, as every micro-label. */
.fb-cost-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 5px;
  border: 1px solid transparent;
  background: var(--band);
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-cost-tag.is-each {
  background: var(--select);
  color: var(--accent);
}

.fb-cost-tag.is-fixed {
  border-color: var(--line);
  background: transparent;
}

.fb-cost__paid {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  max-width: 62%;
  text-align: right;
}

.fb-cost__amount {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-end;
  gap: 0 6px;
  font-family: var(--mono);
  font-size: var(--fs-md, 12.5px);
  line-height: 16px;
}

.fb-cost__money {
  font-weight: 600;
}

.fb-cost__detail,
.fb-cost__suffix {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
  white-space: nowrap;
}

/* While the form is open the other rows step back: the form is the one thing being read. */
.fb-costs__list.has-form .fb-cost {
  opacity: 0.55;
}

.fb-costs__list.has-form .fb-cost.is-button:hover,
.fb-costs__list.has-form .fb-cost.is-button:focus-visible {
  opacity: 1;
}

/* A Review link's marks of an item (docs/COMMENTS.md §9.1, §9.6): Suggest… beside its label, out of
   sight until the row is pointed at or holds the focus (always there for a finger), and the values
   people propose for it under the row. */
.fb-cost__label > .fb-suggest {
  flex: 0 0 auto;
  margin-inline-start: 4px;
  font-size: var(--fs-sm, 11px);
  opacity: 0;
}

.fb-cost:hover .fb-cost__label > .fb-suggest,
.fb-cost__label > .fb-suggest:focus-visible {
  opacity: 1;
}

@media (hover: none) {
  .fb-cost__label > .fb-suggest {
    opacity: 1;
  }
}

.fb-cost-wrap > .fb-redline-row {
  padding: 4px 0 6px;
  border-bottom: 1px solid var(--line-soft);
}

/* What the model uses: the totals the engine reads, on --surface-2 as every computed readout. */
.fb-cost-model {
  margin-top: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  background: var(--surface-2);
}

.fb-cost-model__title {
  margin-bottom: 6px;
  color: var(--text-2);
}

.fb-cost-model__rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
}

.fb-cost-model__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--fs-sm, 11.5px);
  line-height: 16px;
}

.fb-cost-model__row dt {
  min-width: 0;
  color: var(--ink);
}

.fb-cost-model__row dd {
  flex: 0 0 auto;
  margin: 0;
  font-family: var(--mono);
  font-weight: 600;
  white-space: nowrap;
}

/* The form (2b): an ink boundary — the one thing being edited —, four questions top to bottom, then
   the band of what it adds and the two actions. */
.fb-cost-form {
  margin: 8px 0;
  border: 1px solid var(--ink);
  background: var(--surface);
}

.fb-cost-form__body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 10px;
}

.fb-cost-form__group {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.fb-cost-form__label {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
}

.fb-cost-form__text {
  width: 100%;
  min-width: 0;
}

.fb-cost-form__amount {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.fb-cost-form__amount > .fb-input {
  flex: 1 1 auto;
}

.fb-cost-form__amount > .fb-input > input,
.fb-cost-form__rate-row > .fb-input > input {
  width: 0;
}

.fb-cost-form .fb-unit[hidden] {
  display: none;
}

.fb-cost-form .fb-unit.is-lead {
  border-right: 1px solid var(--line-soft);
  border-left: 0;
}

.fb-cost-form__seg {
  display: flex;
}

.fb-cost-form__seg > button {
  /* By their words, not in equal fifths: the Russian for Weekly is twice its Yearly, and equal cells
     broke it into two lines. */
  flex: 1 1 auto;
  justify-content: center;
  min-width: 0;
  padding: 0 4px;
  white-space: nowrap;
  font-size: var(--fs-sm, 11.5px);
}

.fb-cost-form__amount > .fb-cost-form__seg {
  flex: 0 0 auto;
}

.fb-cost-form__amount > .fb-cost-form__seg > button {
  flex: 0 0 auto;
  padding: 0 10px;
}

.fb-cost-form__seg > button:disabled {
  color: var(--muted);
  background: var(--surface-2);
  cursor: default;
}

.fb-cost-form__rate[hidden] {
  display: none;
}

.fb-cost-form__rate {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.fb-cost-form__rate-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.fb-cost-form__rate-row > .fb-input {
  flex: 0 0 112px;
  margin-inline-start: auto;
}

.fb-cost-form__default[hidden] {
  display: none;
}

.fb-cost-form__hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.4;
}

.fb-cost-form__hint[hidden] {
  display: none;
}

.fb-cost-form__hint .btn-link {
  font-size: inherit;
}

.fb-cost-form__seg + .fb-cost-form__hint,
.fb-cost-form__per + .fb-cost-form__hint {
  margin-top: 5px;
}

.fb-cost-form__scenario {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.fb-cost-form__scenario .fb-override-dot {
  transform: translateY(-1px);
}

/* Grows with: the answers as rows of one box, each a title over what it means. */
.fb-cost-form__per {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
}

.fb-cost-form__choice {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 7px 8px;
  border-top: 1px solid var(--line-soft);
  cursor: pointer;
}

.fb-cost-form__choice:first-child {
  border-top: 0;
}

.fb-cost-form__choice:has(> input:checked) {
  background: var(--select-wash);
}

.fb-cost-form__choice > input {
  flex: 0 0 auto;
  margin: 2px 0 0;
}

.fb-cost-form__choice-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.fb-cost-form__per-title {
  font-size: var(--fs-md, 12.5px);
  font-weight: 500;
  line-height: 16px;
}

.fb-cost-form__per-hint {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

.fb-cost-form__manage {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--line-soft);
}

.fb-cost-form__delete {
  color: var(--danger);
  font-size: var(--fs-sm, 11.5px);
}

.fb-cost-form__reset {
  font-size: var(--fs-sm, 11.5px);
}

.fb-cost-form__moves {
  display: inline-flex;
  gap: 4px;
  margin-inline-start: auto;
}

.fb-cost-form__move {
  width: var(--control-h);
  min-width: var(--control-h);
  min-height: var(--control-h);
}

.fb-cost-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 8px 10px;
  border-top: 1px solid var(--line-soft);
  background: var(--surface-2);
}

.fb-cost-form__adds {
  /* The line keeps one row while it can: where it and the buttons do not fit (the Russian Save is long), the
     buttons take the next row; a line wider than the form wraps. */
  flex: 1 1 auto;
  min-width: min(100%, max-content);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  line-height: 15px;
}

.fb-cost-form__adds-detail {
  color: var(--text-2);
}

.fb-cost-form__adds-detail[hidden] {
  display: none;
}

.fb-cost-form__actions {
  display: flex;
  flex: 0 0 auto;
  gap: 6px;
}

/* A phone's sheet: a finger's height for the answers of How often, as for every control there. */
@media (width < 760px) {
  .fb-cost-form__seg > button {
    min-height: 40px;
    font-size: 14px;
  }
}

/* Account settings ▸ Profile ▸ Default hourly rate: a number with its two units, as a sheet's field. */
.fb-settings__rate-cell > .fb-settings__rate {
  width: 132px;
}

.fb-settings__rate > input {
  width: 0;
}

.fb-settings__rate > .fb-unit.is-lead {
  border-right: 1px solid var(--line-soft);
  border-left: 0;
}

.fb-extras {
  margin-top: 6px;
}

.fb-extra {
  margin-bottom: 8px;
  padding: 7px;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-extra-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 4px;
}

.fb-extra-index {
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
}

.fb-extra-add {
  width: 100%;
}

/* ----------------------------------------------------------------- canvas */

.fb-main {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
}

.fb-canvas {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--bg);
  touch-action: none;
  cursor: default;
  user-select: none;
  -webkit-user-select: none;
}

.fb-canvas:focus {
  outline: none;
}

/* The cards live inside the canvas, so a normal outline is painted underneath
   them and the ring looks broken wherever a card touches the edge. Draw the
   focus ring as an overlay above the whole layer instead. */
.fb-canvas:focus-visible {
  outline: none;
}

.fb-canvas:focus-visible::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 30;
  box-shadow: inset 0 0 0 2px var(--accent);
  pointer-events: none;
}

/* canvas.js: a frame being drawn, Space held, the canvas being moved. The cards inherit the
   cursor for the time: under Space a press on a port pans, so its crosshair would promise a
   connection that never comes. The later rule wins, so a pan started with Space shows the closed
   hand. */
.fb-canvas.is-selecting,
.fb-canvas.is-selecting .fb-world * {
  cursor: crosshair;
}

/* ⌥ held: a drag from a card copies it (canvas.js startDuplicateDrag). */
.fb-canvas.is-alt-copy .fb-node,
.fb-canvas.is-alt-copy .fb-node * {
  cursor: copy;
}

/* The Pan tool (H) and Space held: a press anywhere pans. */
.fb-canvas.is-pan-tool,
.fb-canvas.is-pan-tool .fb-world *,
.fb-canvas.is-space-pan,
.fb-canvas.is-space-pan .fb-world * {
  cursor: grab;
}

/* View ▸ Show grid off: the paper without its lines. Snapping does not depend on it. */
.fb-canvas.is-grid-off .fb-grid {
  display: none;
}

.fb-canvas.is-panning,
.fb-canvas.is-panning .fb-world * {
  cursor: grabbing;
}

.fb-canvas.is-connecting {
  cursor: crosshair;
}

/* app.js sets this while a palette block or a .json file hovers the canvas. */
.fb-canvas.is-drop-target {
  box-shadow: inset 0 0 0 1px var(--accent);
  background: var(--select-wash);
}

/* The drawing grid (§2.5): a minor line every pitch and a major line every fifth, both drawn
   by gradients on a static layer. canvas.js moves and scales it through --fb-grid-x / -y and
   --fb-grid-size (the drawn pitch, which it doubles or halves at extreme zoom so the mesh never
   turns to mush or to a sparse net). */
.fb-grid {
  --fb-grid-major: calc(var(--fb-grid-size, 16px) * 5);
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-major) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-major) 1px, transparent 1px),
    linear-gradient(to right, var(--grid-minor) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-minor) 1px, transparent 1px);
  background-size:
    var(--fb-grid-major) var(--fb-grid-major),
    var(--fb-grid-major) var(--fb-grid-major),
    var(--fb-grid-size, 16px) var(--fb-grid-size, 16px),
    var(--fb-grid-size, 16px) var(--fb-grid-size, 16px);
  background-position: var(--fb-grid-x, 0px) var(--fb-grid-y, 0px);
}

.fb-world {
  position: absolute;
  /* The cards are drawn at the compact scale on every screen (§3.1): what they inherit stays the
     compact body size, not the desktop's --fs-md. */
  font-size: 12px;
  left: 0;
  top: 0;
  z-index: 1;
  width: 0;
  height: 0;
  transform-origin: 0 0;
  /* No will-change here: a layer kept for transforms is drawn once and then stretched, so cards
     zoomed in went blurry (Safari never redraws it). canvas.js sets it only while the view moves. */
}

.fb-edges {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  overflow: visible;
  pointer-events: none;
}

/* A connector is a graphical object the funnel cannot be read without, so the stroke
   carries 3:1 against the canvas in its own right (1.4.11). It is drawn thin, as a line of a
   drawing is (docs/DESIGN.md §4.4); the 14px hit stroke under it is what a pointer finds. The head
   is a small filled triangle, a second path of its own (.fb-edge-arrow). */
.fb-edge {
  fill: none;
  stroke: var(--edge);
  stroke-width: 1;
  stroke-linecap: butt;
  stroke-linejoin: round;
}

.fb-edge-arrow {
  fill: var(--edge);
  stroke: none;
}

/* A line to a note or a checklist explains, it does not carry people: dotted, with no arrowhead
   and no percentage. The stroke keeps --edge, so it still clears 3:1. */
.fb-edge.is-annotation {
  stroke-dasharray: 2 4;
}

/* A link into a scorecard feeds its totals and moves nobody: dashed, with its small filled head. */
.fb-edge.is-result {
  stroke-dasharray: 4 3;
}

/* No chip on these — a line to a note, a link into a summary — so the line carries the 24px
   target and the focus ring (2.5.8). */
.fb-edge-hit.is-annotation,
.fb-edge-hit.is-result {
  stroke-width: 24;
}

.fb-edge-hit.is-annotation:focus-visible,
.fb-edge-hit.is-result:focus-visible {
  outline: none;
  stroke: var(--select-wash);
}

.fb-edge-hit.is-annotation:focus-visible + .fb-edge,
.fb-edge-hit.is-result:focus-visible + .fb-edge {
  stroke: var(--accent);
  stroke-width: 1.5;
}

/* A selected summary fades what it does not add up: the surface of a card, its frame (dashed, a cue of
   form besides the colour), its colour tag and the links — never the words. A faded card or chip is
   still clicked, focused and read, so its text keeps 4.5:1 (1.4.3): --muted on --bg is 4.64:1 light
   and 6.55:1 dark, the colours of a sign 4.88 and 5.98 light. Opacity 0.35 took the text to 2.4:1 and
   the muted rows to 1.6:1. The words for a screen reader are the canvas's (aria-describedby). */
.fb-node.is-faded {
  border-style: dashed;
  background: var(--bg);
  color: var(--muted);
}

.fb-node.is-faded .fb-node-header,
.fb-node.is-faded .fb-cell {
  background: var(--bg);
}

.fb-node.is-faded .fb-node-part,
.fb-node.is-faded .fb-node-kind {
  color: var(--muted);
}

.fb-node.is-faded .fb-node-kind.is-badge {
  border-color: var(--muted);
  color: var(--muted);
}

.fb-node.is-faded .fb-todo-check {
  color: var(--muted);
}

.fb-node.is-faded::before,
.fb-edges g.is-faded {
  opacity: 0.35;
}

.fb-edge-chip.is-faded {
  background: var(--bg);
  color: var(--muted);
}

.fb-edges g {
  transition: opacity 0.12s linear;
}

.fb-edge.is-upsell {
  stroke-dasharray: 5 3;
}

/* Selected, under the pointer, or a link of the one selected block: the accent. */
.fb-edge.is-selected,
.fb-edge.is-linked,
.fb-edge-hit:hover + .fb-edge,
.fb-edge.is-hover {
  stroke: var(--accent);
  stroke-width: 1.5;
}

.fb-edge-arrow.is-selected,
.fb-edge-arrow.is-linked,
.fb-edge-hit:hover + .fb-edge + .fb-edge-arrow {
  fill: var(--accent);
}

.fb-edge-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 14;
  pointer-events: stroke;
  cursor: pointer;
}

/* The rate tag of a link: the rate in mono, boxed at the label point of the line like a dimension,
   with UP before an upsell's rate and REST after a rate of those who stayed. */
.fb-edge-chip {
  position: absolute;
  z-index: 3;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 3px;
  max-width: 160px;
  padding: 0 4px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  font-size: 10px;
  line-height: 16px;
  white-space: nowrap;
  pointer-events: auto;
  cursor: pointer;
}

/* A rate the active scenario gives a value of its own: the accent square of §7.3, before the rate. */
.fb-edge-override {
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  background: var(--accent);
}

.fb-edge-override[hidden] {
  display: none;
}

.fb-edge-mod {
  color: var(--muted);
  font-size: 8.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* How long people take along the link (format 9), after the rate and its modifiers: `· 0–115 d`,
   the same mono size, one step quieter than the rate it follows. */
.fb-edge-lag {
  color: var(--text-2);
}

.fb-edge-lag::before {
  content: '· ';
}

.fb-edge-lag[hidden] {
  display: none;
}

/* The link's own notes and open tasks (format 10): the card footer's glyphs, 8px and in --muted, with
   no counts — a light mark that there is something to read in the link's sheet. Last on the tag's
   row: after the wait on one row, after the rate when the wait takes a row of its own. */
.fb-edge-noted {
  order: 1;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 1px;
  color: var(--muted);
}

.fb-edge-noted[hidden] {
  display: none;
}

.fb-edge-noted .fb-foot-icon {
  display: block;
  fill: none;
  stroke: currentColor;
}

.fb-edge-chip.is-stacked > .fb-edge-noted:not([hidden]) {
  vertical-align: middle;
}

/* A tag with a wait that has no room off the cards in one row (two neighbouring cards are closer
   than `40% · 0–115 d` is wide) is set in two rows, centred: the rate, then the wait — no `·`. The
   flex gap becomes a margin between the visible parts of the first row. */
.fb-edge-chip.is-stacked {
  display: inline-block;
  text-align: center;
}

.fb-edge-chip.is-stacked > :not([hidden]) ~ :not([hidden]):not(.fb-edge-lag) {
  margin-left: 3px;
}

.fb-edge-chip.is-stacked > .fb-edge-override {
  display: inline-block;
  vertical-align: middle;
}

.fb-edge-chip.is-stacked > .fb-edge-override[hidden] {
  display: none;
}

.fb-edge-chip.is-stacked > .fb-edge-lag:not([hidden]) {
  display: block;
}

.fb-edge-chip.is-stacked > .fb-edge-lag::before {
  content: none;
}

/* Still wider than the gap in two rows (the Russian `30–90` with its unit between the examples' cards 56 px apart): the
   unit under the days, a third row. */
.fb-edge-chip.is-stacked.is-narrow .fb-edge-lag-unit {
  display: block;
}

/* 2.5.8: the chip is 18px tall and must not grow — it sits on a 1px line. The hit
   area is stretched to 24px with a pseudo-element instead. Offsets are measured from
   the chip's padding box (16px tall), so -4px top and bottom makes 24px exactly, and
   -1px left/right reaches the outside of the border. `z-index: -1` keeps the strip
   behind the chip's own content, so the inline rate <input> still takes its own
   clicks; everywhere else the pseudo-element is hit and the event target is the chip. */
.fb-edge-chip::after {
  content: '';
  position: absolute;
  left: -1px;
  right: -1px;
  top: -4px;
  bottom: -4px;
  z-index: -1;
}

.fb-edge-chip:hover {
  border-color: var(--ink);
}

.fb-edge-chip.is-linked {
  border-color: var(--accent);
  color: var(--accent);
}

.fb-edge-chip.is-selected {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--accent);
}

/* The editing field is a target of its own, so it carries the full 24px (2.5.8); the
   chip grows with it for as long as the edit lasts and snaps back to 18px after. */
.fb-edge-chip input {
  width: 46px;
  min-height: 24px;
  padding: 0 2px;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: right;
}

.fb-edge-chip input:focus {
  outline: 1px solid var(--accent);
  outline-offset: 0;
}

/* ------------------------------------------------------------------ cards */

/* A card is a part on the drawing (docs/DESIGN.md §4.4): 168px wide, a 20px header with the part
   number and the kind, the name, then what the kind shows, and a footer. Its outline is --line-ui,
   the boundary of a thing you can press and drag (§2.3); hover darkens it to ink. */
.fb-node {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  width: 168px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
  color: var(--ink);
  font-size: 12px;
  cursor: default;
}

.fb-node:hover {
  border-color: var(--ink);
}

/* A computed block is always 128px — four CARD_HEIGHT_STEPs (js/routing.js snapCardHeight) — so
   every side's middle is a grid line and its ports never move while its numbers change. */
.fb-node.is-computed {
  height: 128px;
}

/* Selected: the accent outline, and the label above the card (.fb-node-sel). */
.fb-node.is-selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.fb-node.is-dragging {
  opacity: 0.85;
  cursor: grabbing;
}

.fb-node.is-valid-target {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
}

/* The 3px tag bar on the left edge, over the border (§2.4). A pseudo-element, not a border: the
   card stays 168px wide and the measured port offsets never move. Ports sit at z-index 4, above. */
.fb-node::before {
  content: '';
  position: absolute;
  z-index: 1;
  top: -1px;
  bottom: -1px;
  left: -1px;
  width: 3px;
  background: var(--fb-node-bar, transparent);
  pointer-events: none;
}

.fb-node[data-color='none']::before {
  display: none;
}

.fb-node-header {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 6px;
  height: 20px;
  padding: 0 6px 0 9px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--band);
  color: var(--text-2);
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: grab;
}

.fb-node.is-dragging .fb-node-header {
  cursor: grabbing;
}

.fb-node-part {
  flex: 0 0 auto;
  color: var(--ink);
}

.fb-node.is-selected .fb-node-part {
  color: var(--accent);
}

.fb-node-kind {
  min-width: 0;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A note card with a kind (format 11, §7.2) wears the Notes tab's badge where NOTE stood: outlined,
   ASSUMPTION and PLAN in ink, ACTUAL in --ok, OBSERVATION in --text-2. Its NTE code and its ruled
   sheet already say it is a note; the card's name for a screen reader says both. */
.fb-node-kind.is-badge {
  flex: 0 0 auto;
  padding: 2px 4px;
  border: 1px solid var(--ink);
  color: var(--ink);
  letter-spacing: 0.06em;
}

.fb-node-kind.is-badge[data-note-kind='actual'] {
  border-color: var(--ok);
  color: var(--ok);
}

.fb-node-kind.is-badge[data-note-kind='observation'] {
  border-color: var(--text-2);
  color: var(--text-2);
}

.fb-node-title {
  flex: 0 0 auto;
  height: 26px;
  padding: 0 8px 0 9px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 26px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The micro-table: two columns of label over value, ruled by the gaps (§4.4). */
.fb-node-table {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  min-height: 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  background: var(--line-soft);
}

.fb-cell {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  min-width: 0;
  padding: 0 6px 0 9px;
  background: var(--surface);
}

.fb-cell-k {
  overflow: hidden;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 8.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.06em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-cell-v {
  overflow: hidden;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The value's line: the value, and a range's glyph after it (format 8) — a line from From to To
   with end ticks, the average month a square on it; its numbers are the glyph's title and the card's
   accessible name. */
.fb-cell-line {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
}

.fb-cell-line > .fb-cell-v {
  flex: 0 1 auto;
}

.fb-cell-range {
  position: relative;
  flex: 0 0 auto;
  width: 18px;
  height: 7px;
  border-right: 1px solid var(--muted);
  border-left: 1px solid var(--muted);
  background: linear-gradient(var(--muted), var(--muted)) center / 100% 1px no-repeat;
}

.fb-cell-range-dot {
  position: absolute;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  background: var(--ink);
}

.fb-node-foot {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 9px;
  height: 18px;
  padding: 0 6px 0 9px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  white-space: nowrap;
}

.fb-foot-item {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.fb-foot-item[hidden] {
  display: none;
}

.fb-foot-icon {
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

.fb-foot-rate {
  min-width: 0;
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The label over a selected card: the word `Selected`, mono on the accent, on every kind of block
   (the owner's picture, review point 15 — coordinates and size are the property sheet's). It
   repeats the card's own selected state, so it is aria-hidden; pointer events pass through it. */
.fb-node-sel {
  position: absolute;
  z-index: 5;
  bottom: calc(100% + 5px);
  left: -2px;
  display: none;
  padding: 2px 5px;
  background: var(--accent);
  color: var(--accent-text);
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 600;
  line-height: 11px;
  letter-spacing: 0.02em;
  white-space: nowrap;
  pointer-events: none;
}

.fb-node.is-selected .fb-node-sel {
  display: block;
}

.fb-node-body {
  padding: 5px 8px 6px 9px;
}

/* A note is a ruled sheet: its lines fall under the lines of its text. */
.fb-node.is-note .fb-node-body {
  min-height: 32px;
  padding: 0 8px 8px 9px;
  background-image: repeating-linear-gradient(to bottom, transparent 0, transparent 15px, var(--line-soft) 15px, var(--line-soft) 16px);
  color: var(--ink-2);
  line-height: 16px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fb-node.is-faded.is-note .fb-node-body {
  color: var(--muted);
}

/* The scorecard (DESIGN §7.5, the owner's decision of 2026-09-28): the glance — a picture, every
   figure with its unit — 296 × 320 (the Run mode 296 × 384): 168 + 2 × 64 wide so its top and bottom ports stay on the grid,
   10 (12) CARD_HEIGHT_STEPs tall whatever it says (js/scorecard.js SCORECARD_WIDTH/HEIGHT; the picture
   is js/scorecard-card.js's geometry, which the exported picture draws too) — outlined in ink, its header
   band the dark of the menu bar in both themes. */
.fb-node.is-summary {
  width: 296px;
  height: 320px;
  border-color: var(--ink);
}

/* The Run mode's card: its chart, caption and your time need two steps more
   (js/scorecard.js SCORECARD_HEIGHT_RUN). */
.fb-node.is-summary.is-run {
  height: 384px;
}

/* The parts are clipped at the card's body, not at the card: the label over a selected scorecard
   and its ports hang outside the outline like every other card's. */
.fb-node.is-summary > .fb-sc {
  overflow: hidden;
}

.fb-node.is-summary .fb-node-header {
  height: 22px;
  border-bottom-color: var(--chrome);
  background: var(--chrome);
  color: var(--chrome-muted);
}

.fb-node.is-summary .fb-node-part,
.fb-node.is-summary.is-selected .fb-node-part {
  color: var(--chrome-title);
}

.fb-node.is-summary .fb-node-kind {
  margin-left: 0;
}

/* Format 12: the scorecard's mode at the right of its band, a two-part switch TEST | RUN (the owner's
   decision of 2026-10-01, night): both always in sight, the mode in effect filled, the other outlined —
   a button that switches to it (plain words on a share link). */
.fb-node-modes {
  display: inline-flex;
  flex: 0 0 auto;
  margin-left: auto;
}

.fb-node-mode {
  flex: 0 0 auto;
  margin: 0;
  padding: 2px 5px;
  border: 1px solid var(--chrome-line-ui);
  border-radius: 0;
  background: transparent;
  color: var(--chrome-muted);
  font: inherit;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1;
}

.fb-node-mode + .fb-node-mode {
  margin-left: -1px;
}

.fb-node-mode.is-on {
  border-color: var(--chrome-title);
  background: var(--chrome-title);
  color: var(--chrome);
  font-weight: 600;
}

button.fb-node-mode {
  cursor: pointer;
}

button.fb-node-mode.is-on {
  cursor: default;
}

button.fb-node-mode:not(.is-on):hover {
  background: var(--chrome-hover);
  color: var(--chrome-title);
}

button.fb-node-mode:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.fb-node.is-summary.is-faded .fb-node-header {
  background: var(--chrome);
}

.fb-node.is-summary .fb-node-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  height: 28px;
  padding: 0 10px;
  font-size: 13px;
  line-height: 28px;
}

.fb-node-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-node-scope {
  flex: 0 0 auto;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
}

/* The footer under the parts: the scorecard's notes and tasks, as on every card. */
.fb-node.is-summary .fb-node-foot {
  border-top: 1px solid var(--line-soft);
}

/* Nothing is drawn out of a summary: its ports only receive, and a press on one moves the card. */
.fb-node.is-summary .fb-port {
  cursor: default;
}

/* ------------------------------------------------------------- scorecard parts */
/* The card's lines (the canvas, the phone's Score tab) and the sheet's parts (js/scorecard-view.js). */

.fb-sc {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

/* The card's picture (js/scorecard-card.js, drawn as SVG by js/scorecard-view.js createCard): 294 ×
   248 (the Run mode's 312) under the title line's rule, its colours the tokens (fill-* / stroke-* by the geometry's token
   names), every word in Plex Mono so its widths are the geometry's. */
.fb-sc-card {
  flex: 0 0 auto;
  border-top: 1px solid var(--line-soft);
}

.fb-sc-fig {
  display: block;
  overflow: visible;
}

.fb-sc-card.is-empty .fb-sc-fig {
  display: none;
}

.fb-sc-ft {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  /* Drawn at the size the geometry measured, whatever the canvas's zoom: no hinting, no minimum. */
  text-rendering: geometricPrecision;
}

/* The card's sentence-case labels (the owner's mockup of 2026-10-01): Plex Sans, measured generously. */
.fb-sc-ft.is-sans {
  font-family: var(--font);
  font-variant-numeric: normal;
}

.fb-sc-fig .f-ink { fill: var(--ink); }
.fb-sc-fig .f-ink2 { fill: var(--ink-2); }
.fb-sc-fig .f-muted { fill: var(--muted); }
.fb-sc-fig .f-text2 { fill: var(--text-2); }
.fb-sc-fig .f-line { fill: var(--line); }
.fb-sc-fig .f-lineSoft { fill: var(--line-soft); }
.fb-sc-fig .f-lineUi { fill: var(--line-ui); }
.fb-sc-fig .f-accent { fill: var(--accent); }
.fb-sc-fig .f-ok { fill: var(--ok); }
.fb-sc-fig .f-okArea { fill: var(--ok-area); }
.fb-sc-fig .f-okPale { fill: var(--ok-pale); }
.fb-sc-fig .f-dangerArea { fill: var(--danger-area); }
.fb-sc-fig .f-dangerBand { fill: var(--danger-band); }
.fb-sc-fig .f-warn { fill: var(--warn); }
.fb-sc-fig .f-danger { fill: var(--danger); }
.fb-sc-fig .f-surface { fill: var(--surface); }
.fb-sc-fig .f-band { fill: var(--band); }
.fb-sc-fig .s-ink { stroke: var(--ink); }
.fb-sc-fig .s-ink2 { stroke: var(--ink-2); }
.fb-sc-fig .s-text2 { stroke: var(--text-2); }
.fb-sc-fig .s-line { stroke: var(--line); }
.fb-sc-fig .s-lineSoft { stroke: var(--line-soft); }
.fb-sc-fig .s-lineUi { stroke: var(--line-ui); }
.fb-sc-fig .s-surface { stroke: var(--surface); }
.fb-sc-fig .s-danger { stroke: var(--danger); }
.fb-sc-fig .s-ok { stroke: var(--ok); }
.fb-sc-fig .s-muted { stroke: var(--muted); }
.fb-sc-fig .s-accent { stroke: var(--accent); }

.fb-sc-say {
  margin: 0;
  color: var(--ink);
  font-size: 11.5px;
  line-height: 15px;
}

.fb-sc-emptyline {
  padding: 10px;
}

.fb-sc-emptyline[hidden] {
  display: none;
}

/* The picture on the phone's Score tab: the card's own drawing at the width of the tab, in a
   --surface box inside the 16px gutter. */
.fb-sc-card.is-sheet {
  border: 1px solid var(--line-soft);
  background: var(--surface);
}

.fb-sc-card.is-sheet .fb-sc-fig {
  width: 100%;
  height: auto;
}

/* Load by month, in Details: the meter and the average week under it. */
.fb-sc-load {
  flex: 0 0 auto;
}

.fb-sc-meter {
  margin-top: 5px;
}

.fb-sc-meter .fb-segmeter__track {
  position: relative;
}

.fb-sc-meter .fb-segmeter__seg {
  height: 8px;
}

.fb-sc-foot {
  margin-top: 4px;
  overflow: hidden;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  line-height: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The load's foot takes a second line rather than cut the busy month's words. */
.fb-sc-load .fb-sc-foot {
  white-space: normal;
}

/* The sheet's lists (js/scorecard-view.js): a lever a row — a button that selects its input — and
   the test plan's rows. Square, like everything. */

.fb-sc-lvlist {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-sc-levers-more[hidden],
.fb-sc-lvitem[hidden],
.fb-sc-empty[hidden] {
  display: none;
}

.fb-sc-lever {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  margin: 0;
  padding: 4px 4px 5px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.fb-sc-lever:hover {
  background: var(--hover);
}

.fb-sc-lever:focus-visible {
  outline: none;
  background: var(--hover);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-sc-empty {
  margin: 6px 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

/* The test plan (js/scorecard-view.js createPlan; docs/DESIGN.md §7.5, the owner's mockups "3a" and
   "3b" of 2026-10-02): a schedule of checks. The answer large on top (how long and how much until the
   last step is decided) — or, once a step has failed, the decision box in its place —, then a vertical
   timeline, a step a link in the order they are decided: a dot on the line, the time and the ads
   (cumulative from launch) in mono, the link and its rate, the rule in --ok / --danger, where it
   stands, and the two small fields "came" and "went on" — spin buttons, each with a − and a + beside
   it. The END OF TEST line is dashed. */

.fb-sc-plan[hidden],
.fb-sc-plan [hidden] {
  display: none;
}

.fb-sc-plan__lead {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-plan__big {
  display: flex;
  flex-wrap: wrap;
  gap: 0 18px;
  margin: 2px 0 4px;
  color: var(--ink);
  font-family: var(--font);
  font-size: 26px;
  font-weight: 600;
  line-height: 32px;
  white-space: nowrap;
}

.fb-sc-plan__sub {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-plan__sub strong {
  color: var(--ink);
  font-weight: 600;
}

.fb-sc-steps {
  margin: 10px 0 0;
  padding: 10px 0 0;
  border-top: 1px solid var(--ink);
  list-style: none;
}

.fb-sc-step {
  position: relative;
  padding: 0 0 14px 26px;
}

/* The line the dots stand on: from a step's dot down to the next one. */
.fb-sc-step::before {
  content: '';
  position: absolute;
  top: 15px;
  bottom: -3px;
  left: 6px;
  width: 1px;
  background: var(--line);
}

.fb-sc-step:last-child::before {
  content: none;
}

.fb-sc-step:has(+ .fb-sc-stepend)::before {
  bottom: 4px;
}

.fb-sc-step__dot {
  position: absolute;
  top: 3px;
  left: 1px;
  box-sizing: border-box;
  /* A square mark: nothing in the interface is rounded (§1). */
  width: 11px;
  height: 11px;
  border: 1.5px solid var(--line-ui);
  background: var(--panel);
}

.fb-sc-step.is-over .fb-sc-step__dot {
  border-color: var(--danger);
}

.fb-sc-step[data-state='counting'] .fb-sc-step__dot {
  border-color: var(--accent);
  background: linear-gradient(90deg, var(--accent) 50%, var(--panel) 50%);
}

/* On track: the count reached its line, but is not yet sure enough to be called confirmed. */
.fb-sc-step[data-state='ontrack'] .fb-sc-step__dot {
  border-color: var(--ok);
  background: linear-gradient(90deg, var(--ok) 50%, var(--panel) 50%);
}

.fb-sc-step[data-state='confirmed'] .fb-sc-step__dot {
  border-color: var(--ok);
  background: var(--ok);
}

.fb-sc-step[data-state='failed'] .fb-sc-step__dot {
  border-color: var(--danger);
  background: var(--danger);
}

.fb-sc-step__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  color: var(--ink);
  font-size: var(--fs-sm, 11px);
  font-weight: 600;
  line-height: 16px;
  white-space: nowrap;
}

.fb-sc-step.is-over .fb-sc-step__top,
.fb-sc-step[data-state='failed'] .fb-sc-step__top {
  color: var(--danger);
}

/* The two parts of the time of a link with a wait: the people have come, then they are judged. */
.fb-sc-step__wait {
  margin: 2px 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 15px;
}

.fb-sc-step__wait.is-over {
  color: var(--ink);
}

.fb-sc-step__name {
  margin-top: 3px;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  font-weight: 600;
  line-height: 16px;
  overflow-wrap: anywhere;
}

.fb-sc-step__link {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.fb-sc-step__link:hover {
  text-decoration: underline;
}

.fb-sc-step__link:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.fb-sc-step__rate {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  font-weight: 400;
  white-space: nowrap;
}

.fb-sc-step__rule,
.fb-sc-step__state {
  margin: 3px 0 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-step__rule strong {
  color: var(--ink);
  font-weight: 600;
}

/* "≥ 8 went on — on track" and "≤ 3 — stop" each stay on one line. */
.fb-sc-step__rule .is-ok,
.fb-sc-step__rule .is-bad {
  white-space: nowrap;
}

.fb-sc-step__rule .is-ok,
.fb-sc-step__state.is-ok {
  color: var(--ok);
}

.fb-sc-step__rule .is-bad,
.fb-sc-step__state.is-bad {
  color: var(--danger);
}

.fb-sc-step__state {
  color: var(--ink);
}

/* How sure the count makes us: the one figure of the line, in bold. */
.fb-sc-step__state strong {
  font-weight: 600;
}

.fb-sc-step__count {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 6px;
}

.fb-sc-step__field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.fb-sc-step__label {
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

/* A spin button: − [ field ] +, one frame (the borders between them shared). */
.fb-sc-spin {
  display: flex;
}

button.fb-sc-spin__btn {
  box-sizing: border-box;
  flex: none;
  width: 24px;
  height: 24px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--panel);
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1;
  cursor: pointer;
}

button.fb-sc-spin__btn:hover {
  background: var(--surface);
  border-color: var(--ink);
  position: relative;
}

button.fb-sc-spin__btn:active {
  background: var(--ink);
  color: var(--panel);
}

input.fb-sc-step__input {
  box-sizing: border-box;
  position: relative;
  width: 56px;
  height: 24px;
  margin: 0 -1px;
  padding: 0 6px;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  text-align: right;
}

input.fb-sc-step__input::placeholder {
  color: var(--muted);
}

input.fb-sc-step__input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-sc-step[data-state='failed'] input.fb-sc-step__input,
input.fb-sc-step__input[aria-invalid='true'] {
  border-color: var(--danger);
}

/* A "came" that is the suggestion from the steps before: there, but not yet the owner's number. */
input.fb-sc-step__input.is-suggested {
  color: var(--muted);
}

/* Under "came": where the suggested number comes from, or the way back to it. */
.fb-sc-step__sugg,
.fb-sc-step__hint {
  margin: 3px 0 0;
  color: var(--muted);
  font-size: var(--fs-sm, 11px);
  line-height: 15px;
}

button.fb-sc-step__use {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}

button.fb-sc-step__use:hover {
  color: var(--ink);
}

button.fb-sc-step__use:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.fb-sc-step__read {
  margin: 4px 0 0;
  color: var(--ink);
  font-size: var(--fs-sm, 11px);
  line-height: 16px;
}

.fb-sc-step__error {
  margin: 4px 0 0;
  color: var(--danger);
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

/* While the box says the test can be switched off, the steps after the failed one step back; their
   fields stay as they are. */
.fb-sc-step.is-dim > :not(.fb-sc-step__count):not(.fb-sc-step__error) {
  opacity: 0.5;
}

.fb-sc-stepend {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 12px;
  padding: 6px 0 0 26px;
  border-top: 1px dashed var(--line-ui);
  color: var(--ink);
  font-size: var(--fs-xs, 10px);
  font-weight: 600;
  line-height: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-sc-plan__foot {
  margin: 2px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--line-soft);
  color: var(--text-2);
}

/* What "sure" means: the one line under the note of the columns. */
.fb-sc-plan__footsure {
  margin: 4px 0 0;
  color: var(--text-2);
}

/* The decision box (mockup "3b"): a step failed. --danger when the funnel no longer pays for itself
   with the measured rate ("You can switch the test off"), --warn when it still does. */
.fb-sc-verdict {
  margin: 0;
  padding: 10px 12px 12px;
  border: 1px solid var(--danger);
  background: var(--danger-tint);
}

.fb-sc-verdict.is-pays {
  border-color: var(--warn);
  background: transparent;
}

.fb-sc-verdict__title {
  margin: 0 0 4px;
  color: var(--danger);
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 20px;
}

.fb-sc-verdict.is-pays .fb-sc-verdict__title {
  color: var(--warn);
}

.fb-sc-verdict__text {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 17px;
}

.fb-sc-verdict__money {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 12px;
  margin: 8px 0 0;
  color: var(--ink);
  font-size: var(--fs-sm, 11px);
  line-height: 16px;
}

.fb-sc-verdict__money strong {
  font-weight: 600;
}

.fb-sc-verdict__saved {
  color: var(--ok);
}

.fb-sc-verdict__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* "What should I do?" in the sheet (js/scorecard-view.js createAdvice; docs/DESIGN.md §7.5, the
   owner's mockups "1a" and "1d" of 2026-10-02): the mode's number now, large; SUGGESTED SCENARIO — its
   line, its changes, its result, Create scenario from this — while the goal does not hold; then
   BIGGEST LEVERS, best first, no groups: a row is a lever button with the result large in --ok at the
   left ("97" over "of 100") and at the right the lever as a plain action in bold over its exact change
   in mono — a lever is only ever shown in the direction that helps. The Run mode's How far you can
   scale is a plain line. */
.fb-sc-advice[hidden],
.fb-sc-scale[hidden] {
  display: none;
}

.fb-sc-scale {
  margin: 8px 0 4px;
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-head__line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 8px;
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.35;
}

.fb-sc-head__big {
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  font-size: 26px;
  font-weight: 600;
  line-height: 32px;
  white-space: nowrap;
}

.fb-sc-head__line + .fb-sc-head__line .fb-sc-head__big {
  font-size: 18px;
  line-height: 24px;
}

.fb-sc-head__big.is-ok {
  color: var(--ok);
}

.fb-sc-head__big.is-bad {
  color: var(--danger);
}

.fb-sc-head__sub {
  margin: 2px 0 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-advice.is-stale .fb-sc-adv {
  opacity: 0.45;
}

.fb-sc-head + .fb-sc-adv,
.fb-sc-adv + .fb-sc-adv {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}

.fb-sc-adv__head {
  margin: 0 0 4px;
  color: var(--text-2);
}

.fb-sc-adv__lead {
  margin: 0 0 6px;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
}

.fb-sc-adv__result {
  margin: 6px 4px 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  font-weight: 600;
  line-height: 16px;
}

.fb-sc-adv__result.is-ok {
  color: var(--ok);
}

.fb-sc-adv__result.is-bad {
  color: var(--danger);
}

.fb-sc-adv__create {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}

.fb-sc-adv__limits {
  margin: 8px 0 0;
}

/* The levers: one grid, so every result is as wide as the widest and the actions start on one line. */
.fb-sc-levers {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  column-gap: 14px;
  border-top: 1px solid var(--ink);
}

.fb-sc-levers > .fb-sc-lvitem,
.fb-sc-arow.has-result {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
}

.fb-sc-arow {
  gap: 2px;
  padding: 7px 4px 8px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-sc-arow.has-result {
  align-items: start;
  gap: 0 14px;
}

.fb-sc-arow__result {
  display: flex;
  flex-direction: column;
  min-width: 44px;
}

.fb-sc-arow__value {
  color: var(--ok);
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  font-size: 20px;
  font-weight: 600;
  line-height: 22px;
  white-space: nowrap;
}

.fb-sc-arow__unit {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 14px;
  white-space: nowrap;
}

.fb-sc-arow__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.fb-sc-arow__action {
  font-size: var(--fs-md, 12px);
  font-weight: 600;
  line-height: 16px;
  overflow-wrap: anywhere;
}

.fb-sc-arow__change {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 15px;
  overflow-wrap: anywhere;
}

.fb-sc-adv__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 8px;
}

.fb-sc-adv__foot .fb-hint {
  margin: 0;
}

.fb-sc-levers-more {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* The scorecard in the property sheet: the parts set in the sheet's sections, whose heads name them. */
.fb-sc-part.is-sheet {
  padding: 0;
  margin: 0;
}

.fb-sc-compare {
  width: 100%;
  table-layout: fixed;
  border: 1px solid var(--line-soft);
  font-size: var(--fs-sm, 11.5px);
}

.fb-sc-compare[hidden],
.fb-sc-compare-failed[hidden],
/* Format 12: the scorecard's mode at the top of its Summary tab, in the sheet's side gutter. */
.fb-sc-mode {
  padding: 8px 10px 2px;
}

/* Format 13: the scorecard's own test duration and profit target under its mode, in the same gutter. */
.fb-sc-term {
  padding: 2px 10px;
}

.fb-sc-term + .fb-sc-card {
  margin-top: 6px;
}

.fb-sc-compare th,
.fb-sc-compare td {
  height: 24px;
  padding: 0 6px;
  border-top: 1px solid var(--line-soft);
  overflow: hidden;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-sc-compare thead th {
  height: auto;
  padding: 4px;
  border-top: 0;
  background: var(--band);
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
  line-height: 1.25;
  vertical-align: bottom;
  /* The heads are the two scenarios' names (§7.3): a long one takes a second line, then ends in an
     ellipsis, its whole name in the tooltip. */
  display: table-cell;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* The difference's head is one word, never broken: its column is as wide as that word in the page's
   language — its letters (js/ui.js sets --fb-sc-diff-ch; the head is monospaced, so a letter is 1ch)
   and the cell's padding, with 2px to spare — and so a little wider than the names'. Not a share of
   the table: on a 1366 px laptop 24% of the sheet's table was narrower than *Difference* (review
   round 3, finding 8), and a percentage inside max() or calc() is no width to a fixed table's cell. */
.fb-sc-compare thead th.is-diff {
  width: calc(var(--fb-sc-diff-ch, 10) * 1ch + 10px);
  overflow-wrap: normal;
}

.fb-sc-compare thead th > span {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.fb-sc-compare tbody th {
  color: var(--text-2);
  font-weight: 400;
  text-align: left;
}

.fb-sc-compare thead td {
  width: 32%;
  background: var(--band);
}

.fb-sc-compare .num {
  padding: 0 4px;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-variant-numeric: tabular-nums;
}

.fb-sc-diff.is-ok {
  color: var(--ok);
}

.fb-sc-diff.is-bad {
  color: var(--danger);
}

.fb-sc-compare-failed {
  margin: 0;
  color: var(--danger);
}

/* ------------------------------------------------------------- checklist card */

.fb-todo {
  margin: 0;
  padding: 3px 6px 5px 7px;
  list-style: none;
}

/* The card is never empty-looking: an untouched checklist says so itself, in the page's language
   (canvas.js sets data-empty from the catalogue). */
.fb-todo:empty::before {
  content: attr(data-empty);
  display: block;
  padding: 2px 2px 3px;
  color: var(--muted);
}

.fb-todo-row {
  display: flex;
}

/* The whole row is the target — WCAG 2.2 2.5.8 wants 24x24 and a task is one line
   of text, so the row carries the height and the box sits inside it. */
.fb-todo-check {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  width: 100%;
  min-height: 24px;
  padding: 3px 2px;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  line-height: 16px;
  text-align: left;
  cursor: pointer;
}

.fb-todo-check::before {
  content: '';
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-top: 2px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

/* Done is a filled box, not a drawn tick: at 12px a glyph lands differently in every
   font, and the struck-through text says the rest. */
.fb-todo-row.is-done .fb-todo-check::before {
  border-color: var(--ink);
  background: var(--ink);
}

.fb-todo-check:hover::before {
  border-color: var(--text-2);
}

.fb-todo-text {
  min-width: 0;
  overflow-wrap: anywhere;
}

.fb-todo-row.is-done .fb-todo-text {
  color: var(--muted);
  text-decoration: line-through;
}

/* The tick button in the inspector: same box, drawn by the same two rules. */
.fb-todo-toggle {
  flex: 0 0 auto;
}

.fb-todo-toggle::before {
  content: '';
  width: 12px;
  height: 12px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-todo-toggle[aria-checked='true']::before {
  border-color: var(--ink);
  background: var(--ink);
}

/* ------------------------------------------------------- node colour tags */

/* The colour of the 3px tag bar (§2.4), from the --tag-* palette on :root, which owns the dark
   values too. The tint is the tag's 9×9 swatch wash elsewhere; the card's header stays --band, as
   in the design. `data-color="none"` sets neither. */

.fb-node[data-color='gray'] {
  --fb-node-bar: var(--tag-gray);
  --fb-node-tint: var(--tag-gray-tint);
}

.fb-node[data-color='blue'] {
  --fb-node-bar: var(--tag-blue);
  --fb-node-tint: var(--tag-blue-tint);
}

.fb-node[data-color='green'] {
  --fb-node-bar: var(--tag-green);
  --fb-node-tint: var(--tag-green-tint);
}

.fb-node[data-color='amber'] {
  --fb-node-bar: var(--tag-amber);
  --fb-node-tint: var(--tag-amber-tint);
}

.fb-node[data-color='red'] {
  --fb-node-bar: var(--tag-red);
  --fb-node-tint: var(--tag-red-tint);
}

.fb-node[data-color='purple'] {
  --fb-node-bar: var(--tag-purple);
  --fb-node-tint: var(--tag-purple-tint);
}

.fb-node[data-color='teal'] {
  --fb-node-bar: var(--tag-teal);
  --fb-node-tint: var(--tag-teal-tint);
}

/* WCAG 2.2 2.5.8 wants 24x24; the design wants a 7px square. So the button is the
   24x24 target — transparent, no border of its own — and ::before paints the 7px
   square the spec asks for, straddling the card edge exactly where it used to sit.
   The target is not centred on that square: it hangs outward, overlapping the card
   by 5px, so the drag handle of the card keeps its area. Centring it would push
   12px of "start a connection" into the header, right where the card is grabbed.
   Nothing in js/routing.js reads the element: an edge anchor is
   anchorPoint(nodeRect(node), side), pure geometry off the card rect, so the routes
   cannot move. */
.fb-port {
  position: absolute;
  z-index: 4;
  width: 24px;
  height: 24px;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: transparent;
  cursor: crosshair;
  appearance: none;
}

.fb-port::before {
  content: '';
  position: absolute;
  width: 7px;
  height: 7px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-port-in,
.fb-port-left {
  top: 50%;
  left: -19px;
  margin-top: -12px;
}

.fb-port-in::before,
.fb-port-left::before {
  top: 50%;
  left: 15.5px;
  margin-top: -3.5px;
}

.fb-port-out,
.fb-port-right {
  top: 50%;
  right: -19px;
  margin-top: -12px;
}

.fb-port-out::before,
.fb-port-right::before {
  top: 50%;
  right: 15.5px;
  margin-top: -3.5px;
}

.fb-port-top {
  top: -19px;
  left: 50%;
  margin-left: -12px;
}

.fb-port-top::before {
  top: 15.5px;
  left: 50%;
  margin-left: -3.5px;
}

.fb-port-bottom {
  top: auto;
  bottom: -19px;
  left: 50%;
  margin-left: -12px;
}

.fb-port-bottom::before {
  bottom: 15.5px;
  left: 50%;
  margin-left: -3.5px;
}

/* The handles of a selected card are drawn in the accent (§4.4). */
.fb-node.is-selected .fb-port::before {
  border-color: var(--accent);
}

.fb-port:hover::before,
.fb-port:focus-visible::before,
.fb-port.is-active::before,
.fb-node.is-valid-target .fb-port::before {
  border-color: var(--accent);
  background: var(--accent);
}

/* The default ring would trace the invisible 24px target. Draw it around the 7px
   square instead, so the focused port looks exactly as it did before. */
.fb-port:focus-visible {
  outline: none;
}

.fb-port:focus-visible::before {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* The canvas hint sits at the top: the bottom corners hold the zoom control and the title block. */
.fb-canvas-hint {
  position: absolute;
  z-index: 5;
  /* Under the canvas banner while one shows (a version's bar is two lines in Russian). */
  top: calc(10px + var(--fb-banner-h, 0px));
  left: 50%;
  max-width: calc(100% - 64px);
  margin: 0;
  padding: 4px 8px;
  transform: translateX(-50%);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font-size: var(--fs-md, 12px);
  pointer-events: none;
}

/* ------------------------------------------------------------------ paper */

/* The paper around the drawing (docs/DESIGN.md §4.4): fixed to the viewport, above the world. */
.fb-canvas {
  container-type: size;
  container-name: paper;
}

.fb-paper {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
}

/* The title block (§4.4): a ruled table in the lower right, the micro-label over its value — only
   while View ▸ Title block is on (the shell's `is-titleblock` on the canvas); off by default. */
.fb-titleblock {
  position: absolute;
  right: 10px;
  bottom: 10px;
  display: none;
  grid-template-columns: 92px minmax(0, 1fr) 136px;
  grid-template-rows: auto auto;
  /* As wide as the funnel's name needs (at least 380px, at most the paper): PROJECT says it in
     full, on two lines where even that is too narrow. */
  width: max-content;
  min-width: 380px;
  max-width: calc(100% - 20px);
  border: 1px solid var(--ink);
  background: var(--surface);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.05em;
}

.fb-canvas.is-titleblock .fb-titleblock {
  display: grid;
}

.fb-tb-brand {
  display: flex;
  grid-row: span 2;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 6px 8px;
  border-right: 1px solid var(--ink);
}

.fb-tb-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  padding: 5px 7px;
  border-right: 1px solid var(--line);
  text-transform: uppercase;
}

.fb-tb-project,
.fb-tb-by {
  border-bottom: 1px solid var(--line);
}

.fb-tb-by,
.fb-tb-saved {
  border-right: none;
}

.fb-tb-v {
  overflow: hidden;
  color: var(--ink);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  letter-spacing: 0;
  text-overflow: ellipsis;
  text-transform: none;
  white-space: nowrap;
}

/* A funnel's name, a scenario's and a person's are words: the sans face (SAVED stays mono). */
.fb-tb-project .fb-tb-v,
.fb-tb-by .fb-tb-v,
.fb-tb-scenario .fb-tb-v {
  font-family: var(--font);
}

.fb-tb-project .fb-tb-v {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Placed, not flowed: PROJECT over SCENARIO, BY over SAVED; a hidden BY must not pull SCENARIO up
   into its slot. */
.fb-tb-project { grid-area: 1 / 2; }
.fb-tb-by { grid-area: 1 / 3; }
.fb-tb-scenario { grid-area: 2 / 2; }
.fb-tb-saved { grid-area: 2 / 3; }

/* Nobody known, no BY: SAVED has the right column alone, in its middle — never a label over a dash
   (§4.4). */
.fb-tb-cell[hidden] {
  display: none;
}

.fb-titleblock.is-unsigned .fb-tb-saved {
  grid-row: 1 / span 2;
  grid-column: 3;
  justify-content: center;
}

/* No save yet: BY has the right column alone, as SAVED has it with nobody known. */
.fb-titleblock.is-unsaved .fb-tb-by {
  grid-row: 1 / span 2;
  justify-content: center;
  border-bottom: none;
}

/* Neither BY nor SAVED (a share link's viewer): PROJECT over SCENARIO, the whole width. */
.fb-titleblock.is-bare {
  grid-template-columns: 92px minmax(0, 1fr);
}

.fb-titleblock.is-bare .fb-tb-project,
.fb-titleblock.is-bare .fb-tb-scenario {
  border-right: none;
}

/* Link to… (a card's context menu): what to click, over the top of the paper, in the accent (the
   active state), a refused click in --danger; Esc or Cancel ends it. The phone has its own banner. */
.fb-linkprompt {
  position: absolute;
  z-index: 8;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100% - 64px);
  min-height: 30px;
  padding: 3px 3px 3px 10px;
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--ink);
  font: 400 var(--fs-md, 12px)/16px var(--font);
}

.fb-linkprompt[hidden] {
  display: none;
}

.fb-linkprompt.is-refused {
  border-color: var(--danger);
}

.fb-linkprompt__text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-linkprompt__key {
  color: var(--text-2);
  font: 500 var(--fs-xs, 10.5px)/16px var(--mono);
}

.fb-linkprompt .fb-linkprompt__cancel {
  min-height: 22px;
  padding: 0 8px;
}

/* While Link to… waits, the cards say they can be clicked, the one it starts from is marked. */
.fb-canvas.is-tap-linking .fb-node,
#canvas.is-tap-linking .fb-node {
  cursor: crosshair;
}

.fb-node.is-link-source {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
}

/* The zoom control: − · the percentage · + · Fit (F), on the paper's lower left. */
.fb-zoomctl {
  position: absolute;
  z-index: 7;
  bottom: 10px;
  left: 10px;
  display: flex;
  align-items: stretch;
}

.fb-zoomctl-step {
  font-family: var(--mono);
  font-size: var(--fs-lg, 14px);
}

.fb-zoomctl .fb-zoomctl-field {
  width: 56px;
  height: var(--control-h-lg);
  margin: 0 -1px;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.fb-zoomctl-fit {
  gap: 5px;
  margin-left: 4px;
}

.fb-zoomctl-key {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 500;
}

/* A narrow canvas keeps its drawing: the title block goes below 700px of width (as in the design). */
@container paper (max-width: 699px) {
  .fb-canvas.is-titleblock .fb-titleblock {
    display: none;
  }
}

.fb-marquee {
  position: absolute;
  z-index: 5;
  border: 1px dashed var(--accent);
  background: var(--select-wash);
  pointer-events: none;
}

/* ---------------------------------------------------------------- summary */

/* The inspector of a summary block. The headline is the average of a month with the months in
   profit: the sum and the count never break inside, and a line too narrow for both wraps between
   them (the spaces between the pieces are no-break: a flex item drops an ordinary leading one). */
.fb-summary-headline {
  display: flex;
  flex-wrap: wrap;
  margin: 0 0 8px;
  /* The text face, not .num: the monospace one is a fifth wider. Figures still keep their width. */
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-md, 13px);
  font-weight: 600;
}

.fb-summary-average,
.fb-summary-profit {
  white-space: nowrap;
}

.fb-summary-mean {
  color: var(--muted);
  font-weight: 400;
  white-space: nowrap;
}

.fb-summary-headline.is-ok .fb-summary-average {
  color: var(--ok);
}

.fb-summary-headline.is-bad .fb-summary-average {
  color: var(--danger);
}

.fb-summary-scope {
  margin: -4px 0 8px;
}

.fb-summary-body {
  margin-top: 10px;
}

.fb-totals {
  border: 1px solid var(--line);
}

.fb-tot-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 8px;
  padding: 2px 7px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-sm, 11px);
}

.fb-tot-row:last-child {
  border-bottom: none;
}

.fb-tot-k {
  color: var(--muted);
  white-space: nowrap;
}

.fb-tot-row .num {
  /* A value that does not fit next to its label (a six-figure year range in a 248 px
     inspector) moves to a line of its own, still at the right, instead of being clipped. */
  margin-left: auto;
  white-space: nowrap;
}

.fb-tot-row .is-strong {
  font-weight: 600;
  font-size: var(--fs-md, 12px);
}

.fb-tot-row .is-ok {
  color: var(--ok);
}

.fb-tot-row .is-bad {
  color: var(--danger);
}

.fb-meter-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 3px;
  font-size: var(--fs-sm, 11px);
}

/* ---------------------------------------------------------- honest summary */

.fb-spread-hint {
  margin: 4px 0 0;
}

.fb-summary-section {
  margin: 12px 0 4px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* "One month" opens the summary: a rule above it would only double the line of the warnings.
   Without a spread the month and year sections are hidden, and ui.js marks the first section
   still on show — "Test", "Economics" or "On average" — as the lead. */
.fb-summary-section:first-child,
.fb-summary-section.is-lead {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* "Test over N mo": the steps under "At least one sale" are block names, typed by the user
   and of any length. The name gives way with an ellipsis and the chance never does, so a
   step keeps to one line even in a 248 px inspector; the row's title carries the whole name. */
.fb-tot-step {
  flex-wrap: nowrap;
  padding-left: 15px;
}

.fb-tot-step .fb-tot-k {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-tot-step .num {
  flex: none;
}

.fb-test {
  margin-bottom: 4px;
}

.fb-year {
  margin-bottom: 4px;
}

.fb-warnings {
  margin: 0 0 10px;
  border: 1px solid var(--warn);
}

.fb-warning {
  padding: 3px 7px;
  border-bottom: 1px solid var(--line);
  color: var(--warn);
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

.fb-warning:last-child {
  border-bottom: none;
}

/* ----------------------------------------------------------------- toasts */

/* §6: bottom-left of the canvas, solid --ink with --on-ink Sans 12px, a 6px status square, the
   hard drop. Above the modal backdrop (300): a route that opens a dialog also explains itself in
   a toast ("that funnel is not in your account"), and a toast under the overlay is unreadable. */
.fb-toast-host {
  position: fixed;
  z-index: 310;
  left: calc(var(--tree-w) + 16px);
  /* Clear of the canvas's zoom control in the lower left (§4.4). */
  bottom: calc(var(--cmdline-h) + 52px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  max-width: calc(100% - var(--tree-w) - var(--sheet-w) - 32px);
  pointer-events: none;
}

/* An open menu (js/menu.js marks the root) is above the toasts: a toast never covers a focused item. */
:root.fb-menu-open .fb-toast-host {
  z-index: 190;
}

.fb-toast {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 440px;
  min-height: 32px;
  padding: 7px 12px;
  background: var(--ink);
  color: var(--on-ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
  box-shadow: var(--shadow);
  pointer-events: auto;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.15s linear;
}

/* The 6px status square — the only mark a toast carries, no icon storms. A plain toast's square
   is a quiet --on-ink; ok and error take the other theme's status colour, which is the one that
   reads on this theme's ink. */
.fb-toast::before {
  content: '';
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background: var(--on-ink);
  opacity: 0.6;
}

.fb-toast.is-ok::before {
  background: var(--on-ink-ok);
  opacity: 1;
}

.fb-toast.is-error::before {
  background: var(--on-ink-danger);
  opacity: 1;
}

.fb-toast.is-leaving {
  opacity: 0;
}

/* ---------------------------------------------------------- loading states */

/* The busy indicator (DESIGN.md §5.3, docs/PLANS.md §9.2, js/busy.js): the segmented meter of
   §5.2 running — four square cells, one lit at a time, one step every 150 ms. Nothing round,
   nothing rotates, no gradient: a plotter, not a spinner. `sm` sits in a button, a row or a toast;
   `md` on a page or in a dialog's body, always with its words. The colours are where it sits: ink
   on a surface, the title white on the menu bar, on-ink on an ink fill. */
.fb-busy {
  --busy-lit: var(--ink);
  --busy-dim: var(--line-mid);
  --busy-cell: 4px;
  --busy-gap: 2px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  vertical-align: middle;
}

.fb-busy.is-md {
  --busy-cell: 6px;
  --busy-gap: 3px;
  gap: 10px;
}

.fb-busy.is-chrome {
  --busy-lit: var(--chrome-title);
  --busy-dim: var(--chrome-line);
}

.fb-busy.is-on-ink {
  --busy-lit: var(--on-ink);
  --busy-dim: var(--on-ink-faint);
}

.fb-busy__cells {
  display: inline-flex;
  flex: 0 0 auto;
  gap: var(--busy-gap);
}

.fb-busy__cell {
  width: var(--busy-cell);
  height: var(--busy-cell);
  background-color: var(--busy-dim);
  animation: fb-busy-step 600ms steps(1, end) infinite;
}

.fb-busy__cell:nth-child(2) {
  animation-delay: 150ms;
}

.fb-busy__cell:nth-child(3) {
  animation-delay: 300ms;
}

.fb-busy__cell:nth-child(4) {
  animation-delay: 450ms;
}

/* Lit for the first quarter of the cycle, then dark: stepped, never eased (§10). */
@keyframes fb-busy-step {
  0% {
    background-color: var(--busy-lit);
  }

  25%,
  100% {
    background-color: var(--busy-dim);
  }
}

.fb-busy__label {
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  color: var(--text-2);
}

/* A button's busy face: the label stays in the layout, hidden, so the button keeps its width; the
   sm indicator stands over it. The button is aria-disabled (it keeps the focus), not disabled. */
.is-busy-face {
  position: relative;
}

.btn.is-busy-face,
.btn.is-busy-face:hover,
button.is-busy-face {
  color: transparent;
  cursor: progress;
}

.is-busy-face > :not(.fb-busy--face) {
  visibility: hidden;
}

.fb-busy--face {
  position: absolute;
  inset: 0;
  justify-content: center;
}

/* Drawn for a wait, hidden (keeping its room) until the wait is 150 ms old: an answer that comes
   sooner shows no indicator and no skeleton at all (§9.4). */
.is-waiting {
  visibility: hidden;
}

/* A read slower than 10 s keeps its skeleton and adds this line under it: the sm indicator and
   *Still loading…* (docs/PLANS.md §9.4). */
.fb-still-loading {
  margin: 8px 0 0;
}

/* A working toast (an export, an auto-layout): the indicator stands where the status square does. */
.fb-toast.is-working::before {
  display: none;
}

/* The determinate meter of a counting toast (Add to account of many funnels): ten cells, the lit
   ones on-ink, the rest faint — the segmented meter of §5.2 on an ink fill. */
.fb-progress {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 2px;
}

.fb-progress__cell {
  width: 4px;
  height: 4px;
  background: var(--on-ink-faint);
}

.fb-progress__cell.is-on {
  background: var(--on-ink);
}

/* The small indicator before a section's Computing… (the scorecard's levers): it keeps to the
   right with its words. */
.fb-section-busy {
  align-self: center;
  margin-left: auto;
}

.fb-section-busy + .fb-section-hint {
  margin-left: -2px;
}

/* The canvas area while its address's funnel is read (a board's address with no copy here, the
   confirmation link's landing): grid paper over the canvas, the md indicator and its words in the
   middle — never the funnel that happened to be open (docs/PLANS.md §9.1 L5, L30). */
.fb-boot-wait {
  position: absolute;
  z-index: 40;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
}

.fb-boot-wait > .fb-busy {
  position: relative;
}

/* Under the words once the read is 10 s old (§9.4), without moving the indicator from the middle. */
.fb-boot-wait > .fb-still-loading {
  position: absolute;
  top: calc(50% + 18px);
  margin: 0;
}

/* An arrival that lands on the Boards page (docs/PLANS.md §9.4): index.html's pre-paint script marks
   it on <html>, and until js/app.js has drawn the page (settleArrival) the paper is all there is —
   the page's own ground, never a frame of the editor's shell that stands in the markup under it.
   The confirmation link's landing waits here for the account: its indicator and words in the middle
   of the paper, without the canvas's grid (L30). The mark goes the moment the editor is the view. */
:root[data-fb-arrival="boards"] body {
  background: var(--surface-2);
}

:root[data-fb-arrival="boards"] .fb-app {
  visibility: hidden;
}

:root[data-fb-arrival="boards"] .fb-boot-wait {
  position: fixed;
  visibility: visible;
  background: var(--surface-2);
}

:root[data-fb-arrival="boards"] .fb-boot-wait > .fb-grid {
  display: none;
}

.fb-app.is-boot-wait > :is(.fb-tree, .fb-inspector) > *,
.fb-app.is-boot-wait .fb-menubar__doc,
.fb-app.is-boot-wait .fb-mhead__doc {
  visibility: hidden;
}

/* The controls of the funnel that happened to be open are out of reach (inert) until the address's
   funnel is in: drawn as disabled, at 40% as a disabled primary is (DESIGN §5.1), so they do not promise
   an Export or an Undo of a funnel nobody sees. Their places do not move. */
.fb-app.is-boot-wait :is(.fb-menubar__menus, .fb-toolstrip, .fb-cmdline, .fb-mhead__end, .fb-mtabs, .fb-mbar)[data-fb-boot-inert] {
  opacity: 0.4;
}

/* A skeleton (§5.3, docs/PLANS.md §9.3): a flat, square block where content will land, of that
   content's size, with a slow opacity pulse. No shimmer: a moving gradient is a gradient (§1.7).
   --hover on a surface; --line-soft on a recessed band (--surface-2 or --band). */
.fb-skel {
  display: block;
  background: var(--hover);
  animation: fb-skel-pulse 1.2s linear infinite alternate;
}

/* The shapes' default sizes weigh nothing (:where), so a place's own size class wins. */
:where(.fb-skel.is-bar) {
  height: 10px;
}

:where(.fb-skel.is-cell) {
  width: 8px;
  height: 8px;
}

/* A button's or a field's outline, empty: the control's boundary in the decorative line. */
.fb-skel.is-box {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
}

.is-recessed .fb-skel,
.fb-skel.is-recessed {
  background: var(--line-soft);
}

/* Words as a skeleton (`text`): the words themselves, unseen, so they take the lines they will take
   in any language, and under each line a bar of that line's length — an underline of the letters'
   height, raised onto them. */
.fb-skel.is-text,
.is-recessed .fb-skel.is-text {
  display: inline;
  background: none;
  color: transparent;
  text-decoration-line: underline;
  text-decoration-color: var(--hover);
  text-decoration-thickness: 0.72em;
  text-decoration-skip-ink: none;
  text-underline-offset: -0.78em;
  user-select: none;
}

.is-recessed .fb-skel.is-text,
.fb-skel.is-text.is-recessed {
  text-decoration-color: var(--line-soft);
}

/* A control as a skeleton (a button, a badge): the control's own element with its words and glyph
   unseen — so it is the control's size in any language and wraps as the control would — drawn as
   .is-box's empty outline. Not focusable (a span) and hidden from assistive technology. */
.fb-skel.is-box:is(.btn, .fb-badge) {
  border-color: transparent;
  background: transparent;
  color: transparent;
  cursor: default;
  transition: none;
  user-select: none;
}

/* Forced colours would paint the unseen words in the system's text colour: they stay unseen, the
   bars and outlines in GrayText. */
@media (forced-colors: active) {
  .fb-skel.is-text,
  .fb-skel.is-box:is(.btn, .fb-badge) {
    forced-color-adjust: none;
    color: transparent;
  }

  .fb-skel.is-text {
    text-decoration-color: GrayText;
  }

  .fb-skel.is-box:is(.btn, .fb-badge) {
    border-color: transparent;
    box-shadow: inset 0 0 0 1px GrayText;
  }
}

@keyframes fb-skel-pulse {
  from {
    opacity: 1;
  }

  to {
    opacity: 0.55;
  }
}

/* Reduced motion (§9.5): the cells stop, all four at half their lit colour, and the words carry
   the wait; a skeleton stops pulsing and stays at full opacity. */
@media (prefers-reduced-motion: reduce) {
  .fb-busy__cell {
    animation: none;
    background-color: var(--busy-lit);
    opacity: 0.5;
  }

  .fb-skel {
    animation: none;
    opacity: 1;
  }
}

/* ----------------------------------------------------------------- modals */

/* §6: ONE modal system (openModal in js/ui.js). The funnel stays visible behind --overlay. */
.fb-modal-backdrop {
  position: fixed;
  z-index: 300;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: var(--overlay);
}

/* The frame: a 1px --ink outline and the one hard offset drop. */
.fb-modal {
  display: flex;
  flex-direction: column;
  width: 420px;
  max-width: calc(100% - 8px);
  max-height: calc(100% - 8px);
  border: 1px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
}

.fb-modal.is-wide {
  width: 640px;
}

/* The header band: 32px of --band with the mono path on the left, ESC and a square × on the
   right. The dialog's title is in the body, at 15px. */
.fb-modal-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 4px 0 12px;
  border-bottom: 1px solid var(--line);
  background: var(--band);
}

.fb-modal-path {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-modal-esc {
  flex: 0 0 auto;
  color: var(--text-2);
  letter-spacing: 0.02em;
}

.fb-modal-close {
  width: 24px;
  min-width: 24px;
  min-height: 24px;
  border-color: transparent;
  background: transparent;
  font-size: var(--fs-lg, 15px);
}

.fb-modal-close:hover {
  border-color: var(--line-ui);
  background: var(--surface);
}

.fb-modal-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 20px 20px 18px;
  overflow-y: auto;
  color: var(--ink);
}

.fb-modal-title {
  margin-bottom: 14px;
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* Dialog copy: --ink-2 at 12.5px. */
.fb-modal-body p {
  color: var(--ink-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.5;
}

/* The Boards page's confirm says a second thing on a line of its own (a shared board's link). */
.fb-lib-confirm .fb-modal-body p + p {
  margin-top: 8px;
}

.fb-modal-body p.fb-hint,
.fb-modal-body p.muted,
.fb-modal-body p.fb-muted {
  color: var(--muted);
  font-size: var(--fs-sm, 11.5px);
}

/* Controls in a dialog are 26px. */
.fb-modal-body :is(input:not([type="checkbox"]):not([type="radio"]), select) {
  min-height: var(--control-h-lg);
}

/* A field in a dialog (rename funnel, rename scenario, a label, the initials): the label directly
   above a full-width control, both on the title's left edge (the body's padding) — never the
   property sheet's two columns, which left the label and the input in the right one under an
   empty 92px cell (owner's review). Fields one after another are 12px apart. */
.fb-modal-body .field {
  display: block;
}

.fb-modal-body .field + .field {
  margin-top: 12px;
}

/* The footer: mono meta on the left, the actions on the right. */
.fb-modal-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 20px;
  border-top: 1px solid var(--line-soft);
  background: var(--surface);
}

.fb-modal-foot:empty {
  display: none;
}

.fb-modal-meta {
  margin-inline-end: auto;
}

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

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

/* ------------------------------------------------------------ toolbar icons */

/* The one icon family (DESIGN.md §3.2, js/icons.js): 12-unit line glyphs, square ends, mitred
   joins, in currentColor. The stroke weight is each glyph's own attribute (1.3; 1.4 for undo and
   redo), so no rule here sets one; a glyph drawn large on the phone thins it to keep the rendered
   line near 1.5px. */
.fb-ico {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

.fb-ico.is-filled {
  fill: currentColor;
  stroke: none;
}

.btn-icon .fb-ico {
  width: 12px;
  height: 12px;
}

/* Undo and redo keep the design's 16-unit glyphs at 14px. */
.btn-icon .fb-ico[data-icon='undo'],
.btn-icon .fb-ico[data-icon='redo'] {
  width: 14px;
  height: 14px;
}

/* ---------------------------------------------------------------- accounts */
/* The account and board screens are ordinary editor chrome, not a separate product. They reuse
   the toolbar's .btn, the dialog's frame and the global control styling above: a text input
   inside the dialog is styled by the same `input[type="text"]` rule the inspector uses (and the
   email and password fields by the same rule), so
   there is nothing here to keep in step with it.

   The design language, for anything added below, is docs/DESIGN.md: square corners
   (border-radius: 0 everywhere, deliberately), --line-ui for a control boundary, 12px text, and
   the INSET focus ring (an accent border plus an inset accent shadow). */

.fb-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.fb-form-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Matches the inspector's own field label: same size, same colour, same restraint. */
.fb-form-label {
  font-size: var(--fs-sm, 11px);
  color: var(--text-2);
}

.fb-form-status {
  margin: 0;
  min-height: 1.2em;
  font-size: var(--fs-md, 12px);
  color: var(--muted);
}

.fb-form-status.is-error {
  color: var(--danger);
}

.fb-form-status.is-ok {
  color: var(--ok);
}

.fb-form-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-block-start: 6px;
}

.fb-muted {
  margin: 0;
  font-size: var(--fs-md, 12px);
  color: var(--muted);
}

.fb-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------ account dialogs (§8) */
/* One dialog whose view changes (js/screens/auth.js). The pieces follow FunnelCAD Auth
   Flows.dc.html: 14px between blocks, a two-up row of 32px buttons, a bottom line under a
   --line-soft rule, the password's SHOW toggle inside the field's boundary. */

.fb-auth {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.fb-auth .fb-form {
  gap: 12px;
}

.fb-modal-body .fb-auth-lead {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.5;
}

/* What an account adds: "+" rows between --line-soft rules. */
.fb-auth-benefits {
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line-soft);
  list-style: none;
}

.fb-auth-benefits li {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: 6px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.5;
}

.fb-auth-plus {
  font: 500 var(--fs-md, 12px)/1.5 var(--mono);
}

/* Two actions side by side (Create account · Sign in; Back to sign in · Resend) and the
   provider buttons: 32px, full cell width. */
.fb-auth-pair,
.fb-auth-providers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 8px;
}

.fb-auth-pair > .btn,
.fb-auth-providers > .btn {
  width: 100%;
  min-height: 32px;
  font-weight: 500;
}

.fb-auth-provider {
  gap: 7px;
  font-size: var(--fs-md, 12.5px);
}

.fb-auth-g {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 1px solid currentColor;
  font: 600 var(--fs-xs, 9.5px)/1 var(--mono);
}

/* The last line of a view: a link on the left, a mono note on the right. */
.fb-auth-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
}

.fb-auth-foot.is-start {
  justify-content: flex-start;
  gap: 4px;
}

.fb-auth-foot .btn-link {
  font-size: var(--fs-md, 12.5px);
}

.fb-auth .btn-block {
  min-height: 34px;
  font-weight: 500;
}

/* The field label with an action on its right: Password · Forgot your password? The action
   follows the field in the DOM (and the tab order) and is drawn in the label's row. */
.fb-form-row.has-aside {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: 8px;
  row-gap: 3px;
}

.fb-form-row.has-aside > .fb-form-label {
  grid-row: 1;
  grid-column: 1;
}

.fb-form-row.has-aside > .fb-form-aside {
  grid-row: 1;
  grid-column: 2;
  font-size: var(--fs-sm, 11.5px);
}

.fb-form-row.has-aside > .fb-input {
  grid-row: 2;
  grid-column: 1 / -1;
}

/* The next step after a wrong password: the link in the accent (an active state). */
.btn-link.is-next {
  color: var(--accent);
  font-weight: 500;
}

/* Name and Email side by side on the sign-up form. */
.fb-form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  gap: 8px;
}

/* A text field inside .fb-input (the password with its toggle): left-aligned, dialog height. */
.fb-input.is-text {
  min-height: var(--control-h-lg);
}

.fb-input.is-text > input {
  min-height: calc(var(--control-h-lg) - 2px);
  text-align: left;
}

.fb-input.is-text > input[type="password"] {
  font-family: var(--mono);
  letter-spacing: 0.1em;
}

/* SHOW / HIDE: a mono micro-label inside the boundary, like a unit box. */
.fb-reveal {
  flex: 0 0 auto;
  margin: 0;
  padding: 0 8px;
  border: 0;
  border-left: 1px solid var(--line-soft);
  border-radius: 0;
  background: var(--surface-2);
  color: var(--text-2);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.fb-reveal:hover {
  color: var(--ink);
}

.fb-reveal:focus-visible {
  outline: none;
  color: var(--ink);
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* The meter sits right under its field. */
.fb-form-row > .fb-segmeter {
  margin-top: 3px;
}

/* One field's own error, said under it in --danger (Repeat password: the passwords do not match). */
.fb-field-error,
.fb-modal-body p.fb-field-error {
  margin: 3px 0 0;
  color: var(--danger);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.35;
}

.fb-field-error[hidden] {
  display: none;
}

/* The envelope of "Check your email": a 40px square in a 1.5px ink rule. */
.fb-auth-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1.5px solid var(--ink);
  color: var(--ink);
}

.fb-modal-body > .fb-auth-icon {
  margin-bottom: 14px;
}

.fb-auth-icon .fb-ico {
  width: 20px;
  height: 20px;
  /* 12-unit glyph at 20px: about 1.3px drawn, as the family is at 12px. */
  stroke-width: 0.8;
}

/* The code from the mail (docs/COMMENTS.md §32.8): one mono field, the digits large enough to check
   at a glance; 16px on a phone (below it the page would zoom). */
.fb-auth input.fb-auth-code {
  height: 44px;
  font: 500 26px/1 var(--mono);
  letter-spacing: 0.12em;
}

/* Text that holds whole addresses: they break anywhere rather than widen the dialog. */
.fb-auth .is-addresses {
  overflow-wrap: anywhere;
}

/* The account question (docs/COMMENTS.md §32.9): the two answers stacked at every width, full width,
   the primary first with the note under it. Side by side, the Russian Continue (auth.other.continue)
   did not fit half of the 420px dialog and was clipped at both ends (found by eye in R7). */
.fb-auth-stack {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.fb-auth-stack > .btn {
  width: 100%;
  min-height: 32px;
  font-weight: 500;
}

.fb-modal-body .fb-auth-note {
  margin: -2px 0 2px;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

/* The address a mail went to, recessed, with Change on its right. */
.fb-auth-address {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid var(--line-soft);
  background: var(--surface-2);
  color: var(--ink);
  font: 500 var(--fs-md, 12px)/1.3 var(--mono);
}

.fb-auth-address__text {
  min-width: 0;
  overflow-wrap: anywhere;
}

.fb-auth-address .btn-link {
  flex: 0 0 auto;
}

.fb-modal-body .fb-auth p.fb-hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
}

.fb-auth .fb-form-status:empty {
  display: none;
}

@media (max-width: 479.98px) {
  .fb-form-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------------------------------------------------- the Boards page (§13) */
/* js/screens/library.js, after the owner's concept docs/design/FunnelCAD Boards.dc.html: a page
   over the editor (which stays mounted, inert) — the 28px menu bar, the 40px tool strip, a 208px
   sidebar beside the cards; no status bar, as on the canvas (§1). Every colour is a token. */

/* The canvas's own way back: the "Boards" crumb after the menus. */
.fb-menubar__crumb:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--chrome-title);
}

.fb-menubar__rule {
  flex: 0 0 auto;
  width: 1px;
  height: 14px;
  background: var(--chrome-line);
}

.fb-menubar__crumb {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 3px;
  height: 20px;
  padding: 0 6px 0 3px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--chrome-title);
  font: inherit;
  cursor: pointer;
}

.fb-menubar__crumb .fb-ico {
  width: 12px;
  height: 12px;
  color: var(--chrome-muted);
}

.fb-menubar__crumb:hover {
  background: var(--chrome-hover);
  color: var(--chrome-title);
}

.fb-lib {
  --lib-tag: transparent;
  /* The concept's sidebar, as wide as the editor's model tree (240px since 2026-09-28) at every
     width (the editor's --tree-w folds away below 1120px). */
  --lib-side: 240px;
  position: fixed;
  z-index: 150;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--menubar-h) var(--strip-h) minmax(0, 1fr);
  min-width: 760px;
  background: var(--surface-2);
  color: var(--ink);
  font-size: var(--fs-md, 13px);
}

.fb-lib[hidden] {
  display: none;
}

.fb-lib__spacer {
  flex: 1 1 auto;
}

.fb-lib .fb-kbd {
  font: 500 var(--fs-xs, 10px)/1 var(--mono);
  opacity: 0.75;
}

/* Tags: the label's colour on its square, the block's on the thumbnail's bar — and on the
   phone's Folders menu, which hangs outside the page. */
.fb-lib .is-tag-gray, .fb-menu .is-tag-gray { --lib-tag: var(--tag-gray); }
.fb-lib .is-tag-blue, .fb-menu .is-tag-blue { --lib-tag: var(--tag-blue); }
.fb-lib .is-tag-green, .fb-menu .is-tag-green { --lib-tag: var(--tag-green); }
.fb-lib .is-tag-amber, .fb-menu .is-tag-amber { --lib-tag: var(--tag-amber); }
.fb-lib .is-tag-red, .fb-menu .is-tag-red { --lib-tag: var(--tag-red); }
.fb-lib .is-tag-purple, .fb-menu .is-tag-purple { --lib-tag: var(--tag-purple); }
.fb-lib .is-tag-teal, .fb-menu .is-tag-teal { --lib-tag: var(--tag-teal); }

/* The menu bar: the canvas's own (brand, menus, rule, the save indicator, Sign in or the account),
   with the "Boards" crumb in white. Not in the editor's grid: its area name means nothing here. */
.fb-lib__bar {
  grid-area: auto;
}

.fb-lib__crumb {
  flex: 0 0 auto;
  color: var(--chrome-title);
}

/* The page's save indicator is the canvas's (.fb-save, §4.1), right after the crumb. */
.fb-lib__sync {
  margin-left: 6px;
}

.fb-lib__sync[hidden] {
  display: none;
}

/* The tool strip: --panel, the controls white; New funnel is the one solid ink button. */
.fb-lib__strip {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 0 10px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.fb-lib__strip .btn {
  flex: 0 0 auto;
  gap: 7px;
}

.fb-lib__strip .btn .fb-ico {
  width: 12px;
  height: 12px;
}

.fb-lib__strip .btn .fb-kbd {
  margin-inline-start: 0;
  padding-inline-start: 0;
}

.fb-lib__divider {
  flex: 0 0 auto;
  width: 1px;
  height: 22px;
  margin: 0 2px;
  background: var(--line-mid);
}

.fb-lib__filter {
  display: flex;
  flex: 0 1 260px;
  align-items: center;
  gap: 6px;
  min-width: 120px;
  height: var(--control-h-lg);
  padding: 0 8px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
  color: var(--muted);
  cursor: text;
}

.fb-lib__filter:focus-within {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-lib__filter .fb-ico {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
}

.fb-lib__filter > .fb-lib__filter-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-md, 12.5px)/1 var(--font);
  appearance: none;
}

/* The ring is the field's box (focus-within above), as a unit field's is. */
.fb-lib__filter > .fb-lib__filter-input:focus {
  border: 0;
  box-shadow: none;
}

.fb-lib__filter-input::-webkit-search-cancel-button {
  display: none;
}

.fb-lib__sort-label {
  flex: 0 0 auto;
  font-size: var(--fs-xs, 9.5px);
}

.fb-lib__seg {
  flex: 0 0 auto;
}

.fb-lib__seg > button {
  padding: 0 9px;
  font: 500 var(--fs-sm, 11px)/1 var(--mono);
  text-transform: uppercase;
}

.fb-lib__views {
  margin-left: 6px;
}

.fb-lib__views > button {
  justify-content: center;
  width: 28px;
  padding: 0;
}

.fb-lib__views .fb-ico {
  width: 12px;
  height: 12px;
}

/* The body: the sidebar and the paper of cards. */
.fb-lib__body {
  display: grid;
  grid-template-columns: var(--lib-side) minmax(0, 1fr);
  min-height: 0;
}

.fb-lib__side {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: auto;
  border-right: 1px solid var(--line);
  background: var(--panel);
}

.fb-lib__side-head {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  height: 30px;
  padding: 0 12px;
  border-bottom: 1px solid var(--line-mid);
}

.fb-lib__side-head .fb-micro {
  color: var(--text-2);
  font-size: var(--fs-xs, 9.5px);
  font-weight: 600;
}

.fb-lib__side-head + .fb-lib__folders,
.fb-lib__labels {
  padding: 4px 0;
}

.fb-lib__folders + .fb-lib__side-head {
  margin-top: 6px;
  border-top: 1px solid var(--line-mid);
}

.fb-lib__side-head[hidden],
.fb-lib__labels[hidden],
.fb-lib__quota[hidden] {
  display: none;
}

.fb-lib__add-label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}

.fb-lib__add-label:hover {
  color: var(--ink);
}

.fb-lib__add-label:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-lib__add-label .fb-ico {
  width: 10px;
  height: 10px;
}

.fb-lib__folder {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 28px;
  margin: 0;
  padding: 0 12px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-md, 12.5px)/1 var(--font);
  text-align: start;
  cursor: pointer;
}

.fb-lib__folder:hover {
  background: var(--hover);
}

.fb-lib__folder:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* The folder shown: white, an inset 2px ink bar, --line-mid above and below, 600. */
.fb-lib__folder.is-active {
  background: var(--surface);
  box-shadow: inset 2px 0 0 var(--ink), inset 0 1px 0 var(--line-mid), inset 0 -1px 0 var(--line-mid);
  font-weight: 600;
}

.fb-lib__folder.is-active:focus-visible {
  box-shadow: inset 2px 0 0 var(--ink), inset 0 0 0 1px var(--accent);
}

.fb-lib__folder-mark {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border: 1px solid var(--ink);
}

.fb-lib__folder.is-active .fb-lib__folder-mark,
.fb-lib__folder-mark.is-on {
  background: var(--ink);
}

.fb-lib__folder-mark.is-tag,
.fb-lib__folder.is-active .fb-lib__folder-mark.is-tag {
  border: 0;
  background: var(--lib-tag);
}

.fb-lib__folder-name {
  flex: 1 1 auto;
  min-width: 0;
  /* A line box as tall as the glyphs: descenders (g, p, y) are not cut by the overflow. */
  line-height: 16px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-lib__folder-count {
  flex: 0 0 auto;
  color: var(--muted);
  font: 500 var(--fs-xs, 10.5px)/1 var(--mono);
  font-variant-numeric: tabular-nums;
}

/* A label row and its ⋯ (Rename, Colour, Delete): the ⋯ takes the count's place while the row is
   hovered or focused, or its menu is open; a touch screen, which cannot hover, shows both. */
.fb-lib__label-row {
  position: relative;
}

.fb-lib__label-more {
  position: absolute;
  top: 4px;
  right: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 20px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
}

.fb-lib__label-more .fb-ico {
  width: 12px;
  height: 12px;
}

.fb-lib__label-row:hover .fb-lib__label-more,
.fb-lib__label-row:focus-within .fb-lib__label-more,
.fb-lib__label-more.is-open {
  opacity: 1;
}

.fb-lib__label-row:hover .fb-lib__folder-count,
.fb-lib__label-row:focus-within .fb-lib__folder-count,
.fb-lib__label-row:has(.fb-lib__label-more.is-open) .fb-lib__folder-count {
  visibility: hidden;
}

.fb-lib__label-more:hover,
.fb-lib__label-more.is-open {
  border-color: var(--ink);
  background: var(--surface);
  color: var(--ink);
}

.fb-lib__label-more:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

@media (hover: none) {
  .fb-lib__label-more {
    opacity: 1;
  }

  .fb-lib__label-row .fb-lib__folder {
    padding-right: 34px;
  }

  .fb-lib__label-row .fb-lib__folder-count {
    visibility: visible;
  }
}

.fb-lib__side-fill {
  flex: 1 1 auto;
}

/* CLOUD BOARDS n / limit: ten cells scaled to the server's ceiling, and the plan as it is. */
.fb-lib__quota {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--line-mid);
}

.fb-lib__quota-head {
  display: flex;
  justify-content: space-between;
  color: var(--muted);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-lib__quota-value {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.fb-lib__quota-value.is-full {
  color: var(--danger);
}

.fb-lib__quota-cells {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 2px;
}

.fb-lib__quota-cell {
  height: 6px;
  background: var(--line-soft);
}

.fb-lib__quota-cell.is-on {
  background: var(--ink);
}

/* The paper: an 80px grid on the lightest surface. */
.fb-lib__main {
  position: relative;
  min-height: 0;
  overflow: auto;
  background-color: var(--surface-2);
  background-image:
    linear-gradient(color-mix(in srgb, var(--grid-major) 57%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--grid-major) 57%, transparent) 1px, transparent 1px);
  background-size: 80px 80px;
}

.fb-lib__inner {
  padding: 20px 24px 64px;
}

.fb-lib__head {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.fb-lib__title {
  margin: 0;
  font-size: var(--fs-2xl, 20px);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

/* The phone's Folders button (below 760px, where the sidebar is gone). */
.fb-lib__pick {
  display: none;
  align-items: center;
  gap: 6px;
}

.fb-lib__pick .fb-ico {
  width: 12px;
  height: 12px;
}

.fb-lib__head-actions {
  display: flex;
  gap: 8px;
  align-self: center;
}

.fb-lib__head-actions:empty {
  display: none;
}

.fb-lib__banner:empty {
  display: none;
}

.fb-lib__banner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

/* A /b/<id> of a board in Trash: what happened, when it goes for good, Restore and Open Trash. The
   funnel this browser worked on signed out, offered to the account (.fb-lib__offer), is the same box:
   what it is, Add to your account and Not now. */
.fb-lib__trashed {
  max-width: 760px;
  font-size: var(--fs-md, 12.5px);
}

.fb-lib__trashed-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.fb-lib__trashed-body > p {
  margin: 0;
  color: var(--ink);
}

.fb-lib__trashed-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.fb-lib__note {
  max-width: 760px;
  margin: 10px 0 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.5;
}

.fb-lib__note[hidden] {
  display: none;
}

/* The trial banner (docs/PLANS.md §7.4): the paper's line under the title — a --warn square, the
   words, See options and ×, as the canvas banner draws them (.fb-banner). */
.fb-lib__plan {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 760px;
  margin: 10px 0 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.5;
}

.fb-lib__plan[hidden] {
  display: none;
}

.fb-lib__plan-mark {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background: var(--warn);
}

.fb-lib__plan-text {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}

.fb-lib__plan .btn {
  flex: 0 0 auto;
}

.fb-lib__note.is-error {
  color: var(--danger);
}

/* Its room kept, unseen, while /api/me has not said who is here (js/screens/library.js paintNote). */
.fb-lib__note.is-reserved {
  visibility: hidden;
}

/* The grid of cards: 260px at the least, 18px apart. The listbox's cards flow into it. */
.fb-lib__grid {
  margin-top: 16px;
}

.fb-lib__grid.is-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
}

.fb-lib__grid.is-grid > .fb-lib__list {
  display: contents;
}

.fb-lib__list[hidden] {
  display: none;
}

.fb-lib__grid.is-list > .fb-lib__list {
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

/* An empty folder: one plain mono line where the cards would start — no box (a dashed one read as
   the New funnel card that is gone; the sidebar's count already says 0). */
.fb-lib__empty {
  grid-column: 1 / -1;
  padding: 2px 0;
  color: var(--text-2);
  font: 500 var(--fs-xs, 10.5px)/16px var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* A board's card: the thumbnail on its 16px grid, the name and meta, the three figures. */
.fb-lib-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-ui);
  background: var(--surface);
  cursor: default;
}

/*
 * A card is a control, not text: a double click opens the board and must never select the word
 * under it (BRD-02, the name) - nor a shift-click a run of cards. The rename field is text again
 * (Safari keeps an input under `user-select: none` from being typed in).
 */
.fb-lib-card,
.fb-lib-row {
  -webkit-user-select: none;
  user-select: none;
}

.fb-lib__rename {
  -webkit-user-select: text;
  user-select: text;
}

.fb-lib-card:hover,
.fb-lib-card.is-selected {
  border-color: var(--ink);
}

.fb-lib-card:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-lib-card__thumb {
  position: relative;
  height: 132px;
  overflow: hidden;
  border-bottom: 1px solid var(--line-soft);
  background-color: var(--surface-2);
  background-image:
    linear-gradient(color-mix(in srgb, var(--grid-major) 76%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--grid-major) 76%, transparent) 1px, transparent 1px);
  background-size: 16px 16px;
}

.fb-lib-card.is-trash .fb-lib-thumb {
  opacity: 0.55;
}

.fb-lib-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.fb-lib-thumb__link {
  fill: none;
  stroke: var(--line-ui);
  stroke-width: 1;
}

.fb-lib-thumb__block {
  fill: var(--surface);
  stroke: var(--muted);
  stroke-width: 1;
}

.fb-lib-thumb__tag {
  fill: var(--lib-tag);
}

.fb-lib-thumb__score {
  fill: var(--surface);
  stroke: var(--ink);
  stroke-width: 1.2;
}

.fb-lib-thumb__score-head {
  fill: var(--ink);
}

.fb-lib-card__badges {
  position: absolute;
  top: 8px;
  left: 8px;
  display: flex;
  gap: 4px;
}

.fb-lib-badge {
  flex: 0 0 auto;
  padding: 3px 5px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-lib-badge.is-local {
  border: 1px dashed var(--line-ui);
  color: var(--text-2);
}

/* SHARED (docs/SHARING.md §12.7, the Boards concept's): a board whose share link works — the one
   accent, as a 1px boundary and its text on the card's surface. */
.fb-lib-badge.is-shared {
  border-color: var(--accent);
  color: var(--accent);
}

/* OPEN NOW: the funnel open in the editor, only in this browser — ink, not a tone. */
.fb-lib-badge.is-open {
  border-color: var(--ink);
}

/* Its Add to account, on the card (the pointer's; the keyboard has the card's menu and Edit). */
.fb-lib-card__add {
  position: absolute;
  right: 8px;
  bottom: 8px;
  min-height: 26px;
  padding: 0 8px;
  font-size: var(--fs-sm, 11.5px);
}

.fb-lib-card__add .fb-ico {
  width: 12px;
  height: 12px;
}

.fb-lib-card__more {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
}

.fb-lib-card__more:hover,
.fb-lib-card__more.is-open {
  border-color: var(--ink);
}

.fb-lib-card__more .fb-ico {
  width: 12px;
  height: 12px;
}

.fb-lib-card__meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px 0;
}

.fb-lib-card__title {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

.fb-lib-card__tag {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  background: var(--lib-tag);
}

.fb-lib-card__name {
  min-width: 0;
  overflow: hidden;
  font-size: var(--fs-lg, 14px);
  font-weight: 600;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-lib-card__line {
  display: flex;
  gap: 5px;
  min-width: 0;
  overflow: hidden;
  color: var(--muted);
  font: 500 var(--fs-xs, 10.5px)/1.4 var(--mono);
  text-transform: uppercase;
  white-space: nowrap;
}

/* The blocks and the time keep their width; the label gives way first, then the scenario. */
.fb-lib-card__part,
.fb-lib-card__sep {
  flex: 0 0 auto;
}

.fb-lib-card__part.is-label,
.fb-lib-card__part.is-scenario {
  min-width: 3ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-lib-card__part.is-label {
  flex: 0 1000 auto;
}

.fb-lib-card__part.is-scenario {
  flex: 0 1 auto;
}

.fb-lib-card__stats {
  display: grid;
  /* Each cell as wide as its head on one line (RISK OF NONE, EXPECTED PROFIT, the Russian heads),
     the rest shared: the three values stay on one row on a 260px card in either language. */
  grid-template-columns: repeat(3, minmax(0, auto));
  margin-top: 10px;
  border-top: 1px solid var(--line-soft);
}

.fb-lib-card__stat {
  min-width: 0;
  padding: 7px 10px 9px;
  border-right: 1px solid var(--line-soft);
}

.fb-lib-card__stat:last-child {
  border-right: 0;
}

/* The first figure starts where the name and the meta line above it do: 12px in from the card. */
.fb-lib-card__stat:first-child {
  padding-left: 12px;
}

.fb-lib-card__stat-label {
  overflow: hidden;
  color: var(--muted);
  font: 500 var(--fs-xs, 9px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.fb-lib-card__stat-value {
  margin-top: 5px;
  overflow: hidden;
  font: 500 var(--fs-lg, 14px)/1 var(--mono);
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-lib-card__stat-value.is-danger,
.fb-lib-row__num.is-danger {
  color: var(--danger);
}

/* Selection: the accent 5px outside the card, with the drawing's four square handles. */
.fb-lib-card__chrome {
  position: absolute;
  inset: -5px;
  border: 1.5px solid var(--accent);
  pointer-events: none;
}

.fb-lib-card__handle {
  position: absolute;
  width: 7px;
  height: 7px;
  border: 1.5px solid var(--accent);
  background: var(--surface);
}

.fb-lib-card__handle.is-nw { top: -4px; left: -4px; }
.fb-lib-card__handle.is-ne { top: -4px; right: -4px; }
.fb-lib-card__handle.is-sw { bottom: -4px; left: -4px; }
.fb-lib-card__handle.is-se { right: -4px; bottom: -4px; }

.fb-lib__rename {
  flex: 1 1 auto;
  min-width: 0;
  height: 22px;
  min-height: 22px;
  padding: 0 4px;
  font-weight: 600;
}

.fb-lib-card__title .fb-lib__rename {
  font-size: var(--fs-lg, 14px);
}

/* The list: eight columns, the selected row --select-2 with a 2px accent bar. The figures' columns
   are as wide as their heads on one line in English and Russian (RISK OF NONE, EXPECTED PROFIT);
   the name and the label share the rest. With no label on any listed board the
   LABEL column goes and NAME takes its room (.is-nolabel). */
.fb-lib-row {
  display: grid;
  grid-template-columns: 64px minmax(0, 2fr) minmax(0, 1fr) 60px 96px 116px 76px 96px;
  align-items: center;
  height: 34px;
  border-bottom: 1px solid var(--hover);
  background: var(--surface);
  cursor: default;
}

.fb-lib-row > span {
  min-width: 0;
  overflow: hidden;
  padding: 0 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-lib-row:last-child {
  border-bottom: 0;
}

.fb-lib-row:not(.is-head):hover {
  background: var(--hover);
}

.fb-lib-row.is-selected,
.fb-lib-row.is-selected:hover {
  background: var(--select-2);
  box-shadow: inset 2px 0 0 var(--accent);
}

.fb-lib-row:focus-visible {
  outline: none;
  box-shadow: inset 2px 0 0 var(--accent), inset 0 0 0 1px var(--accent);
}

.fb-lib-row.is-head {
  height: 28px;
  border-bottom: 1px solid var(--line-ui);
  background: var(--band);
  color: var(--text-2);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-lib-row.is-head > span {
  line-height: 1.15;
}

/* The figures' cells: a narrower gutter, the column no wider than its figure. */
.fb-lib-row > .is-num,
.fb-lib-row > .fb-lib-row__num {
  padding: 0 8px;
}

.fb-lib-row .is-num,
.fb-lib-row__num {
  text-align: right;
}

.fb-lib-row__code {
  font: 500 var(--fs-sm, 11px)/1 var(--mono);
}

.fb-lib-row.is-selected .fb-lib-row__code {
  color: var(--accent);
}

.fb-lib-row__name {
  display: flex;
  align-items: center;
  gap: 7px;
}

.fb-lib-row__title {
  min-width: 0;
  overflow: hidden;
  font-weight: 500;
  text-overflow: ellipsis;
}

.fb-lib-row__name .fb-lib-badge {
  padding: 2px 4px;
  font-size: var(--fs-xs, 9px);
}

.fb-lib-row__label,
.fb-lib-row__date {
  color: var(--text-2);
}

.fb-lib-row__num {
  font: 500 var(--fs-md, 12px)/1 var(--mono);
  font-variant-numeric: tabular-nums;
}

.fb-lib-row > .fb-lib-row__date {
  font: 400 var(--fs-sm, 11px)/1.1 var(--mono);
  white-space: normal;
}

/* In Trash the last column says when a board is deleted for good: wide enough for its head. */
.fb-lib__grid.is-trash .fb-lib-row {
  grid-template-columns: 64px minmax(0, 2fr) minmax(0, 1fr) 60px 96px 116px 76px 128px;
}

/* No listed board has a label: no empty LABEL column, NAME has its width. */
.fb-lib__grid.is-nolabel .fb-lib-row {
  grid-template-columns: 64px minmax(0, 1fr) 60px 96px 116px 76px 96px;
}

.fb-lib__grid.is-nolabel.is-trash .fb-lib-row {
  grid-template-columns: 64px minmax(0, 1fr) 60px 96px 116px 76px 128px;
}

.fb-lib__grid.is-nolabel .fb-lib-row > .fb-lib-row__label,
.fb-lib__grid.is-nolabel .fb-lib-row > .fb-lib-row__labelhead {
  display: none;
}

/* The Boards page while it waits (docs/PLANS.md §9.1, §9.3). A card waiting on its own request
   carries the small indicator in its badge row; one leaving (Trash, delete, Empty Trash) is
   dimmed until the answer; the card being opened says OPENING beside the indicator. */
.fb-lib-card__wait {
  display: inline-flex;
  align-items: center;
  height: 17px;
  padding: 0 5px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.fb-lib-badge.is-opening {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border-color: var(--ink);
}

.fb-lib-row__name > .fb-lib-card__wait {
  flex: 0 0 auto;
  margin-left: 6px;
}

.fb-lib-card.is-leaving,
.fb-lib-row.is-leaving {
  opacity: 0.5;
}

/* A skeleton card or row: the real one's geometry, bars where its words and figures will be. */
.fb-lib-card.is-skeleton,
.fb-lib-row.is-skeleton {
  pointer-events: none;
}

.fb-lib-row.is-skeleton:hover {
  background: var(--surface);
}

.fb-lib-skel__badge {
  width: 40px;
  height: 17px;
}

/* The name's and the meta line's bars stand in those lines (inline), so each line keeps its own
   height: the skeleton card is the real card's height to the pixel. */
.fb-lib-card.is-skeleton :is(.fb-lib-card__name, .fb-lib-card__line > span, .fb-lib-card__purge > span) > .fb-skel {
  display: inline-block;
  vertical-align: middle;
}

.fb-lib-card.is-skeleton .fb-lib-card__name {
  flex: 1 1 auto;
}

.fb-lib-card.is-skeleton .fb-lib-card__line > span {
  flex: 1 1 auto;
}

.fb-lib-skel__name {
  width: 60%;
  height: 14px;
}

.fb-lib-skel__meta {
  width: 80%;
  height: 10px;
}

.fb-lib-skel__meta.is-short {
  width: 55%;
}

.fb-lib-skel__cell > .fb-skel {
  width: 70%;
  height: 10px;
}

.fb-lib-skel__cell.is-num > .fb-skel {
  width: 32px;
  margin-left: auto;
}

.fb-lib__grid.is-nolabel .fb-lib-row > .fb-lib-skel__cell.is-label {
  display: none;
}

/* The card whose figures are still being computed: bars in their cells, the thumbnail's grid bare
   (L3). */
.fb-lib-card__stat-value > .fb-skel {
  display: inline-block;
  width: 44px;
  height: 14px;
  vertical-align: top;
}

/* Each figure's bar about its figure's width (< 1%, +€933, 11%), so the cells, sized by their
   content, keep the widths the figures give them when they land. */
.fb-lib-card__stat:nth-child(1) > .fb-lib-card__stat-value > .fb-skel {
  width: 32px;
}

.fb-lib-card__stat:nth-child(3) > .fb-lib-card__stat-value > .fb-skel {
  width: 24px;
}

/* The page's toast: centred over the paper, with Undo. */
.fb-lib__toast-host {
  position: fixed;
  z-index: 1;
  right: 0;
  bottom: 16px;
  left: var(--lib-side);
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.fb-lib__toast {
  max-width: min(720px, calc(100% - 32px));
  gap: 12px;
  min-height: 34px;
  padding: 0 6px 0 12px;
  font-size: var(--fs-md, 12.5px);
  cursor: default;
}

.fb-lib__undo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--on-ink) 40%, transparent);
  border-radius: 0;
  background: transparent;
  color: var(--on-ink);
  font: 400 var(--fs-md, 12px)/1 var(--font);
  cursor: pointer;
}

.fb-lib__undo:hover {
  border-color: var(--on-ink);
}

.fb-lib__undo:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--on-ink);
}

/* The delete confirmation: BLOCKS and SAVES in a recessed mono box; the action solid --danger. */
.fb-lib__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 14px;
  margin: 12px 0 0;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  background: var(--band);
  font: 500 var(--fs-sm, 11px)/1.4 var(--mono);
  font-variant-numeric: tabular-nums;
}

.fb-lib__facts dt {
  color: var(--text-2);
  text-transform: uppercase;
}

.fb-lib__facts dd {
  margin: 0;
}

.btn-danger-solid {
  border-color: var(--danger);
  background: var(--danger);
  color: var(--on-ink);
  font-weight: 500;
}

.btn-danger-solid:hover,
.btn-danger-solid:active {
  border-color: var(--ink);
  background: var(--danger);
}

.btn-danger-solid:focus-visible {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 2px var(--surface);
}

.fb-menu__item.is-danger {
  color: var(--danger);
}

.fb-menu__item.is-danger:hover,
.fb-menu__item.is-danger:focus-visible {
  background: var(--danger-tint);
}

/* A destructive item that cannot be picked now is as quiet as any other. */
.fb-menu__item.is-danger[aria-disabled="true"] {
  background: transparent;
  color: var(--muted);
}

/* Trash: when a board is deleted for good, under its meta line. */
.fb-lib-card__purge {
  overflow: hidden;
  color: var(--text-2);
  font: 500 var(--fs-xs, 10.5px)/1.4 var(--mono);
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The quota near (90 %) and at the server's ceiling: the figure and the filled cells in --danger. */
.fb-lib__quota.is-near .fb-lib__quota-cell.is-on,
.fb-lib__quota.is-full .fb-lib__quota-cell.is-on {
  background: var(--danger);
}

.fb-lib__quota-warn {
  margin: 0;
  color: var(--danger);
  font: 500 var(--fs-xs, 10.5px)/1.3 var(--mono);
  text-transform: uppercase;
}

/* Over the plan's ceiling after a lapse (docs/PLANS.md §4.3): --warn, never --danger — a state the
   person expects, not a fault — with Upgrade… and Why?. */
.fb-lib__quota-value.is-over {
  color: var(--warn);
}

.fb-lib__quota.is-over .fb-lib__quota-cell.is-on {
  background: var(--warn);
}

.fb-lib__quota-over {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

.fb-lib__quota-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
}

/* READ-ONLY on a card after BRD-nn (§5.6): a plain state badge. */
.fb-lib-badge.is-readonly {
  color: var(--text-2);
}

/* A first visit: the ways to begin, beside the New funnel card, two cards wide. */
.fb-lib-start {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  align-self: start;
  gap: 8px;
  min-height: 0;
  padding: 18px 20px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-lib-start__title {
  margin: 0;
  font-size: var(--fs-xl, 16px);
  font-weight: 600;
  line-height: 1.3;
}

.fb-lib-start__body {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.45;
}

.fb-lib-start__head {
  margin-top: 6px;
}

/* A .fcad file: the tool strip's Open .fcad… on a desktop; on a phone (no such button) here. */
.fb-lib-start .fb-lib-start__file {
  display: none;
}

.fb-lib-start__list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.fb-lib-start__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
}

.fb-lib-start__item > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-lib-start__item .fb-ico {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
}

/* The canvas with no funnel (js/start-panel.js, DESIGN §4.8): the first-visit panel above over the
   empty paper — each example a two-line choice (its name, its one line), then Empty board and Open a
   file…. Under the banner and the boot wait (40); the paper around it stays the canvas's. */
.fb-start {
  position: absolute;
  z-index: 30;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 56px 24px 24px;
  overflow: auto;
  pointer-events: none;
}

.fb-start[hidden] {
  display: none;
}

.fb-start__panel {
  width: min(600px, 100%);
  pointer-events: auto;
}

.fb-start__examples {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}

.fb-start__examples > [role="listitem"] {
  display: flex;
  min-width: 0;
}

.fb-start__example {
  flex: 1 1 auto;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 3px;
  min-width: 0;
  padding: 8px 10px 9px;
  text-align: left;
  white-space: normal;
}

.fb-start__name {
  font-weight: 600;
  line-height: 1.3;
}

.fb-start__desc {
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

/* The canvas's own "Insert a Source and a Step…" says the same as the panel: one place (§1.8). The
   save indicator has nothing to say (nothing is saved until the pick), nor the zoom anything to zoom. */
body.has-start :is(.fb-canvas-hint, .fb-save, .fb-zoomctl) {
  visibility: hidden;
}

/* "Replace …?" (js/app.js askReplace): what it does, then the rule under it. */
.fb-replace .fb-modal-body p + p {
  margin-top: 8px;
}

/* LABELS "+": the new label typed in place — a colour square that steps through the tag colours,
   the name in a 24px field, and the keys under it. */
.fb-lib__draft {
  padding: 3px 12px 6px 9px;
}

.fb-lib__draft-line {
  display: flex;
  align-items: center;
  gap: 5px;
}

.fb-lib__draft-colour {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  cursor: pointer;
}

.fb-lib__draft-colour:hover {
  border-color: var(--line-ui);
  background: var(--surface);
}

.fb-lib__draft-colour:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-lib__draft-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 24px;
  padding: 0 6px;
  border: 1px solid var(--line-ui);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  font: 400 var(--fs-md, 12.5px)/1 var(--font);
}

.fb-lib__draft-input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-lib__draft-input[aria-invalid='true'] {
  border-color: var(--danger);
}

.fb-lib__draft-error {
  margin: 4px 0 0 25px;
  color: var(--danger);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.35;
}

.fb-lib__draft-hint {
  margin: 4px 0 0 25px;
  color: var(--muted);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

@media (max-width: 1099.98px) {
  .fb-lib__template,
  .fb-lib__strip .btn .fb-kbd {
    display: none;
  }
}

/* The phone's own controls: hidden on a desktop. */
.fb-lib__phone-menu,
.fb-lib__sortpick,
.fb-lib__phonebar,
.fb-lib__quota.fb-lib__quota-phone {
  display: none;
}

/* A phone (§13, in the language of §9): the dark 48px header with the mark, "Boards", the account
   and Menu; the filter and the order; one column of cards; CLOUD BOARDS under them; New funnel as
   the one solid ink button at the bottom. Every target 44px, every field 16px. */
@media (width < 760px) {
  .fb-lib {
    min-width: 0;
    grid-template-rows: auto auto minmax(0, 1fr) auto;
  }

  .fb-lib__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .fb-lib__bar {
    gap: 4px;
    height: auto;
    min-height: calc(48px + var(--safe-top));
    padding: var(--safe-top) calc(4px + var(--safe-right)) 0 calc(16px + var(--safe-left));
  }

  .fb-lib__bar .fb-brand {
    margin-right: 6px;
  }

  /* The mark alone on a phone: a 44px target for a thumb, drawn where it was (the negative margin). */
  .fb-lib__bar .fb-brand__link {
    justify-content: center;
    height: 44px;
    min-width: 44px;
    margin: 0 -14px;
    padding: 0 14px;
  }

  .fb-lib__bar .fb-lockup__word,
  .fb-lib__bar .fb-lockup__cad,
  .fb-lib__bar .fb-menubar__menus,
  .fb-lib__rule,
  .fb-lib__sync,
  .fb-lib__bar .fb-menubar__account-label,
  .fb-lib__side,
  .fb-lib__new,
  .fb-lib__open,
  .fb-lib__template,
  .fb-lib__divider,
  .fb-lib__sort-label,
  .fb-lib__seg,
  .fb-lib__strip > .fb-lib__spacer,
  .fb-lib__filter .fb-kbd {
    display: none;
  }

  .fb-lib__crumb {
    font: 600 15px/44px var(--font);
  }

  .fb-lib__account,
  .fb-lib__phone-menu {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--chrome-title);
    cursor: pointer;
  }

  .fb-lib__account[hidden] {
    display: none;
  }

  .fb-lib__account .fb-avatar {
    width: 24px;
    height: 24px;
    font-size: 10px;
  }

  /* Its glyph is thinned by the phone header's rule (.fb-mhead__btn, a class it carries too). */
  .fb-lib__phone-menu .fb-ico {
    width: 18px;
    height: 18px;
  }

  .fb-lib__phone-menu:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--chrome-title);
  }

  .fb-lib__bar .fb-signin-btn {
    height: 32px;
    margin-right: 4px;
    font-size: 14px;
  }

  /* Beside Sign in and Menu it would crowd the 48px header at 390px (in Russian, past it): Create
     account is Menu's last item on a phone (DESIGN §13). */
  .fb-lib__bar .fb-signup-btn {
    display: none;
  }

  .fb-lib__strip {
    gap: 8px;
    height: auto;
    padding: 8px calc(12px + var(--safe-right)) 8px calc(12px + var(--safe-left));
  }

  .fb-lib__filter {
    flex: 1 1 auto;
    min-width: 0;
    height: 44px;
  }

  .fb-lib__filter > .fb-lib__filter-input {
    font-size: 16px;
  }

  .fb-lib__sortpick {
    display: inline-flex;
    gap: 6px;
    min-height: 44px;
    padding: 0 12px;
    font: 500 12px/1 var(--mono);
    text-transform: uppercase;
  }

  .fb-lib__sortpick .fb-ico {
    width: 12px;
    height: 12px;
  }

  .fb-lib__inner {
    padding: 16px calc(12px + var(--safe-right)) 24px calc(12px + var(--safe-left));
  }

  .fb-lib__head {
    align-items: center;
    gap: 10px;
  }

  .fb-lib__pick {
    display: inline-flex;
    min-height: 44px;
    font-size: 14px;
  }

  .fb-lib__head-actions .btn,
  .fb-lib__trashed-actions .btn {
    min-height: 44px;
  }

  .fb-lib__note {
    font-size: 13px;
  }

  .fb-lib__plan {
    flex-wrap: wrap;
    font-size: 13px;
  }

  .fb-lib__plan-text {
    flex-basis: calc(100% - 60px);
  }

  .fb-lib__grid.is-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }

  .fb-lib-start {
    grid-column: auto;
    min-height: 0;
    padding: 16px;
  }

  .fb-lib-start__item {
    min-height: 44px;
    font-size: 14px;
  }

  .fb-lib-start .fb-lib-start__file {
    display: flex;
  }

  .fb-lib-start .fb-lib-start__head.fb-lib-start__file {
    display: block;
  }

  .fb-start {
    padding: 16px;
  }

  .fb-start__examples {
    grid-template-columns: minmax(0, 1fr);
  }

  .fb-start__example {
    min-height: 44px;
    font-size: 14px;
  }

  .fb-start__desc {
    font-size: 12.5px;
  }

  /* The ⋯ keeps the concept's small box; its target reaches 44px around it. */
  .fb-lib-card__more {
    top: 4px;
    right: 4px;
    width: 36px;
    height: 36px;
  }

  .fb-lib-card__more::before {
    position: absolute;
    inset: -4px;
    content: '';
  }

  .fb-lib-card__line,
  .fb-lib-card__purge {
    font-size: 11px;
  }

  .fb-lib-card__add {
    min-height: 44px;
  }

  .fb-lib__quota.fb-lib__quota-phone {
    display: flex;
    margin-top: 20px;
    border: 1px solid var(--line-mid);
    background: var(--panel);
  }

  .fb-lib__quota[hidden] {
    display: none;
  }

  .fb-lib__quota-head {
    font-size: 11px;
  }

  .fb-lib__phonebar {
    display: flex;
    padding: 8px calc(12px + var(--safe-right)) calc(8px + var(--safe-bottom)) calc(12px + var(--safe-left));
    border-top: 1px solid var(--line);
    background: var(--panel);
  }

  .fb-lib__phonenew {
    flex: 1 1 auto;
    min-height: 44px;
    font-size: 15px;
  }

  .fb-lib__phonenew .fb-ico {
    width: 14px;
    height: 14px;
  }

  /* The toasts stand above the New funnel bar (its 1px rule, 8px, the 44px button, 8px and the
     safe area), 8px clear of it: over the bar a short one (Signing out…) left the button's edges
     showing on both sides of it and read as a garbled label (P1 review). */
  .fb-lib__toast-host {
    bottom: calc(69px + var(--safe-bottom));
    left: 0;
  }
}

/* A confirmation above a dialog's first field (a sign-in notice). */
.fb-modal-body > .fb-ok-box {
  margin-bottom: 14px;
}

/* ------------------------------------------------------ the conflict dialog */

.fb-conflict-body {
  margin: 0 0 10px;
  font-size: var(--fs-md, 12px);
}

.fb-conflict-choices {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.fb-conflict-choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

/* What each choice keeps: a name, a count and a time — figures that must line up and not jump. */
.fb-conflict-version {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------ the share dialog */
/* The owner's Share dialog (js/screens/share.js, docs/SHARING.md §12): the 640px frame, one page
   with no scrolling on a 1366 x 768 laptop. The top is two columns — the link, the lead and the
   three switches on the left, the link preview on the right; then the statistics with the 52-week
   heatmap, then Export. On a phone the columns stack and the body scrolls. */

/* A --danger text and boundary on --surface: Stop sharing, Delete link and statistics. It acts,
   and it can be undone or asks first, so it is not the solid danger of a final confirm. */
.btn-danger-outline {
  border-color: var(--danger);
  color: var(--danger);
}

.btn-danger-outline:hover {
  background: var(--danger-tint);
}

.fb-share {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.fb-share__error > div {
  min-width: 0;
}

.fb-share__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 20px;
  align-items: start;
}

.fb-share__top.is-single {
  grid-template-columns: minmax(0, 1fr);
}

/* Two kinds of link (docs/COMMENTS.md §32.1): `Live link · Snapshot` under the title picks the link
   the body shows. A segment whose link is on carries the 6px square; on the pressed (ink) segment
   it is the ok colour for ink. */
.fb-share__kinds {
  align-self: flex-start;
}

.fb-share__kinds > button[aria-pressed="true"] .fb-status-square.is-ok {
  background: var(--on-ink-ok);
}

/* A live segment's PRO (docs/PLANS.md §6.7): dashed on Free, solid on a trial — on the pressed ink
   segment in the on-ink colour. */
.fb-share__kinds > button[aria-pressed="true"] .fb-badge.is-pro {
  border-color: var(--on-ink);
  color: var(--on-ink);
}

.fb-share__choice-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* A snapshot's Update snapshot under Copy and Post on LinkedIn (§6.7), its hint beside it. */
.fb-share__update {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
}

.fb-modal-body .fb-share__update p.fb-share__hint {
  flex: 1 1 200px;
  margin: 0;
}

/* A paused link's way on (§5.7): Turn into snapshot and Upgrade…, and the question asked in place. */
.fb-share__paused-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.fb-share__main > .fb-share__ask {
  margin-inline-start: 0;
}

/* The first-time choice: two rows in the Boards list's look (DESIGN §13), each one button — its
   name and one line under it on the left, the kind in mono on the right. */
.fb-share__choose {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fb-share__choices {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-share__choice {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  margin: 0;
  padding: 8px 12px;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.fb-share__choice:last-child {
  border-bottom: 0;
}

.fb-share__choice:hover {
  background: var(--hover);
}

.fb-share__choice:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}

.fb-share__choice[aria-busy="true"] {
  cursor: progress;
}

.fb-share__choice-text {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.fb-share__choice-title {
  font-size: var(--fs-md, 13px);
  font-weight: 600;
}

.fb-share__choice-hint {
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.4;
}

.fb-share__choice-kind {
  flex: 0 0 auto;
  color: var(--text-2);
  font: 500 var(--fs-xs, 9.5px)/1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-share__main {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}

.fb-share__side {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

/* A section's head: its mono micro-label on the left, what belongs to it on the right. */
.fb-share__head {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 16px;
}

.fb-share__head > :first-child {
  margin-inline-end: auto;
}

.fb-share__side > .fb-share__head > :first-child {
  margin-inline-end: 0;
}

.fb-share__status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.fb-share__status .fb-micro {
  color: var(--ok);
}

.fb-share__link {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fb-share__linkrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

/* The link has the whole line, so it reads to its end; Copy and Post on LinkedIn sit under it,
   side by side. */
.fb-share__linkrow > .fb-share__url {
  flex-basis: 100%;
}

/* The Share dialog's skeletons (docs/PLANS.md §9.3): the link field a 26px bar the column wide,
   the preview a 240 × 126 block. Its words are `text` skeletons and its buttons ghosts of
   themselves (js/screens/share.js), so they take the lines and widths of their language. A phone's
   sizes (44px controls, the preview the column wide) are in the phone query. */
.fb-share__skel-head {
  width: 88px;
  height: 9px;
}

.fb-share__skel-url {
  flex: 1 1 100%;
  height: 26px;
}

.fb-share__skel-preview {
  width: 240px;
  height: 126px;
}

.fb-share__skel-box {
  width: 14px;
  height: 14px;
  margin-top: 1px;
}

/* The preview language's select (on a link that will be on): a dialog select's 26px. */
.fb-share__skel-lang {
  width: 72px;
  height: var(--control-h-lg);
}

.fb-share__skel-primary {
  width: 100%;
  height: 32px;
}

.fb-share__skel-fighead {
  width: 64px;
  height: 9px;
  margin: 2px 0;
}

.fb-share__skel-figure {
  width: 28px;
  height: 15px;
  margin: 3px 0 2px;
}

.fb-share__preview.fb-skel {
  background: var(--hover);
}

/* A switch whose change is on its way: the small indicator after its label (L10), in the line's
   own gap. */
.fb-share__switch-busy {
  flex: 0 0 auto;
}

/* Copy: the primary act of the link (ink, the family's copy glyph). For two seconds after a copy
   it is --ok with the tick and "Copied" (.is-copied, below) — its own confirmation, in place of a
   toast. Its two faces share one cell; the one not shown keeps its room, so the button has one
   width. */
.fb-share__copy {
  display: inline-grid;
}

.fb-share__face {
  display: inline-flex;
  grid-area: 1 / 1;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.fb-share__face.is-off {
  visibility: hidden;
}

.fb-share__copy.is-copied,
.fb-share__copy.is-copied:hover,
.fb-share__copy.is-copied:active {
  border-color: var(--ok);
  background: var(--ok);
  color: var(--on-ink);
}

.fb-share__copy.is-copied:focus-visible {
  border-color: var(--accent);
  background: var(--ok);
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 2px var(--surface);
}

/* A Review link's line on whom to send it to, in Post on LinkedIn's place beside Copy
   (docs/COMMENTS.md §11): it takes the rest of the row, and the row's next line when that is too
   narrow. Where it wraps (Russian, beside the wider Russian Copy) its two lines are no taller than
   Copy, so the row keeps its height and the Review segment still fits 1366 × 768. */
.fb-modal-body p.fb-share__hint.fb-share__send {
  flex: 1 1 180px;
  align-self: center;
  min-width: 0;
  margin: 0;
  line-height: 1.2;
}

/* A Review link's page is longer than a View link's by its lead's two sentences on comments. On a
   laptop screen (SHARING §16.4: no scrolling at 1366 × 768 while the link is on) its switches' hint
   lines are cut to one each (docs/COMMENTS.md §11): a hint on its label's line, ended with an
   ellipsis where it is longer, and the column's gaps are a little tighter. The whole sentence stays
   in each one's tooltip and in the description a screen reader hears. The send line beside Copy is
   short and never cut. A taller screen has room for every line. With Accept new comments (C4) the
   longest leads — a password and hidden notes, whose export note adds a line — scrolled by 24px
   (English) and 44px (Russian) until C6 tightened the sections' air and the lead's leading. The
   skeleton of a Review link the page knows is on (`is-will-on`, js/screens/share.js) takes the same
   rules, so nothing moves when the link arrives. A snapshot link (docs/PLANS.md §6.7) — Update
   snapshot with its hint and a third switch — takes the same rules. */
@media (min-width: 760px) and (max-height: 879.98px) {
  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) {
    gap: 10px;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__main {
    gap: 6px;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__lead {
    line-height: 1.4;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__switches {
    gap: 4px;
  }

  /* 6px, not the Review link's 10px: the Live link's On lead with a password and hidden notes is its
     longest (six lines), and scrolled by 7px (Russian) at 10px (R6's check, docs/COMMENTS.md §33.7). */
  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__stats,
  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__export {
    padding-top: 6px;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__switch-text {
    flex-direction: row;
    align-items: baseline;
    column-gap: 10px;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__switch-line {
    flex: 0 0 auto;
    flex-wrap: nowrap;
  }

  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]):is(.is-on, .is-will-on) .fb-share__switch-text > .fb-share__hint {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* The skeleton's hints are unseen words: no ellipsis drawn after their bars. */
  .fb-share:is([data-share-kind="live"].has-comments, [data-share-kind="frozen"]).is-will-on .fb-share__switches.is-skeleton .fb-share__switch-text > .fb-share__hint {
    text-overflow: clip;
  }

  /* Update snapshot's hint on its button's line, the whole sentence in its tooltip — and in the
     skeleton of a snapshot the page knows is on, its unseen words on that one line (no ellipsis). */
  .fb-share[data-share-kind="frozen"]:is(.is-on, .is-will-on) .fb-modal-body .fb-share__update p.fb-share__hint,
  .fb-share[data-share-kind="frozen"]:is(.is-on, .is-will-on) .fb-share__update > p.fb-share__hint:not(.fb-share__updated) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .fb-share[data-share-kind="frozen"].is-will-on .fb-share__update.is-skeleton > p.fb-share__hint {
    text-overflow: clip;
  }
}

/* Post on LinkedIn: a link drawn as a button (it opens LinkedIn's share page in a new tab). */
a.btn.fb-share__linkedin {
  text-decoration: none;
}

/* Account settings ▸ Plan's Manage billing (docs/PLANS.md §5.10), and Your data's while a subscription
   keeps the account from being deleted (§11.2 item 4): Stripe's portal in a new tab, a link drawn as a
   button with its ↗. */
a.btn[data-settings-key="manage-billing"],
a.btn[data-settings-key="delete-billing-portal"] {
  text-decoration: none;
}

/* The link: read-only yet a control to select and copy from — ink on --surface, not the muted
   read-only field; mono, as every code is. */
.fb-share__url,
.fb-share__url[readonly] {
  flex: 1 1 auto;
  min-width: 0;
  border-color: var(--line-ui);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11.5px);
  cursor: text;
}

/* While sharing is off the link is greyed, still selectable. */
.fb-share__url.is-off,
.fb-share__url.is-off[readonly] {
  border-color: var(--line-soft);
  background: var(--surface-2);
  color: var(--muted);
}

.fb-modal-body p.fb-share__lead {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.5;
}

.fb-share__switches {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.fb-share__switch {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  column-gap: 8px;
  align-items: start;
}

.fb-share__switch > input[type="checkbox"] {
  margin-top: 1px;
}

.fb-share__switch-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.fb-share__switch-label {
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
  cursor: pointer;
}

.fb-share__switch-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 10px;
  row-gap: 2px;
}

/* The Live link's Comments (docs/COMMENTS.md §32.1): its label on the left and a small `.btn-seg`
   On · Read only · Hidden on the right, on one line with no hint line — the segments are named by
   what a viewer gets, each one's tooltip and description say the rest. A radiogroup: the chosen
   segment is ink. On a phone the label takes its own line and the segments the full width. */
.fb-share__comments {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 10px;
}

.fb-share__comments-line {
  flex: 0 1 auto;
}

.fb-share__comments-seg > button,
.fb-share__comments-seg > .fb-skel {
  min-height: 22px;
  padding: 0 8px;
  font-size: var(--fs-sm, 11.5px);
  white-space: nowrap;
}

.fb-share__comments-seg > .fb-skel {
  display: inline-flex;
  align-items: center;
}

/* An arrow's choice that waits on a press, unsaved (§32.1, round 3): *Not saved. Press Enter to …* on its
   own line under the segments, in the warning tone — the radio drawn checked is not the saved state. */
.fb-modal-body p.fb-share__comments-note {
  flex-basis: 100%;
  margin: 0;
  color: var(--warn);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

/* A link's scenarios (docs/SHARING.md §7.3), in the right column under the preview (which draws the
   opening one): the mono head OPENS ON with its select, a box per choice — Base and each scenario —
   two to a line, then the hint on one line; the opening one's box stays ticked (disabled). The column
   stays no taller than the switches' on a laptop with up to four choices. */
.fb-share__scen {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.fb-share__scen-line {
  display: flex;
  align-items: center;
  gap: 8px;
}

.fb-share__scen-opens {
  flex: 0 0 auto;
  white-space: nowrap;
}

.fb-share__scen-select,
.fb-modal-body .fb-share__scen-select {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  min-height: 20px;
  height: 20px;
  padding-inline-start: 6px;
  font-size: var(--fs-sm, 11.5px);
}

.fb-share__scen-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px 12px;
}

.fb-share__scen-item {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.fb-share__scen-item > input[type="checkbox"] {
  flex: 0 0 auto;
  margin: 0;
}

.fb-share__scen-item > label {
  overflow: hidden;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 15px;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.fb-share__scen-item > input:disabled + label {
  color: var(--text-2);
  cursor: default;
}

.fb-share__scen > .fb-share__hint {
  overflow: hidden;
  line-height: 14px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-modal-body .fb-share__scen > p.fb-share__warn {
  margin: 0;
}

/* The posted-address question (§32.1) under the Comments row: its actions wrap on a narrow column. */
.fb-share__wasview .fb-share__ask-actions {
  flex-wrap: wrap;
  align-items: center;
}

/* The merge's note (docs/COMMENTS.md §4.5) at the top of the link's segment: the `i` box with its ×. */
.fb-info-box.fb-share__note {
  grid-template-columns: 12px minmax(0, 1fr) auto;
  align-items: start;
}

.fb-modal-body .fb-share__note p {
  margin: 0;
}

.fb-share__note-x,
.fb-share__alias-x {
  width: 20px;
  min-width: 20px;
  height: 20px;
  min-height: 20px;
  padding: 0;
}

/* The earlier address in the footer's meta (§32.1): its words, the path in the token's own case, and
   its ×, kept on one line together. */
.fb-share__alias {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

.fb-share__alias-path {
  margin-inline-start: 1ch;
  text-transform: none;
}

.fb-share__alias-x {
  margin-inline-start: 4px;
}

.fb-share__switch-aside {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.fb-share__switch-aside > .btn-link {
  font-size: var(--fs-sm, 11.5px);
}

.fb-share__hint,
.fb-modal-body p.fb-share__hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.4;
}

/* The password field opens under its switch, indented to the switch's words. */
.fb-share__pw {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-inline-start: 22px;
}

.fb-share__pw-actions,
.fb-share__ask-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* A question asked in place (Remove the password?): the words, then the safe answer and the act. */
.fb-share__ask {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-inline-start: 22px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-modal-body .fb-share__ask p {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
}

.fb-modal-body p.fb-share__warn {
  margin: 0 0 0 22px;
  color: var(--warn);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

.fb-share__head > .fb-micro {
  white-space: nowrap;
}

.fb-share__lang {
  flex: 0 0 auto;
  width: auto;
  min-height: 20px;
  height: 20px;
  padding-inline-start: 4px;
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-modal-body .fb-share__lang {
  min-height: 20px;
}

/* The preview as LinkedIn will show it, in a 1px --line frame; while off, a recessed box. */
.fb-share__preview {
  display: block;
  width: 240px;
  height: 126px;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-share__preview.is-off {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  color: var(--muted);
  font-size: var(--fs-sm, 11.5px);
  text-align: center;
}

/* Statistics: the mono figures — viewing now, today, total, then after a rule the conversions —
   then the heatmap. */
.fb-share__stats {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

.fb-share__figures {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 28px;
}

/* Views on its left, what viewers did on its right. */
.fb-share__figures-rule {
  align-self: stretch;
  width: 1px;
  background: var(--line-soft);
}

.fb-share__figure {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.fb-share__value {
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-lg, 15px);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.fb-share__heat {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fb-heat__legend {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

.fb-heat__legend > .fb-micro:first-child {
  margin-inline-end: 4px;
}

.fb-heat__legend > .fb-micro:last-child {
  margin-inline-start: 4px;
}

/* The squares: 8px, a 2px gap, square-cornered (DESIGN §1.1); weeks run left to right, Monday on
   top. The weekday column is 24px and 6px from the squares (docs/SHARING.md §12.4). */
.fb-heat {
  position: relative;
  align-self: flex-start;
}

.fb-heat__months {
  position: relative;
  height: 12px;
  margin-inline-start: 30px;
}

.fb-heat__month {
  position: absolute;
  top: 0;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  line-height: 10px;
  white-space: nowrap;
}

.fb-heat__body {
  display: flex;
  gap: 6px;
}

.fb-heat__days {
  display: grid;
  grid-template-rows: repeat(7, 8px);
  row-gap: 2px;
  width: 24px;
}

.fb-heat__days > span {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  line-height: 8px;
  white-space: nowrap;
}

.fb-heat__grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, 8px);
  grid-auto-columns: 8px;
  gap: 2px;
}

.fb-heat__cell {
  display: block;
  width: 8px;
  height: 8px;
  background: var(--heat-0);
}

.fb-heat__cell.is-l1 {
  background: var(--heat-1);
}

.fb-heat__cell.is-l2 {
  background: var(--heat-2);
}

.fb-heat__cell.is-l3 {
  background: var(--heat-3);
}

.fb-heat__cell.is-l4 {
  background: var(--heat-4);
}

.fb-heat__cell.is-future {
  visibility: hidden;
}

/* NO VIEWS YET over the empty year, on a --surface patch so the squares do not run through it. */
.fb-heat__empty {
  position: absolute;
  inset: 12px 0 0 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.fb-heat__empty > span {
  padding: 2px 8px;
  background: var(--surface);
  color: var(--text-2);
}

.fb-share__export {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

.fb-share__export-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* The footer: CREATED … · REPLACED … on the left, the link's actions on the right; a question
   takes the actions' place, its words above its answers. */
.fb-share__meta {
  color: var(--text-2);
}

.fb-share__foot-ask {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.fb-modal-foot .fb-share__foot-ask p {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

/* ------------------------------------------------------ account settings (§8) */
/* The 640px settings frame (js/screens/settings.js; FunnelCAD Auth Flows.dc.html, D): the section
   list on the left, the section and its staged-changes footer on the right. The frame keeps one
   height, so switching sections never moves it. The list sits on --surface-2, not the design's
   --bg: its Sign out is a control, and --line-ui clears 3:1 only on the lighter paper (§2.3). */

.fb-modal.fb-settings {
  height: min(560px, calc(100% - 8px));
}

.fb-modal-body.fb-settings__body {
  display: flex;
  padding: 0;
  overflow: hidden;
}

.fb-settings__grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  width: 100%;
  min-height: 0;
}

.fb-settings__nav {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-settings__who {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 12px;
  border-bottom: 1px solid var(--line-mid);
}

/* The initials: a square in ink, never a circle and never the accent (§1.2). */
.fb-settings__avatar {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: var(--ink);
  color: var(--on-ink);
  font: 600 12px/1 var(--mono);
  letter-spacing: 0.02em;
}

.fb-settings__avatar.is-large {
  width: 56px;
  height: 56px;
  font-size: 18px;
}

.fb-settings__who-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.fb-settings__who-name,
.fb-settings__who-email {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-settings__who-name {
  font-size: var(--fs-md, 13px);
  font-weight: 600;
}

.fb-settings__who-email {
  color: var(--text-2);
  font-size: var(--fs-xs, 10.5px);
}

.fb-settings__tabs {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: 6px 0;
  overflow-y: auto;
}

.fb-settings__tab {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 30px;
  padding: 0 12px;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  font: 400 var(--fs-md, 12.5px)/1.2 var(--font);
  text-align: start;
  cursor: pointer;
}

.fb-settings__tab:hover {
  background: var(--hover);
}

/* The section shown: the surface, an ink bar on the left, rules above and below. */
.fb-settings__tab[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--ink), inset 0 1px 0 var(--line-mid), inset 0 -1px 0 var(--line-mid);
}

.fb-settings__tab:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-settings__tab[aria-selected="true"]:focus-visible {
  box-shadow: inset 2px 0 0 var(--ink), inset 0 0 0 1px var(--accent);
}

.fb-settings__key {
  color: var(--text-2);
  font: 500 var(--fs-xs, 10px)/1 var(--mono);
}

.fb-settings__navfoot {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 12px;
  border-top: 1px solid var(--line-mid);
}

.fb-settings__plan {
  color: var(--text-2);
}

.fb-settings__signout {
  width: 100%;
}

.fb-settings__main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.fb-settings__panels {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.fb-settings__panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 22px 22px;
}

.fb-settings__panel[hidden] {
  display: none;
}

.fb-settings__panel:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-settings__title {
  margin: 0;
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 1.3;
}

.fb-settings .fb-settings__lead {
  margin: -8px 0 4px;
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.45;
}

.fb-settings .fb-settings__note {
  margin: 0;
  color: var(--muted);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.45;
}

.fb-settings .fb-settings__note.is-body {
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
}

/* The footer: how many changes wait on the left, Discard and Save on the right; while leaving
   with changes, the question takes the actions' place. */
.fb-settings__foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 48px;
  padding: 8px 22px;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-settings__meta {
  margin-inline-end: auto;
  color: var(--text-2);
}

.fb-settings__meta.is-dirty {
  color: var(--ink);
}

.fb-settings__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.fb-settings__actions[hidden] {
  display: none;
}

.fb-settings__actions.is-asking {
  flex: 1 1 auto;
  flex-wrap: wrap;
}

.fb-settings__ask {
  color: var(--ink);
  font-size: var(--fs-md, 12px);
}

.fb-settings__actions.is-asking > .fb-settings__ask {
  margin-inline-end: auto;
}

/* Initials read as they will be kept: upper case while they are typed. */
.fb-settings__initials-cell > .fb-settings__initials {
  text-transform: uppercase;
}

/* Profile. */
.fb-settings__identity {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-settings__rows {
  display: grid;
  grid-template-columns: 100px minmax(0, 1fr);
  align-items: start;
  gap: 10px 12px;
}

.fb-settings__label {
  padding-top: 6px;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
}

.fb-settings__rows > input,
.fb-settings__subform input:not([type="checkbox"]):not([type="radio"]),
.fb-settings__inline input {
  width: 100%;
  min-width: 0;
}

.fb-settings__email-cell,
.fb-settings__initials-cell {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.fb-settings__initials-cell > .fb-settings__initials {
  width: 72px;
}

.fb-settings__email {
  display: flex;
  align-items: stretch;
  gap: 8px;
}

.fb-settings__email[hidden] {
  display: none;
}

/* The address as it stands: read-only, recessed, with its CONFIRMED badge. */
.fb-settings__recessed {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  min-height: var(--control-h-lg);
  padding: 0 8px;
  border: 1px solid var(--line-mid);
  background: var(--surface-2);
}

.fb-settings__email-text {
  overflow: hidden;
  font-size: var(--fs-md, 12px);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-settings__subform {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--line);
}

.fb-settings__subform[hidden],
.fb-settings__pending[hidden] {
  display: none;
}

/* Under Resend when the wait is the server's per-address limit, not the minute's pause. */
.fb-resend-limit {
  margin: 0;
}

.fb-settings__pending .fb-resend-limit {
  margin-top: 8px;
}

.fb-settings__subactions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.fb-settings__pending > div {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.fb-settings__pending:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* A group head (PASSKEYS · 1) with its action on the right, in the action's own type. */
.fb-settings__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 6px;
  color: var(--text-2);
  font-weight: 600;
}

/* A head's link (Sign out everywhere else) shows once the list is in: its line is kept meanwhile,
   so the list under it does not move by the link's 2px when it lands. */
.fb-settings__head.has-action {
  min-height: 14px;
}

.fb-settings__head :is(.btn, .btn-link) {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

.fb-settings__head .btn {
  min-height: var(--control-h);
  padding: 0 8px;
}

.fb-settings__band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}

.fb-settings__list {
  border: 1px solid var(--line);
}

.fb-settings__list > .fb-still-loading {
  margin: 0;
  padding: 8px 10px;
  border-top: 1px solid var(--line-soft);
}

.fb-settings__list.is-rules {
  border: 0;
  border-top: 1px solid var(--line-soft);
}

.fb-settings__item {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 8px 10px;
  border-top: 1px solid var(--line-soft);
}

.fb-settings__item:first-child {
  border-top: 0;
}

.fb-settings__item.is-plain {
  grid-template-columns: minmax(0, 1fr) auto;
}

.fb-settings__list.is-rules > .fb-settings__item {
  padding: 10px 0;
  border-top: 0;
  border-bottom: 1px solid var(--line-soft);
}

.fb-settings__item-icon {
  display: inline-flex;
  color: var(--ink);
}

.fb-settings__item-icon .fb-ico,
.fb-settings__item-icon svg {
  width: 14px;
  height: 14px;
}

.fb-settings__item-icon.is-letter {
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 1px solid var(--ink);
  font: 600 var(--fs-xs, 9.5px)/1 var(--mono);
}

.fb-settings__row-text {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.fb-settings__row-name {
  font-size: var(--fs-md, 12.5px);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.fb-settings__row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}

.fb-settings__row-actions[hidden] {
  display: none;
}

/* A row asking before it removes: the question takes a line of its own under the name. */
.fb-settings__item.is-asking > .fb-settings__row-actions {
  grid-column: 2 / 4;
  justify-content: flex-start;
}

.fb-settings__inline {
  grid-column: 2 / 4;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.fb-settings .fb-settings__empty {
  margin: 0;
  padding: 14px;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  text-align: center;
}

/* An empty status line takes no room: the panel's gap is enough until it has news. */
.fb-settings__panel > .fb-form-status:empty {
  min-height: 0;
  margin-top: -12px;
}

.fb-settings__list > .fb-error-box {
  border-width: 0;
}

.btn-link.is-danger {
  color: var(--danger);
}

/* THIS DEVICE: a state, solid ink. */
.fb-badge.is-solid {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--on-ink);
}

/* Connected apps (docs/MCP.md): the address in the Share dialog's recessed mono field with its Copy,
   three numbered steps (mono numerals, the entry dialog's + rows' grid), the Claude Code line; each
   connection a row with its host as a badge, and under it its activity — time right-aligned in mono. */
.fb-settings__apps-connect {
  display: grid;
  gap: 10px;
}

.fb-settings__steps {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-settings__steps li {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: 6px;
  color: var(--ink);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.5;
}

.fb-settings__step-n {
  font: 500 var(--fs-md, 12.5px)/1.5 var(--mono);
}

.fb-settings__apps-code {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  margin: 0;
}

.fb-settings .fb-settings__apps-code-after {
  flex-basis: 100%;
}

.fb-settings__apps-cmd {
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11.5px);
  overflow-wrap: anywhere;
  user-select: all;
}

.fb-settings__app-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.fb-settings__app.is-ended .fb-settings__row-name {
  color: var(--text-2);
  font-weight: 400;
}

.fb-settings__list.is-rules > .fb-settings__item:has(+ .fb-settings__activity) {
  padding-bottom: 6px;
  border-bottom: 0;
}

.fb-settings__activity {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0 0 10px;
  border-bottom: 1px solid var(--line-soft);
  list-style: none;
}

.fb-settings__activity li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  color: var(--ink-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

.fb-settings__activity-text {
  overflow-wrap: anywhere;
}

.fb-settings__activity-more {
  display: block;
  margin: 6px 0 10px;
  font-size: var(--fs-sm, 11.5px);
}

/* Plan: the one plan under a chrome band, its limits as segmented meters. */
.fb-settings__card {
  border: 1px solid var(--ink);
}

.fb-settings__card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 30px;
  padding: 0 12px;
  background: var(--chrome);
}

.fb-settings__card-head > * {
  color: var(--chrome-title);
}

.fb-settings__plan-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 12px;
}

/* Plan once plans are enforced (docs/PLANS.md §5.9): its end under the band, then — outside the
   card — the paused View links, the history and one See plans. */
.fb-settings__plan-body > p.fb-settings__plan-line {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

.fb-settings__plan-more {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 14px;
}

.fb-settings__plan-more[hidden] {
  display: none;
}

.fb-settings__paused,
.fb-settings__paused-ask {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.fb-settings__paused-ask > p {
  margin: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

.fb-settings__history .fb-settings__row-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}

.fb-settings__history-note {
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  overflow-wrap: anywhere;
}

.fb-settings__limits {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 18px;
}

.fb-settings__limit {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

/* Account settings while a list is read (docs/PLANS.md §9.1 L13): its own rows, bars for the text. */
.fb-settings__skel-icon {
  width: 14px;
  height: 14px;
}

.fb-settings__skel-name {
  width: 40%;
  height: 12px;
}

.fb-settings__skel-meta {
  width: 60%;
  height: 9px;
}

/* A bar stands in the line its words will take (the row's name, a micro line, a fact's figure):
   inline, so that line keeps its own height and the row is the real row's height. */
.fb-settings :is(.fb-settings__row-name, .fb-micro, .fb-settings__facts dd) > .fb-skel.is-bar {
  display: inline-block;
  vertical-align: middle;
}

.fb-settings__row-text > .fb-micro > .fb-settings__skel-meta {
  width: 160px;
}

/* Change password's place: a .btn's height (44px on a phone, as the button is) and its width. */
.fb-settings__skel-button {
  flex: 0 0 auto;
  width: 120px;
  height: var(--control-h-lg);
}

.fb-settings__skel-button[hidden] {
  display: none;
}

.fb-settings__skel-fact {
  width: 72px;
  height: 9px;
}

.fb-settings__skel-meter {
  height: 3px;
}

.fb-settings__limit-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

/* The label may wrap; the figure never does: "0 KB / 1 MB" keeps its unit with its number. */
.fb-settings__limit-head .num {
  flex: 0 0 auto;
  color: var(--ink);
  white-space: nowrap;
}

.fb-settings__limit-head .num.is-over {
  color: var(--warn);
}

.fb-settings__limit-head .num.is-full {
  color: var(--danger);
}

.fb-settings__facts {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 6px 16px;
  margin: 0;
  font-size: var(--fs-md, 12px);
}

.fb-settings__facts dt {
  color: var(--text-2);
}

.fb-settings__facts dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* A choice that is a code (EN, RU) is set in mono, like every code. */
.btn-seg > button.num {
  font-family: var(--mono);
  font-size: var(--fs-sm, 11.5px);
  font-weight: 500;
}

/* Your data: the danger zone, a --danger rule round the one irreversible action. */
/* Your data ▸ Legal: the site's pages, a line of links (each a new tab, its ↗ in mono). */
.fb-settings__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-settings__legal-link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.fb-settings__danger {
  margin-top: 4px;
  border: 1px solid var(--danger);
}

.fb-settings__danger-head {
  padding: 8px 12px;
  border-bottom: 1px solid var(--danger);
  background: var(--danger-tint);
  color: var(--danger);
  font-weight: 600;
}

.fb-settings__danger-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 12px 12px;
}

.fb-settings__danger-body .fb-settings__item.is-plain {
  padding-inline: 0;
}

.fb-settings .btn-danger:not(:disabled) {
  border-color: var(--danger);
  color: var(--danger);
  font-weight: 500;
}

.fb-settings .btn-danger.is-solid:not(:disabled) {
  background: var(--danger);
  color: var(--on-ink);
}

.fb-settings .btn-danger.is-solid:not(:disabled):hover {
  background: var(--danger);
  color: var(--on-ink);
  opacity: 0.9;
}

/* A narrow window: the sections become a row of tabs over the section, the fields stack. */
@media (max-width: 599.98px) {
  .fb-modal.fb-settings {
    height: calc(100% - 8px);
  }

  .fb-settings__grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  .fb-settings__nav {
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .fb-settings__who,
  .fb-settings__plan,
  .fb-settings__key {
    display: none;
  }

  .fb-settings__tabs {
    flex-direction: row;
    padding: 0;
    overflow-x: auto;
  }

  .fb-settings__tab {
    flex: 0 0 auto;
    min-height: 36px;
  }

  .fb-settings__tab[aria-selected="true"] {
    box-shadow: inset 0 -2px 0 var(--ink);
  }

  .fb-settings__tab[aria-selected="true"]:focus-visible {
    box-shadow: inset 0 -2px 0 var(--ink), inset 0 0 0 1px var(--accent);
  }

  .fb-settings__navfoot {
    flex-direction: row;
    justify-content: flex-end;
    padding: 6px 12px;
    border-top: 1px solid var(--line-soft);
  }

  .fb-settings__signout {
    width: auto;
  }

  .fb-settings__panel {
    padding: 16px;
  }

  .fb-settings__rows,
  .fb-settings__limits {
    grid-template-columns: minmax(0, 1fr);
  }

  .fb-settings__rows {
    gap: 4px;
  }

  .fb-settings__foot {
    padding: 8px 16px;
  }
}

/* ------------------------------------------------------ the degraded-mode banner */
/* Over the top edge of the canvas, never pushing the four-region layout: the editor keeps its
   size while the server is away. Surface, a decorative rule, and the status colour only on the
   square — a calm notice, not an alarm. The menu bar's save indicator says the state itself. */

.fb-banner {
  position: absolute;
  z-index: 40;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 4px 6px 4px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-md, 12px);
}

.fb-banner__mark {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  background: var(--warn);
}

.fb-banner__text {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}

.fb-banner .btn {
  flex: 0 0 auto;
}

/* ==========================================================================
   The phone (docs/DESIGN.md §9), built by js/mobile.js. Below 760px the desktop shell gives way to
   a dark header bar, the tabs Canvas · Outline · Score, the canvas with a bottom tool bar, and the
   property sheet as a bottom sheet. Every target is 44px; no text is smaller than 11px outside the
   drawing; the safe-area insets are respected (index.html asks for viewport-fit=cover).
   ========================================================================== */

.fb-phone {
  display: none;
}

@media (max-width: 759.98px) {
  /* What only the desktop shows (a scorecard's results in its sheet: the phone's Score tab has them). */
  .fb-desktop-only {
    display: none !important;
  }

  /* Your data ▸ Legal: a finger's target (DESIGN §9) — one link a row, 44px tall. */
  .fb-settings__legal {
    flex-direction: column;
    gap: 0;
  }

  .fb-settings__legal-link {
    min-height: 44px;
  }

  :root {
    --tree-w: 0px;
    --sheet-w: 0px;
    --mhead-h: 48px;
    --mtabs-h: 44px;
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    /* The canvas strip left above an open sheet: enough to see the selected card. */
    --msheet-gap: 136px;
  }

  .fb-app {
    min-width: 0;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: calc(var(--mhead-h) + var(--safe-top)) var(--mtabs-h) minmax(0, 1fr) auto auto;
    grid-template-areas:
      "mhead"
      "mtabs"
      "main"
      "mpeek"
      "mbar";
  }

  .fb-app > .fb-menubar,
  .fb-app > .fb-toolstrip,
  .fb-app > .fb-tree,
  .fb-app > .fb-cmdline {
    display: none;
  }

  /* Anything typed on a phone is 16px: a smaller field makes Safari zoom the page on focus. */
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  input[type="search"],
  input[type="date"],
  select,
  textarea {
    font-size: 16px;
  }

  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  input[type="search"],
  input[type="date"],
  select {
    height: 44px;
  }

  .btn {
    min-height: 44px;
    font-size: 14px;
  }

  .btn-icon {
    min-width: 44px;
  }

  /* Every dialog button is a 44px target, whatever it is on the desktop (the auth screens' 32 and
     34px ones included), and the password meter's caption is no smaller than 11px. */
  .fb-modal :is(.btn, .btn-block) {
    min-height: 44px;
  }

  .fb-auth input.fb-auth-code {
    font-size: 16px;
  }

  .fb-settings__skel-button {
    width: 136px;
    height: 44px;
  }

  .fb-segmeter__caption {
    font-size: 11px;
  }

  /* The Share dialog (docs/SHARING.md §12): the columns stack, the switches are 20px squares with
     14px words, and the small print is no smaller than 11px. */
  .fb-share__top {
    grid-template-columns: minmax(0, 1fr);
  }

  /* The two segments share the width at 44px (docs/COMMENTS.md §11). */
  .fb-share__kinds {
    align-self: stretch;
    display: flex;
  }

  .fb-share__kinds > button {
    flex: 1 1 0;
    justify-content: center;
    min-height: 42px;
    font-size: 14px;
  }

  .fb-share__choice {
    min-height: 64px;
  }

  .fb-share__choice-title {
    font-size: 15px;
  }

  .fb-share__choice-hint {
    font-size: 13px;
  }

  .fb-share__choice-kind {
    display: none;
  }

  .fb-share__switch {
    grid-template-columns: 20px minmax(0, 1fr);
  }

  .fb-share__switch > input[type="checkbox"] {
    width: 20px;
    height: 20px;
  }

  .fb-share__switch > input[type="checkbox"]:checked::after {
    left: 6px;
    top: 2px;
    width: 5px;
    height: 10px;
  }

  .fb-share__switch-label {
    font-size: 14px;
    line-height: 20px;
  }

  .fb-share__switch-aside > .btn-link {
    font-size: 14px;
  }

  /* Comments (docs/COMMENTS.md §32.1): the label on its own line, the three segments the full width
     at 44px — at 375px the three Russian words fit in three thirds at 13px. */
  .fb-share__comments {
    flex-direction: column;
    align-items: stretch;
  }

  .fb-share__comments-seg {
    display: flex;
  }

  .fb-share__comments-seg > button,
  .fb-share__comments-seg > .fb-skel {
    flex: 1 1 0;
    justify-content: center;
    min-width: 0;
    min-height: 42px;
    padding: 0 4px;
    font-size: 13px;
  }

  /* A link's scenarios (§7.3): the select at 44px, each box a 44px row. */
  .fb-share__scen-list {
    grid-template-columns: minmax(0, 1fr);
  }

  .fb-share__scen > .fb-share__hint {
    white-space: normal;
  }

  .fb-share__scen-select,
  .fb-modal-body .fb-share__scen-select {
    min-height: 44px;
    height: 44px;
    font-size: 16px;
  }

  .fb-share__scen-item {
    min-height: 44px;
  }

  .fb-share__scen-item > label {
    font-size: 14px;
    line-height: 44px;
  }

  .fb-share__note-x,
  .fb-share__alias-x {
    width: 44px;
    min-width: 44px;
    height: 44px;
    min-height: 44px;
  }

  .fb-share__pw,
  .fb-share__ask,
  .fb-modal-body p.fb-share__warn {
    margin-inline-start: 0;
  }

  .fb-share__head {
    flex-wrap: wrap;
    row-gap: 4px;
  }

  .fb-share__preview {
    width: 100%;
    max-width: 360px;
    height: auto;
    aspect-ratio: 1200 / 630;
  }

  .fb-share__hint,
  .fb-modal-body p.fb-share__hint,
  .fb-heat__month,
  .fb-heat__days > span {
    font-size: 11px;
  }

  .fb-share__lang {
    height: 32px;
    min-height: 32px;
    font-size: 11px;
  }

  .fb-modal-body .fb-share__lang {
    min-height: 32px;
  }

  .fb-share__url {
    font-size: 16px;
  }

  /* Copy and Post on LinkedIn share their line half and half. */
  .fb-share__linkrow > .btn {
    flex: 1 1 calc(50% - 3px);
  }

  /* The skeletons keep the phone's sizes of what they stand for (P1 review): the 44px link field
     and primary button, the 20px switch squares, the preview the column wide at 1200:630 under a
     32px language select. The ghost buttons and the words take the phone's rules themselves. */
  .fb-share__skel-url {
    height: 44px;
  }

  .fb-share__skel-box {
    width: 20px;
    height: 20px;
    margin-top: 0;
  }

  .fb-share__skel-lang {
    height: 32px;
  }

  .fb-share__skel-preview {
    width: 100%;
    max-width: 360px;
    height: auto;
    aspect-ratio: 1200 / 630;
  }

  .fb-share__skel-primary {
    height: 44px;
  }

  /* A figure is 36px on a phone: its number's line is a pixel taller. */
  .fb-share__skel-figure {
    margin-bottom: 3px;
  }

  /* The conversions always take the next line: the rule becomes the break between the two. */
  .fb-share__figures {
    column-gap: 20px;
  }

  .fb-share__figures-rule {
    flex-basis: 100%;
    height: 0;
    margin-block: -4px;
    background: none;
  }

  .fb-share__meta {
    flex-basis: 100%;
  }

  .fb-modal-foot:has(.fb-share__meta) {
    flex-wrap: wrap;
  }

  .fb-share__export-row > .btn {
    flex: 1 1 calc(50% - 3px);
  }

  /* ------------------------------------------------------------ header */

  .fb-mhead {
    grid-area: mhead;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding: var(--safe-top) calc(4px + var(--safe-right)) 0 calc(16px + var(--safe-left));
    background: var(--chrome);
    color: var(--chrome-title);
  }

  /* The way back to the Boards page: the ‹, a 44px target that starts at the edge. */
  .fb-mhead__boards {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 44px;
    margin-left: -12px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--chrome-title);
    cursor: pointer;
  }

  .fb-mhead__boards .fb-ico {
    width: 14px;
    height: 14px;
    stroke-width: 1;
  }

  .fb-mhead__boards:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--chrome-title);
  }

  /* The funnel's name over the save indicator (§9, §4.1). The name renames; its hit area is the
     whole 44px block (the ::after), the line under it is only a label. */
  .fb-mhead__doc {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    min-width: 0;
    height: 44px;
  }

  .fb-mhead__name {
    min-width: 0;
    height: 22px;
    padding: 0;
    overflow: hidden;
    border: 0;
    background: transparent;
    color: var(--chrome-title);
    font: 600 15px/22px var(--font);
    text-align: left;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
  }

  .fb-mhead__name::after {
    content: '';
    position: absolute;
    inset: 0;
  }

  /* The menu bar's save indicator, at the phone's smallest text size; the scenario, when it is not
     Base, before it in the title colour — it says what every edit changes. */
  .fb-mhead__save {
    min-width: 0;
    font-size: 11px;
    pointer-events: none;
  }

  /* The scenario's name gives way before the time does (fitSave): it shrinks with an ellipsis only
     once the save words are down to the square and the time, which do not shrink. */
  .fb-mhead__scenario {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    color: var(--chrome-title);
    text-overflow: ellipsis;
  }

  .fb-mhead__scenario[hidden] {
    display: none;
  }

  .fb-mhead__save-text {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .fb-mhead__save-text.is-short {
    flex-shrink: 0;
  }

  .fb-mhead__end {
    flex: 0 0 auto;
    display: flex;
  }

  .fb-mhead__btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--chrome-title);
    cursor: pointer;
  }

  .fb-mhead__btn:disabled {
    color: var(--chrome-muted);
    cursor: default;
  }

  .fb-mhead__btn .fb-ico {
    width: 18px;
    height: 18px;
  }

  /* Drawn at 16-18px a 12-unit glyph's 1.3 would render near 2px: thinned to about 1.5px, the
     weight the design draws its phone bars in. Undo stays on its own 16-unit grid. */
  .fb-mhead__btn .fb-ico:not([data-icon='undo']),
  .fb-mbar__btn .fb-ico,
  .fb-mbar__plus .fb-ico,
  .fb-msheet__close .fb-ico,
  .fb-insert-row .fb-ico {
    stroke-width: 1;
  }

  .fb-mhead__btn:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--chrome-title);
  }

  .fb-mhead__name:focus-visible {
    outline: none;
  }

  .fb-mhead__name:focus-visible::after {
    box-shadow: inset 0 0 0 1px var(--chrome-title);
  }

  /* -------------------------------------------------------------- tabs */

  /* As many equal columns as there are tabs: Canvas · Outline · Score · Model in the editor, the
     first three on a share link (a hidden tab takes no column). */
  .fb-mtabs {
    grid-area: mtabs;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    border-bottom: 1px solid var(--line);
    background: var(--band);
  }

  .fb-mtabs__tab {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-width: 0;
    height: 44px;
    padding: 0 6px;
    border: 0;
    background: transparent;
    color: var(--text-2);
    font: 400 14px/1 var(--font);
    white-space: nowrap;
    cursor: pointer;
  }

  /* The active tab's 2px ink rule is on its BOTTOM edge (the owner, 2026-10-02), as on the sheet's
     own tabs: it stands on the panel it opens. */
  .fb-mtabs__tab[aria-selected='true'] {
    background: var(--surface);
    color: var(--ink);
    font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--ink);
  }

  .fb-mtabs__tab:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  .fb-mtabs__tab[aria-selected='true']:focus-visible {
    box-shadow: inset 0 -2px 0 var(--ink), inset 0 0 0 1px var(--accent);
  }

  /* ----------------------------------------------------------- canvas */

  .fb-app > .fb-main {
    grid-area: main;
  }

  .fb-app[data-mtab='outline'] > .fb-main,
  .fb-app[data-mtab='score'] > .fb-main,
  .fb-app[data-mtab='model'] > .fb-main {
    visibility: hidden;
  }

  /* No title block on a phone (the design draws none), whatever the desktop chose: the drawing
     takes it all. */
  .fb-app .fb-canvas.is-titleblock .fb-titleblock {
    display: none;
  }

  /* The zoom: the percentage and Fit in the upper right (pinch zooms; − and + are the fingers'),
     under the canvas banner while one shows (--fb-banner-h, js/app.js mountBanner) — never behind it. */
  .fb-app .fb-zoomctl {
    top: calc(10px + var(--fb-banner-h, 0px));
    right: calc(10px + var(--safe-right));
    bottom: auto;
    left: auto;
  }

  .fb-app .fb-zoomctl-step,
  .fb-app .fb-zoomctl-key {
    display: none;
  }

  .fb-app .fb-zoomctl .fb-zoomctl-field {
    width: 64px;
    height: 44px;
    margin: 0 -1px 0 0;
    /* Typed into: 16px, or Safari zooms the page on focus. */
    font-size: 16px;
  }

  .fb-app .fb-zoomctl-fit {
    min-width: 44px;
    height: 44px;
    margin-left: 0;
  }

  .fb-app .fb-canvas-hint {
    top: auto;
    bottom: 10px;
    left: 10px;
    right: 10px;
    max-width: none;
    transform: none;
  }

  .fb-app .fb-banner {
    z-index: 9;
  }

  /* The Link tool's banner: what to tap, over the top of the canvas, in the accent (the active
     state); a refused tap in --danger. */
  .fb-mlink {
    position: absolute;
    z-index: 9;
    top: calc(10px + var(--fb-banner-h, 0px));
    left: calc(10px + var(--safe-left));
    right: calc(10px + var(--safe-right));
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 52px;
    padding: 4px 4px 4px 12px;
    border: 1px solid var(--accent);
    background: var(--surface);
    color: var(--ink);
    font-size: 14px;
    line-height: 1.3;
  }

  .fb-mlink.is-refused {
    border-color: var(--danger);
  }

  /* The desktop's Link to… prompt: the phone says it in its own banner above. */
  .fb-linkprompt {
    display: none;
  }

  .fb-mlink__text {
    flex: 1 1 auto;
    min-width: 0;
  }

  .fb-mlink__cancel {
    flex: 0 0 auto;
  }

  .fb-node.is-link-source {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent);
  }

  /* ----------------------------------------------------------- handle */

  /* While something is selected: a 44px handle that says what it does, «Properties ˄», and opens
     the sheet — no code, name or figure (the selected card above shows them, §1.8). Nothing
     selected, or the Link tool waiting: none, and the canvas has the height. */
  .fb-app[data-mtab='canvas'] > .fb-mpeek:not([hidden]) {
    grid-area: mpeek;
    display: flex;
  }

  .fb-mpeek {
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 44px;
    margin: 0;
    padding: 0 calc(12px + var(--safe-right)) 0 calc(12px + var(--safe-left));
    border: 0;
    border-top: 1px solid var(--ink);
    background: var(--surface);
    color: var(--ink);
    font: 500 14px/1 var(--font);
    cursor: pointer;
  }

  .fb-mpeek:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  .fb-mpeek__open {
    display: flex;
  }

  /* ------------------------------------------------------- bottom bar */

  .fb-app[data-mtab='canvas'] > .fb-mbar {
    grid-area: mbar;
    display: grid;
  }

  .fb-mbar {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    align-items: stretch;
    padding: 6px calc(8px + var(--safe-right)) calc(6px + var(--safe-bottom)) calc(8px + var(--safe-left));
    background: var(--chrome);
    color: var(--chrome-text);
  }

  .fb-mbar__btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 0;
    min-height: 48px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--chrome-text);
    font: 400 11px/1 var(--font);
    cursor: pointer;
  }

  .fb-mbar__btn .fb-ico {
    width: 18px;
    height: 18px;
  }

  .fb-mbar__btn[aria-pressed='true'],
  .fb-mbar__btn[aria-expanded='true'] {
    color: var(--chrome-title);
    box-shadow: inset 0 -2px 0 var(--chrome-title);
  }

  .fb-mbar__slot {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* ＋ is the one filled control of the bar: on the dark bar its fill is the light chrome button
     (ink on --chrome would not show) — DESIGN.md §12. */
  .fb-mbar__plus {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    background: var(--chrome-button);
    color: var(--chrome-button-text);
    cursor: pointer;
  }

  .fb-mbar__plus .fb-ico {
    width: 18px;
    height: 18px;
  }

  .fb-mbar__btn:focus-visible,
  .fb-mbar__plus:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--chrome-title);
  }

  .fb-mbar__plus:focus-visible {
    box-shadow: inset 0 0 0 2px var(--chrome-button-text);
  }

  /* ----------------------------------------------------------- outline */

  .fb-app[data-mtab='outline'] > .fb-moutline,
  .fb-app[data-mtab='score'] > .fb-mscore,
  .fb-app[data-mtab='model'] > .fb-mmodel {
    grid-area: main;
    display: flex;
  }

  .fb-moutline,
  .fb-mscore {
    flex-direction: column;
    min-height: 0;
    padding-bottom: var(--safe-bottom);
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface);
  }

  .fb-moutline__head {
    position: sticky;
    z-index: 1;
    top: 0;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 32px;
    padding: 0 calc(14px + var(--safe-right)) 0 calc(14px + var(--safe-left));
    border-bottom: 1px solid var(--line-mid);
    background: var(--surface-2);
    font-size: 11px;
  }

  .fb-moutline__list {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .fb-moutline__item.is-apart {
    border-top: 1px solid var(--line);
    margin-top: 12px;
  }

  .fb-orow {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 52px;
    margin: 0;
    padding: 6px calc(14px + var(--safe-right)) 6px calc(14px + var(--safe-left) + var(--depth, 0) * 12px);
    border: 0;
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
    /* A long press opens the row's own menu (§9): no callout or text selection over it. */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
  }

  /* The guide from the parent: a vertical rule at its depth and a tick into the row. */
  .fb-orow.is-child::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(14px + var(--safe-left) + (var(--depth, 1) - 1) * 12px + 3px);
    border-left: 1px solid var(--line);
  }

  .fb-orow.is-child::after {
    content: '';
    position: absolute;
    top: 50%;
    left: calc(14px + var(--safe-left) + (var(--depth, 1) - 1) * 12px + 3px);
    width: 7px;
    border-top: 1px solid var(--line);
  }

  .fb-orow:hover {
    background: var(--hover);
  }

  .fb-orow.is-selected {
    background: var(--select);
    box-shadow: inset 2px 0 0 var(--accent);
  }

  .fb-orow:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  .fb-orow__tag {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border: 1px solid var(--fb-swatch, var(--line-ui));
    background: var(--fb-swatch, transparent);
  }

  /* A scorecard with no tag of its own is ink, as its card's rule is. */
  .fb-orow__tag[data-color='ink'] {
    border-color: var(--ink);
    background: var(--ink);
  }

  .fb-orow__main {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }

  .fb-orow__meta {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    font: 500 11px/1 var(--mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .fb-orow:hover .fb-orow__meta,
  .fb-orow.is-selected .fb-orow__meta {
    color: var(--text-2);
  }

  .fb-orow__rate {
    padding: 1px 3px;
    border: 1px solid var(--line);
    color: var(--ink);
    text-transform: uppercase;
  }

  /* The wait after the rate (format 9) in the canvas tag's case and colour: `10% · 0–115 d`. */
  .fb-orow__wait {
    color: var(--text-2);
    text-transform: none;
  }

  .fb-orow.is-selected .fb-orow__code {
    color: var(--accent);
  }

  .fb-orow__name {
    overflow: hidden;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.25;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .fb-orow.is-ref .fb-orow__name {
    color: var(--text-2);
    font-weight: 400;
  }

  .fb-orow__fig {
    flex: 0 0 auto;
    font: 500 12px/1 var(--mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
  }

  .fb-mempty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding: 28px calc(16px + var(--safe-right)) 28px calc(16px + var(--safe-left));
  }

  .fb-mempty__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
  }

  .fb-mempty__text {
    margin: 0 0 8px;
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.45;
  }

  /* ------------------------------------------------------------- score */

  .fb-mscore__pickrow {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px calc(16px + var(--safe-right)) 0 calc(16px + var(--safe-left));
  }

  .fb-mscore__pick {
    flex: 1 1 auto;
    min-width: 0;
  }

  .fb-mscore__head {
    flex: 0 0 auto;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 14px calc(16px + var(--safe-right)) 10px calc(16px + var(--safe-left));
  }

  .fb-mscore__title {
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font-size: 18px;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .fb-mscore__code {
    flex: 0 0 auto;
    color: var(--accent);
    font: 500 11px/1 var(--mono);
    letter-spacing: 0.04em;
  }

  .fb-mscore__body {
    flex: 1 0 auto;
  }

  .fb-panel.is-scorecard-view {
    height: auto;
  }

  .fb-panel.is-scorecard-view > .fb-panel-head,
  .fb-panel.is-scorecard-view > .fb-sheet-id {
    display: none;
  }

  .fb-panel.is-scorecard-view > .fb-panel-body {
    overflow: visible;
  }

  /* ------------------------------------------------------ bottom sheet */

  .fb-app > .fb-inspector {
    position: fixed;
    z-index: 200;
    top: calc(var(--safe-top) + var(--mhead-h) + var(--mtabs-h) + var(--msheet-gap));
    right: 0;
    bottom: 0;
    left: 0;
    display: none;
    padding: 0 var(--safe-right) var(--safe-bottom) var(--safe-left);
    border-top: 1.5px solid var(--ink);
    border-left: 0;
    background: var(--surface);
    will-change: transform;
  }

  .fb-app.is-sheet-open > .fb-inspector {
    display: flex;
  }

  .fb-mscrim {
    position: fixed;
    z-index: 190;
    top: calc(var(--safe-top) + var(--mhead-h));
    right: 0;
    bottom: 0;
    left: 0;
    background: var(--overlay);
  }

  .fb-app.is-sheet-open > .fb-mscrim {
    display: block;
  }

  /* The Model tab (§9): the scenario list and the model settings at the tab's full height, as the
     Outline and the Score tabs stand in the canvas's place. */
  .fb-mmodel {
    flex-direction: column;
    min-height: 0;
    padding: 0 var(--safe-right) var(--safe-bottom) var(--safe-left);
    background: var(--surface);
  }

  /* The sections scroll (the panel's own body). */
  .fb-mmodel__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .fb-mmodel .fb-panel-body {
    overscroll-behavior: contain;
  }

  /* The scenarios as a radio list: 44px rows, the tree's square radio and how much each changes.
     Which one the scorecard compares with is the Score tab's Compare with (§1.8, §7.3). */
  .fb-mscen {
    margin-top: 10px;
    border: 1px solid var(--line);
  }

  .fb-mscen__row {
    display: flex;
    align-items: stretch;
    min-width: 0;
    border-bottom: 1px solid var(--line-soft);
  }

  .fb-mscen__row:last-child {
    border-bottom: 0;
  }

  .fb-mscen__pick {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    min-height: 44px;
    padding: 0 12px;
    border: 0;
    background: transparent;
    color: var(--ink);
    font: 400 14px/1.2 var(--font);
    text-align: left;
    cursor: pointer;
  }

  .fb-mscen .fb-scen__radio {
    width: 12px;
    height: 12px;
  }

  .fb-mscen .fb-scen__radio.is-on {
    box-shadow: inset 0 0 0 2.5px var(--surface);
  }

  .fb-mscen__row.is-active .fb-mscen__pick {
    font-weight: 600;
  }

  .fb-mscen__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .fb-mscen__count {
    flex: 0 0 auto;
    color: var(--muted);
    font: 500 11px/1 var(--mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .fb-mscen__pick:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  /* New scenario across, Rename… and Delete… (of the one in effect) side by side under it: three
     in a row do not fit the Russian Rename… at 360px. */
  .fb-mscen__tools {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    margin-top: 8px;
  }

  .fb-mscen__tools .btn {
    justify-content: center;
    min-width: 0;
    padding: 0 8px;
  }

  .fb-mscen__tools .fb-mscen__new {
    grid-column: 1 / -1;
  }

  .fb-mscen__new .fb-ico {
    width: 12px;
    height: 12px;
  }

  .fb-msheet {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    justify-content: center;
    height: 28px;
  }

  /* A drag affordance, not a button: × closes the sheet (§9). */
  .fb-msheet__grab {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 50%;
    height: 28px;
    cursor: grab;
    touch-action: none;
  }

  .fb-msheet__handle {
    width: 36px;
    height: 4px;
    background: var(--line);
  }

  .fb-msheet__close {
    position: absolute;
    z-index: 2;
    top: 24px;
    right: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
  }

  .fb-msheet__close .fb-ico {
    width: 16px;
    height: 16px;
  }

  .fb-msheet__close:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-panel {
    min-height: 0;
    flex: 1 1 auto;
  }

  /* The sheet names what it shows, not itself: the PROPERTIES head goes; the name is 20px. */
  :is(.fb-inspector, .fb-mmodel) .fb-panel-head {
    display: none;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-sheet-id {
    padding: 0 60px 12px 16px;
    border-bottom-color: var(--line);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-sheet-id:has(> .fb-tabs) {
    padding-bottom: 0;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-sheet-id__line {
    font-size: 11px;
    line-height: 14px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-sheet-id__name {
    margin-top: 5px;
    font-size: 20px;
    line-height: 26px;
    letter-spacing: -0.01em;
  }

  :is(.fb-inspector, .fb-mmodel) :is(textarea.fb-sheet-id__name-input, .fb-sheet-id__title) {
    font-size: 20px;
    line-height: 26px;
    letter-spacing: -0.01em;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-sheet-id__code {
    font-size: 11px;
    line-height: 26px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-tabs {
    margin-right: -44px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-tab {
    flex: 1 1 0;
    justify-content: center;
    height: 44px;
    padding: 0 6px;
    font-size: 14px;
  }

  /* On the white phone sheet the tabs share its width: the active one is underlined in ink. */
  :is(.fb-inspector, .fb-mmodel) .fb-tab[aria-selected='true'] {
    border-color: transparent;
    border-bottom-color: var(--line);
    background: transparent;
    box-shadow: inset 0 -2px 0 var(--ink);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-tab[aria-selected='true']:focus-visible {
    box-shadow: inset 0 -2px 0 var(--ink), inset 0 0 0 1px var(--accent);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-section-head {
    min-height: 34px;
    padding-left: 16px;
    padding-right: 16px;
  }

  :is(.fb-inspector, .fb-mmodel, .fb-mscore) .fb-section-title {
    font-size: 12px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-section-hint {
    font-size: 11px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-section-body {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* A field: the label left at 14px, the control right, a 56px row. */
  :is(.fb-inspector, .fb-mmodel) .field {
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    min-height: 52px;
  }

  :is(.fb-inspector, .fb-mmodel) .field.is-stacked {
    min-height: 0;
  }

  /* A range: two numbers with their − and + do not fit beside a label, so the label takes its line,
     as the tag swatches' does, and the two ends one line under it — [− 0 +] – [− 21 + d] — sharing
     the sheet's width; the line of what they mean under them. Six digits in each end and the Russian
     per-month unit (five letters) fit on one line at 390px (in English at 375px) only with the ends'
     − and + 40px wide, 44px tall, and the gaps and paddings at 2px: 44px squares clip 330000. */
  :is(.fb-inspector, .fb-mmodel) .field.fb-range-field {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    padding: 8px 0;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range-field > .fb-override-reset {
    align-self: flex-end;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range {
    gap: 2px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range > .fb-input > input {
    width: 0;
    padding: 0 2px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range .fb-step {
    width: 40px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range .fb-unit {
    padding: 2px 4px 0;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-range__dash {
    font-size: 14px;
  }

  :is(.fb-inspector, .fb-mmodel) .field-label {
    margin-bottom: 0;
    font-size: 14px;
    line-height: 18px;
  }

  :is(.fb-inspector, .fb-mmodel) .field.is-stacked .field-label {
    margin-bottom: 6px;
  }

  /* The tag swatches: a 44px target each (§9). Eight 44px slots do not fit beside a label, so
     the row stacks under it (one line from 352px up); the square itself is 24px in the middle of
     its slot, and the slot around it takes the tap. */
  :is(.fb-inspector, .fb-mmodel) .field:has(> .fb-swatches) {
    display: block;
    padding: 8px 0;
  }

  :is(.fb-inspector, .fb-mmodel) .field:has(> .fb-swatches) .field-label {
    margin-bottom: 2px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-swatches {
    display: grid;
    grid-template-columns: repeat(auto-fill, 44px);
    gap: 0;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-swatch {
    position: relative;
    width: 24px;
    height: 24px;
    margin: 10px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-swatch::after {
    content: '';
    position: absolute;
    inset: -11px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-unit,
  :is(.fb-inspector, .fb-mmodel) .fb-override-reset,
  :is(.fb-inspector, .fb-mmodel) .fb-hint {
    font-size: 12px;
  }

  /* Reset to Base is a finger's target like the stepper over it (§9, 44px): the link keeps its
     look, its box is 44px tall and clear of the stepper's box above. */
  :is(.fb-inspector, .fb-mmodel) .fb-override-reset:not([hidden]) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-top: 4px;
    padding: 0 0 0 16px;
  }

  /* Use my data… and Use From–To instead (format 9) are a finger's target as Reset to Base is. */
  :is(.fb-inspector, .fb-mmodel) .fb-takes-actions .btn-link:not([hidden]) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-size: 12px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-takes-actions {
    margin-top: 0;
  }

  /* The steppers (§5): − · value · +, each 44px, inside one --line-ui boundary. */
  :is(.fb-inspector, .fb-mmodel) .fb-input {
    min-height: 44px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-input > input {
    width: 72px;
    min-height: 44px;
    height: 44px;
    padding: 0 8px;
    font-size: 16px;
    font-weight: 500;
    text-align: right;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    padding: 0;
    border: 0;
    background: var(--band);
    color: var(--ink);
    font: 500 18px/1 var(--mono);
    cursor: pointer;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step:first-child {
    border-right: 1px solid var(--line-soft);
  }

  /* − stays first before a leading unit (€ 3000 /mo), which is ordered before the figure. */
  :is(.fb-inspector, .fb-mmodel) .fb-input > .fb-step:first-child {
    order: -2;
  }

  /* A note's kind chips keep the badge's size and take a 44px target (§9) from an ::after. */
  .fb-note-form__head {
    min-height: 44px;
  }

  .fb-note-form__kinds {
    gap: 8px;
  }

  .fb-note-chip {
    font-size: 11px;
  }

  .fb-note-chip::after {
    content: '';
    position: absolute;
    inset: -12px -4px;
  }

  .fb-note-form__ref {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-size: 14px;
  }

  /* Notes and Tasks line up with the sections' 16px, as the design's phone sheets draw them. */
  .fb-inspector .fb-sheet-tab {
    padding: 12px 16px;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step:last-child {
    border-left: 1px solid var(--line-soft);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step:active {
    background: var(--hover);
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step:disabled {
    color: var(--muted);
    cursor: default;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-step:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  /* The field's ring is the field's, not the steppers'. */
  :is(.fb-inspector, .fb-mmodel) .fb-input.has-steps:focus-within:not(:has(> input:focus))::after {
    content: none;
  }

  :is(.fb-inspector, .fb-mmodel) .fb-input.has-steps:focus-within:not(:has(> input:focus)) {
    border-color: var(--line-ui);
  }

  /* No text under 11px outside the drawing (§9): the micro-labels, the scorecard's parts and the
     dialogs' small print step up; key hints (Esc, ↵, ⌘↵) are for a keyboard a phone has not got. */
  .fb-micro,
  .fb-section-hint,
  .fb-reveal,
  :is(.fb-mscore, .fb-inspector) .fb-sc-foot {
    font-size: 11px;
  }

  .fb-modal-esc,
  .fb-kbd {
    display: none;
  }

  /* A lever selects its input: a 44px target on a phone. */
  :is(.fb-mscore, .fb-inspector) .fb-sc-lever {
    min-height: 44px;
  }

  .fb-mscore .fb-sc-card.is-sheet {
    margin: 0 calc(16px + var(--safe-right)) 12px calc(16px + var(--safe-left));
  }

  /* "What should I do?" and the test plan on a phone: 13px names, 12px figures (§9: no text under 11px). */
  :is(.fb-mscore, .fb-inspector) :is(.fb-sc-arow__action, .fb-sc-adv__lead, .fb-sc-adv__result, .fb-sc-head__sub, .fb-sc-plan__lead, .fb-sc-plan__sub, .fb-sc-step__name, .fb-sc-step__rule, .fb-sc-step__state, .fb-sc-step__label, .fb-sc-verdict__text) {
    font-size: 13px;
    line-height: 18px;
  }

  :is(.fb-mscore, .fb-inspector) :is(.fb-sc-arow__change, .fb-sc-arow__unit, .fb-sc-step__top, .fb-sc-step__wait, .fb-sc-step__rate, .fb-sc-step__read, .fb-sc-step__sugg, .fb-sc-step__hint, .fb-sc-step__error, .fb-sc-verdict__money) {
    font-size: 12px;
    line-height: 17px;
  }

  :is(.fb-mscore, .fb-inspector) .fb-sc-stepend {
    font-size: 11px;
  }

  /* The count's fields and the box's buttons are a finger's targets. */
  :is(.fb-mscore, .fb-inspector) input.fb-sc-step__input {
    width: 60px;
    height: 44px;
    font-size: 16px;
  }

  :is(.fb-mscore, .fb-inspector) button.fb-sc-spin__btn {
    width: 40px;
    height: 44px;
    font-size: 16px;
  }

  :is(.fb-mscore, .fb-inspector) .fb-sc-verdict__actions .btn {
    min-height: 44px;
  }

  .fb-mscore .fb-section-head,
  .fb-mscore .fb-section-body{
    padding-left: calc(16px + var(--safe-left));
    padding-right: calc(16px + var(--safe-right));
  }

  /* A finger leaves no hover behind: a tapped tab or row does not stay lit. */
  @media (hover: none) {
    .fb-tab:hover:not([aria-selected='true']),
    .fb-orow:hover:not(.is-selected),
    .fb-insert-row:hover {
      background: transparent;
    }
  }

  /* ---------------------------------------------------- floating parts */

  .fb-toast-host {
    left: calc(16px + var(--safe-left));
    right: calc(16px + var(--safe-right));
    bottom: calc(var(--safe-bottom) + 148px);
    max-width: none;
  }

  .fb-toast {
    font-size: 14px;
  }

  /* An open sheet takes the lower screen: a toast there would cover its first fields, so it shows
     in the dimmed band above. */
  body:has(.fb-app.is-sheet-open, .fb-app.is-comments-open) .fb-toast-host {
    top: calc(var(--safe-top) + var(--mhead-h) + 8px);
    bottom: auto;
  }

  .fb-modal-backdrop {
    padding: calc(8px + var(--safe-top)) calc(8px + var(--safe-right)) calc(8px + var(--safe-bottom)) calc(8px + var(--safe-left));
  }

  .fb-modal {
    max-width: 100%;
    max-height: 100%;
  }

  .fb-modal-head {
    height: 44px;
  }

  .fb-modal-path {
    font-size: 11px;
  }

  .fb-menu {
    max-width: calc(100vw - 8px);
    max-height: calc(100dvh - 8px);
    overflow-y: auto;
  }

  .fb-menu__item {
    min-height: 44px;
    font-size: 14px;
  }

  /* The glyphs grow with the 14px labels (a 1.5px line at the family's weight). */
  .fb-menu__mark {
    width: 14px;
    height: 14px;
  }

  .fb-menu__mark .fb-ico {
    width: 14px;
    height: 14px;
  }

  .fb-menu__hint,
  .fb-menu__head .fb-micro {
    font-size: 11px;
  }

  /* A long press's context menu: key hints are for a keyboard a phone has not got; why an item is
     disabled, the submenu arrow and a value (a count, `meta`) stay. */
  .fb-menu__hint:not(.fb-menu__why):not(.fb-menu__sub):not(.fb-menu__meta):not(.fb-menu__pro) {
    display: none;
  }

  /* The ＋ sheet: the modal docked to the bottom, full width, a 56px row per block type. */
  .fb-modal-backdrop:has(> .fb-insert-sheet) {
    align-items: flex-end;
    padding: calc(8px + var(--safe-top)) 0 0;
  }

  .fb-modal.fb-insert-sheet {
    width: 100%;
    max-width: none;
    border-right: 0;
    border-bottom: 0;
    border-left: 0;
    padding-bottom: var(--safe-bottom);
    box-shadow: none;
  }

  .fb-insert-list {
    margin: 4px 0 0;
    padding: 0;
    list-style: none;
  }

  .fb-insert-row {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    min-height: 56px;
    padding: 6px 4px;
    border: 0;
    border-bottom: 1px solid var(--line-soft);
    background: transparent;
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .fb-insert-row:hover {
    background: var(--hover);
  }

  .fb-insert-row:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 1px var(--accent);
  }

  .fb-insert-row .fb-ico {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
  }

  .fb-insert-row__text {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }

  .fb-insert-row__name {
    font-size: 15px;
    font-weight: 600;
  }

  .fb-insert-row__hint {
    color: var(--text-2);
    font-size: 13px;
  }
}

/* ------------------------------------------------ a share link's viewer */

/* docs/SHARING.md §13: the editor's shell, read-only. No command line (js/shell.js buildCommand says
   why): its row goes, and the canvas takes it. */
.fb-app.is-view-only {
  --cmdline-h: 0px;
}

.fb-app.is-view-only > .fb-cmdline {
  display: none;
}

/* A card on a share link is selected, never dragged (DESIGN §15): its header does not promise a
   grab. The Pan tool and Space held keep their hand. */
.fb-app.is-view-only .fb-canvas:not(.is-pan-tool):not(.is-space-pan):not(.is-panning) .fb-node-header {
  cursor: default;
}

/* The password, gone, error and loading pages: the menu bar over grid paper, nothing of a board —
   no tool strip, no model tree, no property sheet. */
.fb-app.is-viewer-page {
  --strip-h: 0px;
  --tree-w: 0px;
  --sheet-w: 0px;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "menubar"
    "strip"
    "main"
    "cmdline";
}

.fb-app.is-viewer-page > :is(.fb-toolstrip, .fb-tree, .fb-inspector) {
  display: none;
}

.fb-app.is-viewer-page .fb-canvas-ui {
  display: none;
}

/* The page stands on the canvas's own grid paper, the panel in the middle of it. */
.fb-viewer-page {
  position: absolute;
  z-index: 40;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  overflow-y: auto;
}

.fb-viewer-page[hidden] {
  display: none;
}

.fb-viewer-panel {
  width: 400px;
  max-height: none;
}

.fb-viewer-panel .fb-modal-body > .btn-block {
  margin-top: 16px;
}

.fb-viewer-form {
  display: grid;
  gap: 12px;
  margin-top: 16px;
}

.fb-viewer-form .fb-error-box[hidden] {
  display: none;
}

/* A comment mail's "Stop these emails" page (docs/COMMENTS.md §12.4): the page alone, the panel on the
   canvas's grid paper; the editor is never built behind it. */
body.is-unsub > .fb-app {
  display: none;
}

.fb-unsub-page {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  overflow-y: auto;
  background-color: var(--bg);
  background-image:
    linear-gradient(to right, var(--grid-major) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-major) 1px, transparent 1px),
    linear-gradient(to right, var(--grid-minor) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-minor) 1px, transparent 1px);
  background-size: 80px 80px, 80px 80px, 16px 16px, 16px 16px;
}

.fb-unsub-panel .fb-modal-body > :is(.fb-ok-box, .fb-error-box) {
  margin-top: 12px;
}

.fb-unsub-panel .fb-modal-body > .fb-error-box[hidden] {
  display: none;
}

.fb-unsub-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

/* Connecting Claude's consent page (docs/MCP.md, DESIGN §8 "Connect Claude"): the unsubscribe page's
   frame — the paper, one 420px panel. Where the app returns in mono under the title (the part the person
   can trust), what it may do as the entry dialog's + rows, Deny · Allow side by side. The heading takes
   the focus, never Allow (as the conflict dialog's). */
.fb-connect-panel {
  width: 420px;
}

.fb-connect-host {
  margin: 4px 0 12px;
  color: var(--text-2);
  letter-spacing: 0.04em;
}

.fb-connect-can {
  margin-bottom: 12px;
}

.fb-connect-panel .fb-info-box {
  margin-bottom: 12px;
}

/* An app FunnelCAD cannot vouch for (not Claude's host, not this computer): the i box as a warning. */
.fb-connect-panel .fb-connect-warn {
  border-color: var(--warn);
  color: var(--ink);
}

.fb-connect-panel .fb-connect-warn::before {
  content: '!';
  color: var(--warn);
}

/* The name such an app gave itself: a claim, said under where it returns. */
.fb-connect-claim {
  margin: -4px 0 12px;
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.fb-connect-who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  margin: 12px 0 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
  overflow-wrap: anywhere;
}

.fb-connect-panel .fb-modal-body > .fb-error-box {
  margin-top: 12px;
}

.fb-connect-actions {
  margin-top: 16px;
}

.fb-connect-later {
  margin: 12px 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.45;
}

/* Loading: the name and one quiet line on the paper, no frame and no shadow — nothing to act on yet. */
.fb-viewer-panel.is-quiet {
  width: auto;
  border: 0;
  background: transparent;
  box-shadow: none;
}

.fb-viewer-panel.is-quiet .fb-modal-body {
  padding: 0;
  text-align: center;
}

/* An open link's name above it, from the page's meta: the dialog title, on the paper. */
.fb-viewer-panel.is-quiet .fb-modal-title {
  max-width: 480px;
  margin: 0 auto 6px;
}

.fb-viewer-panel.is-quiet .fb-viewer-panel__lead {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* The name is text on a share link: nobody renames it here. */
.fb-doc-title.is-text {
  display: block;
  cursor: default;
}

.fb-doc-title.is-text:hover {
  background: transparent;
}

/* VIEW ONLY on the dark bar: the §5.2 badge in the chrome's words colour; the owner's own link in
   the title colour, which says "this is yours" without a second hue. */
.fb-menubar .fb-viewer-badge {
  color: var(--chrome-text);
}

.fb-viewer-badge.is-owner {
  color: var(--chrome-title);
}

.fb-viewer-badge__short,
.fb-viewer-badge__tight {
  display: none;
}

/* The name keeps its room (js/shell.js fitDoc): the badge's tightest form, at any width. */
.fb-menubar.is-badge-tight .fb-viewer-badge__full,
.fb-menubar.is-badge-tight .fb-viewer-badge__short {
  display: none;
}

.fb-menubar.is-badge-tight .fb-viewer-badge__tight {
  display: inline;
}

@media (max-width: 1099.98px) {
  .fb-menubar .fb-viewer-badge__full {
    display: none;
  }

  .fb-menubar .fb-viewer-badge__short {
    display: inline;
  }
}

.fb-viewer-badge:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--chrome-title);
}

.fb-viewer-badge[hidden],
.fb-save[hidden] {
  display: none;
}

/* A snapshot's brand strip (docs/PLANS.md §6.4): a 28px --chrome bar across the bottom of the canvas
   area, in the page's own grid — its own row under the canvas, between the model tree and the
   property sheet — so it covers nothing. The mark and MADE WITH FUNNELCAD (one link to funnelcad.com),
   and no button: the page's primary action is the menu bar's (docs/SHARING.md §32). Dark in both
   themes, as the menu bar is. js/shell.js buildBrandStrip. */
.fb-brandstrip {
  display: none;
}

.fb-app.has-brandstrip {
  --brandstrip-h: 28px;
  grid-template-rows: var(--menubar-h) var(--strip-h) minmax(0, 1fr) var(--brandstrip-h) var(--cmdline-h);
  grid-template-areas:
    "menubar menubar menubar"
    "strip   strip   strip"
    "tree    main    sheet"
    "tree    brand   sheet"
    "cmdline cmdline cmdline";
}

.fb-app.has-brandstrip > .fb-brandstrip:not([hidden]) {
  grid-area: brand;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 0 8px;
  background: var(--chrome);
  color: var(--chrome-title);
}

.fb-brandstrip__made {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  height: 22px;
  padding: 0 6px 0 4px;
  color: var(--chrome-title);
  font: 500 var(--fs-xs, 10px)/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}

.fb-brandstrip__made > .fb-mark {
  flex: 0 0 auto;
}

.fb-brandstrip__words {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-brandstrip__made:hover {
  background: var(--chrome-hover);
}

.fb-brandstrip__made:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--chrome-title);
}

@media (max-width: 1119.98px) {
  .fb-app.has-brandstrip {
    grid-template-areas:
      "menubar menubar"
      "strip   strip"
      "main    sheet"
      "brand   sheet"
      "cmdline cmdline";
  }
}

/* On a phone the same bar, 44px, above the bottom bar — on every tab, the button on the right. */
@media (max-width: 759.98px) {
  .fb-app.has-brandstrip {
    grid-template-rows: calc(var(--mhead-h) + var(--safe-top)) var(--mtabs-h) minmax(0, 1fr) auto auto auto;
    grid-template-areas:
      "mhead"
      "mtabs"
      "main"
      "mpeek"
      "brand"
      "mbar";
  }

  .fb-app.has-brandstrip > .fb-brandstrip:not([hidden]) {
    min-height: 44px;
    padding: 0 calc(12px + var(--safe-right)) 0 calc(8px + var(--safe-left));
  }

  /* Without the bottom bar (the Score and Outline tabs) the strip is the page's last row. */
  .fb-app.has-brandstrip:not([data-mtab='canvas']) > .fb-brandstrip:not([hidden]) {
    min-height: calc(44px + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
  }

  .fb-brandstrip__made {
    height: 36px;
    font-size: 11px;
  }
}

/* The property sheet of a viewer: every value legible (ink, not the muted disabled text), in the
   recessed read-only cell of §2.1 with a soft line — no control boundary that promises typing. A
   choice shows its answer and does not react to the pointer. */
.fb-app.is-view-only :is(.fb-inspector, .fb-mmodel, .fb-mscore) :is(input, textarea)[readonly] {
  border-color: var(--line-soft);
  background-color: var(--surface-2);
  color: var(--ink);
  cursor: text;
}

.fb-app.is-view-only :is(.fb-inspector, .fb-mmodel, .fb-mscore) :is(input, textarea)[readonly]:focus {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-app.is-view-only :is(.fb-inspector, .fb-mmodel, .fb-mscore) .fb-input:has(> input[readonly]) {
  border-color: var(--line-soft);
  background: var(--surface-2);
}

.fb-app.is-view-only :is(.fb-inspector, .fb-mmodel, .fb-mscore) select:disabled {
  border-color: var(--line-soft);
  background-color: var(--surface-2);
  background-image: none;
  color: var(--ink);
  opacity: 1;
}

/* The name in the sheet's header line stays the heading it looks like. */
.fb-app.is-view-only :is(.fb-inspector, .fb-mmodel) textarea.fb-sheet-id__name-input[readonly] {
  border-color: transparent;
  background: transparent;
  cursor: text;
}

.fb-app.is-view-only .btn-seg > button:disabled {
  cursor: default;
}

.fb-app.is-view-only .btn-seg > button:disabled:not([aria-checked="true"]):hover {
  background: transparent;
}

.fb-app.is-view-only .btn-seg > button:disabled:not([aria-checked="true"]) {
  color: var(--text-2);
}

.fb-app.is-view-only .fb-swatch:disabled {
  cursor: default;
}

.fb-app.is-view-only .fb-swatch:disabled:not([aria-pressed="true"]) {
  opacity: 0.35;
}

.fb-app.is-view-only .fb-swatch:disabled:hover:not([aria-pressed="true"]) {
  border-color: transparent;
}

.fb-app.is-view-only input[type="checkbox"]:disabled {
  cursor: default;
}

/* A task list's tick on a viewer's canvas shows its state and selects the card when pressed. */
.fb-todo-check:disabled {
  color: var(--ink);
  cursor: inherit;
  pointer-events: none;
}

/* A viewer's Notes or Tasks tab with nothing in it says so. */
.fb-sheet-tab__none {
  margin: 12px 0 0;
}

.fb-sheet-tab__none[hidden] {
  display: none;
}

/* The scenarios panel's head on a share link: where + New stands, that the pick is this page's. */
.fb-scen__local {
  color: var(--text-2);
  cursor: default;
}

/* A toast's one action (Duplicate's Add to account / Download .fcad): the Boards page's Undo. */
.fb-toast__action {
  flex: 0 0 auto;
  height: 24px;
  padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--on-ink) 40%, transparent);
  border-radius: 0;
  background: transparent;
  color: var(--on-ink);
  font: 500 var(--fs-md, 12px)/1 var(--font);
  white-space: nowrap;
  cursor: pointer;
}

.fb-toast__action:hover {
  border-color: var(--on-ink);
}

.fb-toast__action:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--on-ink);
}

@media (max-width: 759.98px) {
  /* The viewer's pages on a phone: the header over grid paper; no tabs, no bottom bar. */
  .fb-app.is-viewer-page > :is(.fb-mtabs, .fb-mbar, .fb-mpeek, .fb-moutline, .fb-mscore) {
    display: none !important;
  }

  .fb-app.is-viewer-page {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "mhead"
      "mtabs"
      "main"
      "mpeek"
      "mbar";
  }

  .fb-app.is-viewer-page > .fb-main {
    grid-row: 2 / -1;
  }

  .fb-viewer-page {
    align-items: flex-start;
    padding: 16px;
  }

  .fb-viewer-panel {
    width: 100%;
  }

  .fb-viewer-panel.is-quiet {
    margin-top: 40vh;
  }

  .fb-unsub-page {
    align-items: flex-start;
    padding: 16px calc(16px + var(--safe-right)) 16px calc(16px + var(--safe-left));
  }

  .fb-unsub-panel .btn {
    min-height: 44px;
  }

  .fb-unsub-actions .btn {
    flex: 1 1 auto;
  }

  /* The phone: the panel full width at the top, Allow first and both 44px (DESIGN §11). */
  .fb-connect-panel {
    width: 100%;
  }

  .fb-connect-actions {
    display: flex;
    flex-direction: column-reverse;
  }

  /* The name is text here too; its line under it: VIEW ONLY and when it was updated. */
  .fb-mhead.is-viewer .fb-mhead__name {
    cursor: default;
  }

  .fb-mhead.is-viewer .fb-mhead__name::after {
    content: none;
  }

  .fb-mhead.is-viewer .fb-viewer-badge {
    flex: 0 0 auto;
    padding: 1px 4px;
    color: var(--chrome-text);
    font-size: 9px;
  }

  .fb-mhead.is-viewer .fb-viewer-badge.is-owner {
    color: var(--chrome-title);
  }

  .fb-mbar.is-viewer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The brand where the desktop's stands (docs/SHARING.md §13.8): the mark before the funnel's name;
     on the pages with nothing of a board (.is-page) the lockup, whose words then have the room. */
  .fb-mhead__brand {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    color: var(--chrome-title);
  }

  .fb-mhead.is-viewer:not(.is-page) .fb-mhead__brand .fb-lockup__word,
  .fb-mhead.is-viewer:not(.is-page) .fb-mhead__brand .fb-lockup__cad {
    display: none;
  }

  .fb-mhead.is-viewer:not(.is-page) .fb-mhead__brand .fb-mark {
    margin-right: 0;
  }

  /* The primary action in the header of those pages (Make your own funnel, docs/SHARING.md §32): the
     menu bar's light chrome button, 30px drawn on a
     44px target — the 7px around it is padding the background does not paint (content-box). */
  .fb-mhead__try {
    display: flex;
    align-items: center;
    height: 44px;
    padding: 7px;
    border: 0;
    cursor: pointer;
    background: var(--chrome-button);
    background-clip: content-box;
    color: var(--chrome-button-text);
    text-decoration: none;
  }

  .fb-mhead__try-label {
    padding: 0 10px;
    font: 500 13px/1 var(--font);
    white-space: nowrap;
  }

  /* Focus: a 2px ring in the button's own ink, 1px inside its edge (the 7px band stays --chrome). */
  .fb-mhead__try:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 7px var(--chrome), inset 0 0 0 8px var(--chrome-button), inset 0 0 0 10px var(--chrome-button-text);
  }

  /* The Score and Outline tabs' last row for a viewer signed out: the way to FunnelCAD, a plain button. */
  .fb-mscore__try {
    padding: 16px;
    border-top: 1px solid var(--line);
  }

  .fb-mscore__try .btn {
    min-height: 44px;
    text-decoration: none;
  }

  /* The scorecard's own sheet, one row under its score: what it is on the left, the chevron right. */
  .fb-mscore__settings {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 12px;
    align-items: center;
    width: 100%;
    min-height: 56px;
    margin: 0;
    padding: 8px calc(16px + var(--safe-right)) 8px calc(16px + var(--safe-left));
    border: 0;
    border-top: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .fb-mscore__settings[hidden] {
    display: none;
  }

  .fb-mscore__settings:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent);
  }

  .fb-mscore__settings-label {
    font-size: 14px;
    font-weight: 500;
  }

  .fb-mscore__settings-hint {
    grid-row: 2;
    color: var(--text-2);
    font-size: 12px;
  }

  .fb-mscore__settings-open {
    grid-column: 2;
    grid-row: 1 / span 2;
    display: inline-flex;
    color: var(--text-2);
  }
}

/* ============================================================ comments on a Review link (C3)
   docs/COMMENTS.md §9: the right column's COMMENTS, the composer, a suggestion's value and its exact
   effect, the pins and redlines on the drawing, the sheet's Suggest… and SUGGESTED rows. Ink and
   the one accent; a proposed value is a dashed box, never a colour (E16). */

/* The right column shows PROPERTIES or COMMENTS (§9.3): the panel is kept in the column and the
   sheet steps aside while it shows. */
.fb-inspector.is-comments > :not(.fb-comments) {
  display: none;
}

.fb-comments {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

.fb-comments[hidden],
.fb-cm-composer[hidden],
.fb-cm-head[hidden],
.fb-cm-only[hidden],
.fb-cm-empty[hidden],
.fb-cm-showmore[hidden],
.fb-cm-out[hidden],
.fb-cm-state[hidden],
.fb-cm-frommail[hidden],
.fb-cm-list[hidden],
.fb-cm-bar[hidden],
.fb-cm-body[hidden],
.fb-cm-line[hidden],
.fb-cm-counter[hidden],
.fb-cm-more[hidden],
.fb-cm-new[hidden],
.fb-cm-filters > button[hidden],
.fb-cm-effline[hidden],
.fb-cm-unsaved[hidden],
.fb-cm-combined[hidden],
.fb-cm-combined__body[hidden],
.fb-suggest[hidden],
.fb-redline-row[hidden],
.fb-pin[hidden],
.fb-redline[hidden],
.fb-edge-marks[hidden] {
  display: none;
}

.fb-cm-head .btn-icon {
  width: 22px;
  height: 22px;
  border-color: transparent;
  background: transparent;
}

.fb-cm-head .btn-icon:hover {
  border-color: var(--line-ui);
  background: var(--hover);
}

/* The segments with their counts, and + New. A segment's word stays on one line: where the three
   do not fit beside + New (Russian in the 300–316px column), + New goes under them, at the right. */
.fb-cm-bar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 7px 10px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-cm-bar .fb-cm-new {
  margin-left: auto;
}

.fb-cm-filters > button {
  white-space: nowrap;
  gap: 5px;
  padding: 0 7px;
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-cm-count {
  font-variant-numeric: tabular-nums;
}

.fb-cm-new {
  gap: 5px;
  height: 22px;
  padding: 0 7px;
}

.fb-cm-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.fb-cm-state,
.fb-cm-frommail {
  margin: 0;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

.fb-cm-code {
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* The threads: rows between --line-soft rules, newest activity first. */
.fb-cm-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.fb-cm-thread {
  border-bottom: 1px solid var(--line-soft);
}

.fb-cm-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-md, 12px)/1.35 var(--font);
  text-align: left;
  cursor: pointer;
}

.fb-cm-row:hover {
  background: var(--hover);
}

.fb-cm-row:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-cm-thread.is-open > .fb-cm-row {
  background: var(--surface);
}

.fb-cm-row__top {
  display: flex;
  align-items: baseline;
  gap: 5px;
  min-width: 0;
}

.fb-cm-unread {
  align-self: center;
  background: var(--ink);
}

.fb-cm-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.fb-cm-gone {
  flex: 0 0 auto;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-cm-meta {
  flex: 0 0 auto;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  white-space: nowrap;
}

.fb-cm-value {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
}

.fb-cm-value__text {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

.fb-cm-value .num,
.fb-cm-from,
.fb-cm-arrow {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.fb-cm-arrow {
  color: var(--text-2);
}

/* The one sign of *proposed* (E16): the value in a 1px dashed ink box, never a colour. */
.fb-proposed {
  display: inline-block;
  padding: 0 4px;
  border: 1px dashed var(--ink);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-variant-numeric: tabular-nums;
  line-height: 16px;
  white-space: nowrap;
}

.fb-cm-now {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-cm-first {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  color: var(--ink-2);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fb-cm-first.is-deleted,
.fb-cm-msg__text.is-deleted {
  color: var(--muted);
}

.fb-cm-replies {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
}

/* An opened thread: every message, event lines, the effect, the reply field. */
.fb-cm-open {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 10px 10px;
  background: var(--surface);
}

.fb-cm-msgs {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 8px 0 0;
  border-top: 1px solid var(--line-soft);
  list-style: none;
}

.fb-cm-msg__head {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 20px;
}

.fb-cm-msg .fb-cm-author {
  font-weight: 500;
}

.fb-cm-time,
.fb-cm-edited {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
}

.fb-cm-msg__acts {
  display: inline-flex;
  gap: 2px;
  margin-left: auto;
}

/* Show on board (COMMENTS §32.4): the thread's first line, at its right, before Edit and Delete —
   always in sight, unlike them; a 24px target (44px on a phone). */
.fb-cm-locate {
  flex: 0 0 auto;
  width: 24px;
  min-width: 24px;
  height: 24px;
  min-height: 24px;
  margin-left: auto;
  border-color: transparent;
  background: transparent;
  color: var(--text-2);
}

.fb-cm-locate:hover {
  border-color: var(--line-ui);
  color: var(--ink);
}

.fb-cm-locate + .fb-cm-msg__acts {
  margin-left: 0;
}

.fb-cm-event.has-locate {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* One's own Edit and Delete: out of sight until the message is pointed at or holds the focus, as a
   note's actions are (DESIGN §7.2); they stay in the tab order, and a finger always sees them. */
.fb-cm-msg__act {
  width: 20px;
  height: 20px;
  border-color: transparent;
  background: transparent;
  opacity: 0;
}

.fb-cm-msg:hover .fb-cm-msg__act,
.fb-cm-msg:focus-within .fb-cm-msg__act {
  opacity: 1;
}

.fb-cm-msg__act:hover {
  border-color: var(--line-ui);
}

.fb-cm-msg__act.is-danger {
  color: var(--danger);
}

@media (hover: none) {
  .fb-cm-msg__act {
    opacity: 1;
  }
}

.fb-cm-msg__text {
  margin: 2px 0 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fb-cm-event {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  letter-spacing: 0.04em;
  line-height: 1.4;
  text-transform: uppercase;
}

.fb-cm-replyrow {
  display: flex;
  align-items: flex-end;
  gap: 6px;
}

.fb-cm-reply,
.fb-cm-text {
  display: block;
  width: 100%;
  min-height: 26px;
  resize: none;
  font-size: var(--fs-md, 12px);
  line-height: 18px;
}

.fb-cm-text {
  min-height: 62px;
}

.fb-cm-send {
  flex: 0 0 auto;
  gap: 8px;
}

.fb-cm-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}

.fb-cm-actions.is-start {
  justify-content: flex-start;
}

.fb-cm-post {
  gap: 8px;
}

.fb-cm-ask {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  border: 1px solid var(--line-ui);
  background: var(--surface-2);
}

.fb-cm-ask > p {
  margin: 0;
  color: var(--ink);
}

.fb-cm-ask__actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
}

.fb-cm-own {
  margin: 0;
}

.fb-cm-change {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* The next page of 100 (§8.2): the list's last line. */
.fb-cm-showmore {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
}

.fb-cm-showmore__btn {
  align-self: flex-start;
}

/* Empty and signed out (§9.5). */
.fb-cm-empty {
  padding: 16px 10px;
}

.fb-cm-empty__head {
  margin: 0 0 6px;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.fb-cm-empty__hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.45;
}

.fb-cm-out {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 10px;
}

.fb-cm-out__text {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

.fb-cm-out__actions {
  display: flex;
  gap: 6px;
}

/* The composer (§9.3), at the top of the panel. */
.fb-cm-composer {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 8px 10px 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

/* Where the composer was, once another tab continued with its draft (docs/COMMENTS.md §32.8). */
.fb-cm-elsewhere {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-md, 12.5px);
  line-height: 1.45;
}

.fb-cm-composer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.fb-cm-composer__head h3 {
  margin: 0;
}

.fb-cm-composer__close {
  width: 22px;
  height: 22px;
  border-color: transparent;
  background: transparent;
}

.fb-cm-composer__close:hover {
  border-color: var(--line-ui);
}

.fb-cm-field__k {
  flex: 0 0 44px;
}

.fb-cm-field {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.fb-cm-field select {
  flex: 1 1 auto;
  min-width: 0;
}

.fb-cm-field__v {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-cm-scenario {
  padding: 0;
  border: 0;
}

.fb-cm-counter {
  margin: 0;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  text-align: right;
}

.fb-cm-counter.is-warn {
  color: var(--warn);
}

.fb-cm-suggest {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-md, 12px);
}

.fb-cm-valuerow {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.fb-cm-valuerow .fb-input {
  flex: 1 1 auto;
  min-width: 0;
}

.fb-cm-from {
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  white-space: nowrap;
}

.fb-cm-value.fb-input.is-invalid,
.fb-input.is-invalid {
  border-color: var(--danger);
  box-shadow: inset 0 0 0 1px var(--danger);
}

.fb-cm-line {
  margin: -2px 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-cm-line.is-error {
  color: var(--danger);
}

/* The line under the composer's effect (§32.2): what is pending, *Shown for €290 · Update*, or
   nothing — always its own height, so a commit that fills the table moves nothing below it. */
.fb-cm-effline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 4px;
  min-height: 24px;
  margin-top: -3px;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-cm-effline .fb-effect__computing {
  padding: 0;
}

.fb-cm-update,
.fb-cm-see {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  font-size: var(--fs-sm, 11px);
}

.fb-cm-see {
  color: var(--text-2);
}

/* The composer's way to the combined effect keeps its room while it cannot be used (§32.7). */
.fb-cm-seerow {
  margin: -6px 0 0;
}

.fb-cm-seerow.is-reserved {
  visibility: hidden;
}

/* Change the value's line (§32.2), under Cancel · Save. */
.fb-cm-unsaved {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

/* The figures of a value other than the one typed (§32.2): kept, and dimmed. */
.fb-effect.is-stale .fb-effect__now,
.fb-effect.is-stale .fb-effect__with,
.fb-effect.is-stale .fb-effect__diff,
.fb-effect.is-stale .fb-sc-diff.is-ok,
.fb-effect.is-stale .fb-sc-diff.is-bad {
  color: var(--text-2);
}

/* The combined effect of one's suggestions (§32.7): a disclosure row at the top of the OPEN list. */
.fb-cm-combined {
  margin: 8px 10px 0;
  border-bottom: 1px solid var(--line-soft);
  padding-bottom: 6px;
}

.fb-cm-combined__btn {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-md, 12px);
  text-align: left;
  cursor: pointer;
}

.fb-cm-combined__btn:hover {
  color: var(--accent);
}

.fb-cm-combined__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.fb-cm-combined__chev {
  display: inline-flex;
  flex: none;
  color: var(--text-2);
}

.fb-cm-combined__btn[aria-expanded="true"] .fb-cm-combined__chev {
  transform: rotate(90deg);
}

.fb-cm-combined__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 6px;
}

.fb-cm-combined__items {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm, 11.5px);
}

.fb-cm-combined__items > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px;
  min-width: 0;
}

.fb-cm-combined__note {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-cm-who {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.4;
}

.fb-cm-note {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
}

.fb-cm-badge {
  font-size: var(--fs-xs, 9px);
}

/* The effect of a suggestion (§6.2, §9.4): the Compare table's four rows. A column of 360px and more
   is a table; narrower — the 300–316px panel, a thread in it, a phone's sheet — each figure takes two
   lines, its name, then now → with and the difference, the figures never wrapped. */
.fb-effect {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-soft);
  background: var(--surface);
}

.fb-effect.is-computing .fb-effect__row:not(.is-head) {
  opacity: 0.45;
}

.fb-effect__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto auto;
  align-items: baseline;
  column-gap: 6px;
  padding: 4px 6px;
  border-top: 1px solid var(--line-soft);
  font-size: var(--fs-sm, 11.5px);
}

.fb-effect__row.is-head {
  border-top: 0;
  background: var(--band);
}

.fb-effect__row.is-head > * {
  color: var(--text-2);
}

.fb-effect__head {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.fb-effect__select {
  height: 20px;
  max-width: 100%;
  font-size: var(--fs-xs, 10.5px);
}

.fb-effect__label {
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

.fb-effect__now,
.fb-effect__with,
.fb-effect__diff {
  justify-self: end;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-effect__arrow {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
}

.fb-effect__none,
.fb-effect__computing,
.fb-effect__scenario {
  margin: 0;
  padding: 6px;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

/* Narrow (the default for the panel): the name on its own line, then `now → with   difference`. */
.fb-effect__row:not(.is-head) {
  grid-template-columns: auto auto auto minmax(0, 1fr);
}

.fb-effect__row:not(.is-head) > .fb-effect__label {
  grid-column: 1 / -1;
}

.fb-effect__row:not(.is-head) > .fb-effect__now {
  justify-self: start;
}

.fb-effect__row.is-head {
  grid-template-columns: auto auto auto minmax(0, 1fr);
}

.fb-effect__row.is-head > .fb-effect__head {
  grid-column: 1 / -1;
}

.fb-effect__row.is-head > .fb-effect__diff {
  display: none;
}

.fb-effect__row.is-head > .fb-effect__now {
  justify-self: start;
}

@container (min-width: 360px) {
  .fb-effect__row,
  .fb-effect__row:not(.is-head),
  .fb-effect__row.is-head {
    grid-template-columns: minmax(0, 1fr) 72px 0 80px 84px;
  }

  .fb-effect__row:not(.is-head) > .fb-effect__label,
  .fb-effect__row.is-head > .fb-effect__head {
    grid-column: auto;
  }

  .fb-effect__arrow {
    visibility: hidden;
  }

  .fb-effect__row.is-head > .fb-effect__diff {
    display: block;
  }

  .fb-effect__row:not(.is-head) > .fb-effect__now,
  .fb-effect__row.is-head > .fb-effect__now {
    justify-self: end;
  }

  /* A column's head longer than its figures (the bundle's WITH THESE 3, Russian words) takes a
     second line rather than running into the next column. */
  .fb-effect__row.is-head > .fb-effect__now,
  .fb-effect__row.is-head > .fb-effect__with,
  .fb-effect__row.is-head > .fb-effect__diff {
    align-self: end;
    white-space: normal;
    text-align: right;
  }

  .fb-effect__row.is-head > .fb-effect__head {
    align-self: end;
    white-space: normal;
  }
}

/* The menu bar's Comments (§9.1): an outline --chrome button with its own value; below 1100px the
   glyph and the count, the words still read. */
.fb-comments-btn[aria-pressed="true"] {
  border-color: var(--chrome-title);
  background: var(--chrome-hover);
}

.fb-comments-btn .fb-ico {
  width: 11px;
  height: 11px;
}

.fb-comments-btn__full {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.fb-comments-btn__short {
  display: none;
  font-family: var(--mono);
}

@media (max-width: 1099.98px) {
  .fb-comments-btn__full {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .fb-comments-btn__short:not(:empty) {
    display: inline;
  }
}

/* The Comment tool (§9.2): a target under the pointer gets a 1px dashed accent outline 3px outside
   it — a drop target's look, not a selection's; the paper none. The cursor is `cell`. */
.fb-canvas.is-comment-tool,
.fb-canvas.is-comment-tool .fb-world * {
  cursor: cell;
}

.fb-canvas.is-comment-tool .fb-node:hover,
.fb-canvas.is-comment-tool .fb-edge-chip:hover {
  outline: 1px dashed var(--accent);
  outline-offset: 3px;
}

.fb-canvas.is-comment-tool .fb-edge-hit:hover + .fb-edge {
  color: var(--accent);
  stroke-dasharray: 3 2;
}

/* A pin (§9.6): 16px, ink, the count in mono on-ink — dashed ink on the paper where a proposal is
   among the threads. It hangs off a card's top-right corner, 4px above its outline. */
.fb-pin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-width: 16px;
  height: 16px;
  padding: 0 2px;
  background: var(--ink);
  color: var(--on-ink);
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
}

.fb-pin.is-proposal {
  border: 1px dashed var(--ink);
  background: var(--bg);
  color: var(--ink);
}

.fb-node > .fb-pin {
  position: absolute;
  z-index: 5;
  right: -1px;
  bottom: calc(100% + 4px);
}

/* After a link's rate tag: the dashed tag of a proposed rate and the link's pin. */
.fb-edge-marks {
  display: flex;
  align-items: center;
  gap: 3px;
  transform: translate(0, -50%);
  pointer-events: none;
}

.fb-edge-marks .fb-pin {
  pointer-events: auto;
}

.fb-redline {
  display: inline-block;
  padding: 0 4px;
  border: 1px dashed var(--ink);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 14px;
  white-space: nowrap;
  pointer-events: auto;
}

/* The sheet's Suggest… (§9.1): over the right end of the label cell, out of sight until the row is
   pointed at or holds the focus; and the SUGGESTED redline under a field (§9.6). */
.fb-field-head {
  position: relative;
}

.fb-field-head > .fb-suggest {
  position: absolute;
  top: 50%;
  right: 0;
  height: 18px;
  padding: 0 0 0 6px;
  background: var(--panel);
  font-size: var(--fs-sm, 11px);
  line-height: 18px;
  opacity: 0;
  transform: translateY(-50%);
}

.field:hover .fb-field-head > .fb-suggest,
.fb-field-head > .fb-suggest:focus-visible {
  opacity: 1;
}

/* A finger has no hover: on the phone's sheet a tap on the value opens the composer (§9.1). */
@media (hover: none) {
  .fb-field-head > .fb-suggest {
    display: none;
  }
}

.field > .fb-redline-row {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-sm, 11px);
}

.fb-redline-row__head {
  color: var(--text-2);
}

.fb-redline-row__values {
  display: inline-flex;
  gap: 3px;
}

.fb-redline-row__who {
  color: var(--text-2);
}

.fb-redline-row__open {
  margin-left: auto;
}

/* The gate's line in an app's own browser (§9.7 step 4). */
.fb-auth-inapp {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fb-auth-inapp__text {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
}

@media (max-width: 759.98px) {
  /* The phone's Comments sheet (COMMENTS §36) holds the board's list at full width. */
  .fb-mcomments .fb-comments {
    height: 100%;
  }

  .fb-mcomments .fb-panel-head {
    min-height: 44px;
  }

  .fb-cm-row {
    padding: 12px 16px;
    font-size: 14px;
  }

  .fb-cm-open,
  .fb-cm-composer,
  .fb-cm-bar,
  .fb-cm-empty,
  .fb-cm-state,
  .fb-cm-out {
    padding-left: 16px;
    padding-right: 16px;
  }

  .fb-cm-filters > button,
  .fb-cm-new,
  .fb-cm-composer .btn,
  .fb-cm-open .btn,
  .fb-cm-out .btn {
    min-height: 44px;
  }

  .fb-cm-composer select,
  .fb-cm-composer input:not([type="checkbox"]),
  .fb-cm-composer textarea,
  .fb-cm-open textarea,
  .fb-cm-open input:not([type="checkbox"]) {
    min-height: 44px;
    font-size: 16px;
  }

  /* Suggest a value: the row is the 44px target (its label fills it), the box 20px as the Share
     dialog's switches. A box given the fields' 44px grew into a bar. */
  .fb-cm-suggest {
    min-height: 44px;
    font-size: 14px;
  }

  /* Update, the way to the combined effect and its disclosure: 44px targets on a phone (§32.2,
     §32.7); the effect's line keeps Update's height. */
  .fb-cm-effline,
  .fb-cm-update,
  .fb-cm-see,
  .fb-cm-combined__btn {
    min-height: 44px;
  }

  .fb-cm-update,
  .fb-cm-see,
  .fb-cm-combined__btn {
    font-size: 14px;
  }

  .fb-cm-combined {
    margin-left: 16px;
    margin-right: 16px;
  }

  .fb-cm-suggest > label {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    align-self: stretch;
  }

  .fb-cm-suggest > input[type="checkbox"] {
    width: 20px;
    height: 20px;
  }

  .fb-cm-suggest > input[type="checkbox"]:checked::after {
    left: 6px;
    top: 2px;
    width: 5px;
    height: 10px;
  }

  .fb-cm-composer__close,
  .fb-cm-locate,
  .fb-cm-head .btn-icon {
    width: 44px;
    height: 44px;
  }

  /* The composer as a bottom sheet over a scrim, the block sheet's frame (§9.9). */
  .fb-cm-scrim {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: var(--overlay);
  }

  .fb-cm-sheet {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 61;
    max-height: calc(100% - 96px);
    overflow-y: auto;
    padding-bottom: env(safe-area-inset-bottom, 0);
    border-top: 1.5px solid var(--ink);
    background: var(--surface);
  }

  .fb-cm-sheet .fb-cm-composer {
    border-bottom: 0;
  }

  /* A pin keeps a 44px target around its 16px square. */
  .fb-pin::after {
    content: '';
    position: absolute;
    inset: -14px;
  }

  .fb-pin {
    position: relative;
  }

  .fb-node > .fb-pin {
    position: absolute;
  }
}

@media (max-width: 759.98px) {
  /* The board's whole list of comments (COMMENTS §36; Menu ▸ Comments): a bottom sheet in the block
     sheet's frame — the same ink rule, grab handle and × — from under the tabs, over the scrim. It
     leaves less of the canvas in sight than a block's sheet does: a list wants the height, and the
     board under it is not what it is about. */
  .fb-app > .fb-mcomments {
    position: fixed;
    z-index: 200;
    top: calc(var(--safe-top) + var(--mhead-h) + var(--mtabs-h) + 12px);
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    flex-direction: column;
    padding: 0 var(--safe-right) var(--safe-bottom) var(--safe-left);
    border-top: 1.5px solid var(--ink);
    background: var(--surface);
    will-change: transform;
  }

  .fb-app > .fb-mcomments[hidden],
  .fb-mtabs__tab[hidden] {
    display: none;
  }

  .fb-app.is-comments-open > .fb-mscrim {
    display: block;
  }

  .fb-mcomments__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .fb-mcomments__body > .fb-comments {
    flex: 1 1 auto;
  }

  /* The list's head is the sheet's first line, where the × stands (24px down, 44px wide, 6px in):
     COMMENTS, then its ⋯ left of the ×. */
  .fb-mcomments .fb-cm-head {
    padding-right: 52px;
  }

  /* Something unread: a 6px square on the header's Menu, whose first item is the way to the list. */
  .fb-mhead__btn.has-news {
    position: relative;
  }

  .fb-mhead__btn.has-news::after {
    content: '';
    position: absolute;
    top: 10px;
    right: 7px;
    width: 6px;
    height: 6px;
    background: var(--chrome-title);
  }

  /* The sheet's Comments tab on a phone: the count at the tab's own size; a row that does not fit
     (js/ui.js fitTabs) gives up the tabs' side padding first. */
  .fb-inspector .fb-tab__count {
    font-size: 12px;
  }

  .fb-inspector .fb-tabs.is-snug > .fb-tab {
    padding: 0 2px;
  }

  .fb-inspector .fb-tabs.is-glyph > .fb-tab[data-tab='comments'] {
    flex: 0 0 auto;
    padding: 0 12px;
  }

  .fb-inspector .fb-tab > .fb-ico {
    width: 16px;
    height: 16px;
  }

  .fb-mbar__btn[hidden] {
    display: none;
  }
}

@media (max-width: 759.98px) {
  /* A Review link's bottom bar is three tools: Select · Pan · Comment. The editor's is always five
     equal slots — Select · Pan · ＋ · Link · Comment (the owner, 2026-10-02) — the fifth empty while
     the board has no comments, so ＋ keeps the middle. */
  .fb-mbar.is-viewer:has(> .fb-mbar__btn.is-comment:not([hidden])) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* The Comments tab starts with + Comment (COMMENTS §34): primary, across the tab, 44px. */
  .fb-cm-start {
    flex: 0 0 auto;
    padding: 10px 16px;
    border-bottom: 1px solid var(--line-soft);
  }

  .fb-cm-start .fb-cm-new {
    min-height: 44px;
    font-size: 14px;
  }

  .fb-cm-start .fb-cm-new .fb-ico {
    width: 12px;
    height: 12px;
  }
}

.fb-cm-start[hidden] {
  display: none;
}

/* ============================================================ the owner's comments (C4)
   docs/COMMENTS.md §10: the Comments button left of Share, the panel's ARCHIVED and Suggestions
   only, a suggestion's decision, Block and Remove, the bundle and Blocked people dialogs, the Share
   dialog's Review answers, the Boards page's N NEW and Account settings ▸ Your comments. Ink, the
   one accent, --warn only for a stale or unrecorded line; a proposed value stays a dashed box. */

/* The owner's menu bar keeps the funnel's name readable (js/shell.js fitDoc): after Share, the
   Comments button takes its glyph and count, as below 1100px. */
.fb-menubar.is-comments-short .fb-comments-btn__full {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.fb-menubar.is-comments-short .fb-comments-btn__short:not(:empty) {
  display: inline;
}

/* Suggestions only (§10.1): the owner's check beside the segments. */
.fb-cm-only {
  order: 3;
  flex-basis: 100%;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink-2);
  font-size: var(--fs-sm, 11px);
  white-space: nowrap;
}

.fb-cm-only input {
  margin: 0;
}

.fb-cm-panelask {
  margin: 8px 10px;
}

.fb-cm-panelask[hidden] {
  display: none;
}

.fb-cm-threadmore {
  width: 26px;
  height: 26px;
  margin-left: auto;
}

/* A suggestion to decide (§10.3): its head, the field and the values, the stale line, the effect,
   one primary with Add to scenario ▾ and Reject…. */
.fb-cm-decide {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 8px;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

.fb-cm-decide__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}

.fb-cm-decide__head .fb-micro {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.fb-cm-stale,
.fb-cm-decide__state.is-warn {
  margin: 0;
  color: var(--warn);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.4;
}

.fb-cm-decide__state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
}

.fb-cm-decide__buttons .btn {
  min-height: 26px;
}

.fb-cm-addto {
  gap: 4px;
}

.fb-cm-addto .fb-ico {
  width: 10px;
  height: 10px;
}

/* New scenario from suggestions… (§10.3): the name, the checkbox rows, where it starts, the effect.
   520px: the effect table's four columns and their heads (WITH THESE 3, Russian words) on the
   dialog's body without cutting the scorecard's part number. */
.fb-modal.fb-bundle {
  width: 520px;
}

.fb-bundle .fb-bundle__head {
  display: block;
  margin: 12px 0 4px;
  color: var(--text-2);
}

.fb-bundle__list {
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line-soft);
  list-style: none;
}

.fb-bundle__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  gap: 2px 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--line-soft);
}

.fb-bundle__row > input {
  margin: 0;
}

.fb-bundle__row > p {
  grid-column: 2;
}

.fb-bundle__label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 4px;
  min-width: 0;
  color: var(--ink);
  font-size: var(--fs-md, 12px);
}

.fb-bundle__label .fb-cm-label {
  flex: 0 1 auto;
}

.fb-bundle__label .num,
.fb-bundle__label .fb-cm-arrow {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.fb-bundle__who {
  color: var(--text-2);
}

.fb-modal-body p.fb-bundle__from {
  margin: 10px 0 6px;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
}

.fb-bundle__effect .fb-effect {
  margin: 0;
}

.fb-modal-body .fb-bundle .fb-error-box[hidden],
.fb-bundle .fb-error-box[hidden] {
  display: none;
}

/* Blocked people… (§10.2): a row per person — the name, the date in mono, Unblock. */
.fb-blocked__list {
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line-soft);
  list-style: none;
}

.fb-blocked__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  border-bottom: 1px solid var(--line-soft);
}

.fb-blocked__name {
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  font-weight: 500;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.fb-blocked__date {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10.5px);
}

.fb-blocked__empty {
  padding: 14px 0;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.fb-modal-body p.fb-blocked__status:empty {
  display: none;
}

/* The Share dialog's Replace link… on a Review link (§4.2, §11): two answers, each with its words. */
.fb-share__foot-ask.is-review {
  gap: 6px;
}

.fb-modal-foot .fb-share__foot-ask p.fb-share__ask-title {
  font-weight: 500;
}

.fb-share__answer {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  gap: 10px;
}

.fb-modal-foot .fb-share__answer p.fb-share__hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.35;
}

/* The Boards page's N NEW (§10.5): after SHARED, ink — the page's one statement of the news. */
.fb-lib-badge.is-news {
  border-color: var(--ink);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* Account settings ▸ Your comments (§8.5, E19): the board, where and when, the words themselves. */
.fb-settings__comment {
  gap: 2px;
}

.fb-settings__comment-where {
  color: var(--text-2);
  text-transform: none;
  letter-spacing: 0;
}

.fb-settings__comment-body {
  display: -webkit-box;
  overflow: hidden;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fb-settings__item.is-plain.is-asking > .fb-settings__row-actions {
  grid-column: 1 / -1;
}

/* A checkbox row (Preferences ▸ Email me about comments): the whole row toggles it, through its
   name's label stretched over the row; the box stays on top for its own focus ring. */
.fb-settings__item.is-check {
  position: relative;
}

.fb-settings__item.is-check .fb-settings__row-name {
  cursor: pointer;
}

.fb-settings__item.is-check .fb-settings__row-name::after {
  content: '';
  position: absolute;
  inset: 0;
}

.fb-settings__item.is-check > input[type="checkbox"] {
  z-index: 1;
}

@media (max-width: 759.98px) {
  /* The owner's decisions at 44px on a phone (§10.4). */
  .fb-cm-decide__buttons .btn,
  .fb-cm-threadmore {
    min-height: 44px;
  }

  .fb-cm-threadmore {
    width: 44px;
  }

  .fb-share__answer {
    grid-template-columns: 1fr;
    gap: 4px;
  }

  /* The comment mail's row is a 44px target, its box 20px as the Share dialog's switches. */
  .fb-settings__item.is-check {
    min-height: 44px;
  }

  .fb-settings__item.is-check > input[type="checkbox"] {
    width: 20px;
    height: 20px;
  }

  .fb-settings__item.is-check > input[type="checkbox"]:checked::after {
    left: 6px;
    top: 2px;
    width: 5px;
    height: 10px;
  }
}

/* ------------------------------------------------------------ plans */

/* docs/PLANS.md §8.2: the ONE upgrade dialog — the reason block, the site's three plans as
   DESIGN's cards (square, 1px --line-ui, the account's plan with an ink boundary, the Pro card the
   site's tinted one as --surface-2; no shadow, no tint, no gradient) and one line of truth. */
.fb-modal.fb-plans-dialog {
  width: 680px;
}

.fb-plans {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.fb-plans__reason-row {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.fb-plans__reason-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fb-plans__way {
  flex: 0 0 auto;
}

.fb-plans__bulk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: 10px;
}

/* Turn N live links into snapshots, asked in place (docs/PLANS.md §5.7): the question over its two
   actions, Not now first, the conversion solid --danger (what viewers get changes). */
.fb-plans__ask {
  display: grid;
  gap: 8px;
  flex: 1 1 100%;
}

.fb-plans__ask-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.fb-plans__bulk > .fb-ok-box {
  flex: 1 1 100%;
}

.fb-plans__rule {
  border-top: 1px solid var(--line-soft);
}

.fb-plans__billing {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* SAVE 30%: the site's tag inside the Yearly segment, mono, in the segment's own colour. */
.fb-plans__save {
  padding: 2px 4px;
  border: 1px solid currentColor;
  font-family: var(--mono);
  font-size: var(--fs-xs, 9.5px);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fb-plans__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  align-items: stretch;
}

.fb-plans__card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--line-ui);
  background: var(--surface);
}

.fb-plans__card.is-pro {
  background: var(--surface-2);
}

.fb-plans__card.is-current {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}

.fb-plans__card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-height: 16px;
}

/* The code on the left, CURRENT / TRIAL · N DAYS LEFT / COMING SOON on the right. */
.fb-plans__card-head > .fb-micro {
  margin-inline-end: auto;
}

.fb-plans__name-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
}

.fb-plans__name {
  font-size: var(--fs-lg, 15px);
  font-weight: 600;
  line-height: 1.2;
}

.fb-plans__tag {
  color: var(--text-2);
}

.fb-plans__price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px;
  margin-top: 4px;
}

.fb-plans__amount {
  font-family: var(--mono);
  font-size: var(--fs-2xl, 18px);
  font-weight: 600;
  line-height: 1.1;
}

.fb-plans__per {
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
}

.fb-modal-body p.fb-plans__note {
  color: var(--text-2);
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.35;
}

.fb-plans__items {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.35;
}

.fb-plans__items > li {
  position: relative;
  padding-inline-start: 14px;
}

/* The entry dialog's "+" rows (DESIGN §8): only what exists. */
.fb-plans__items > li::before {
  content: '+';
  position: absolute;
  inset-inline-start: 0;
  color: var(--text-2);
  font-family: var(--mono);
}

/* The founding offer: yearly only — hidden while Monthly is on, keeping its room (the site's). */
.fb-plans__founding {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 4px;
  padding: 8px;
  border: 1px solid var(--ink);
  background: var(--surface);
}

.fb-plans__founding.is-hidden {
  visibility: hidden;
}

.fb-modal-body .fb-plans__founding p {
  font-size: var(--fs-sm, 11.5px);
  line-height: 1.35;
}

.fb-plans__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  margin-top: auto;
  padding-top: 8px;
}

a.btn.fb-plans__cta {
  min-height: 32px;
  padding: 6px 10px;
  text-align: center;
  text-decoration: none;
  white-space: normal;
  line-height: 1.25;
}

a.fb-plans__more {
  align-self: center;
  font-size: var(--fs-sm, 11.5px);
  text-align: center;
}

.fb-plans__out {
  margin-inline-start: 4px;
  font-family: var(--mono);
}

.fb-plans__foot {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fb-modal-body p.fb-plans__truth {
  color: var(--ink-2);
  font-size: var(--fs-md, 12px);
}

.fb-modal-body p.fb-plans__notes {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 16px;
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
}

/* The PRO badge in a menu's shortcut column (docs/PLANS.md §8.1); a shortcut after it follows closely. */
.fb-menu__pro {
  display: inline-flex;
  align-items: center;
}

.fb-menu__pro + .fb-menu__hint {
  margin-left: 6px;
}

/* A dashed PRO after a gated control's label: DESIGN's dashed = not real yet (as LOCAL) — the
   account has no such feature; solid during a trial: this is what Pro adds (docs/PLANS.md §8.1). */
.fb-badge.is-pro {
  color: var(--ink);
}

.fb-badge.is-pro.is-dashed {
  border-style: dashed;
  color: var(--text-2);
}

/* …after a settings section's name (Connected apps): beside the name, the key stays at the end. */
.fb-settings__tab .fb-settings__pro {
  margin-inline-end: auto;
}

/* A PRO badge in a skeleton (the Share dialog's brand row) is a ghost like any other: its outline,
   its word unseen — the badge's own colours above would otherwise win over the skeleton's. */
.fb-skel.is-box.fb-badge.is-pro {
  border-color: transparent;
  color: transparent;
}

@media (max-width: 759.98px) {
  /* A phone: the dialog is the screen, the cards stack with Pro first (§8.2), actions 44px. */
  .fb-modal.fb-plans-dialog {
    width: 100%;
    height: 100%;
  }

  .fb-plans__cards {
    grid-template-columns: 1fr;
  }

  .fb-plans__reason-row {
    flex-direction: column;
    gap: 10px;
  }

  a.btn.fb-plans__cta {
    min-height: 44px;
    font-size: 14px;
  }

  a.fb-plans__more {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  .fb-plans__billing .btn-seg > button {
    min-height: 42px;
  }
}

/* ============================================================ the version history (DESIGN §20)
   VERSION HISTORY in the right column, in PROPERTIES' place as COMMENTS stands there; a bottom sheet
   on a phone. A row is a listbox option: the time and V-number in mono, who, the figure on the right
   in mono with its unit; what changed under it in --text-2; an app's note in mono --muted. The row on
   the canvas is --select-2, as a menu's current item. The bar over the canvas is the banner's, with the
   accent square: a state the person entered, not a warning. */

.fb-inspector.is-history > :not(.fb-history) {
  display: none;
}

.fb-history {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

.fb-history[hidden],
.fb-history__busy[hidden],
.fb-history__unsent[hidden],
.fb-history__state[hidden],
.fb-history__list[hidden],
.fb-history__empty[hidden],
.fb-history__older[hidden],
.fb-history__upgrade[hidden],
.fb-banner__actions[hidden],
.fb-banner__list[hidden],
.fb-banner .btn[hidden],
.fb-mhistory[hidden],
.fb-mhistory-scrim[hidden] {
  display: none;
}

.fb-history__title {
  flex: 1 1 auto;
}

.fb-history__tools {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

.fb-history__head .btn-icon {
  width: 22px;
  height: 22px;
  border-color: transparent;
  background: transparent;
}

.fb-history__head .btn-icon:hover {
  border-color: var(--line-ui);
  background: var(--hover);
}

.fb-history__unsent {
  flex: 0 0 auto;
  margin: 0;
  padding: 6px 10px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--warn);
  font-size: var(--fs-sm, 11px);
}

.fb-history__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.fb-history__state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 12px 10px;
}

.fb-history__day {
  position: sticky;
  z-index: 1;
  top: 0;
  margin: 0;
  padding: 10px 10px 4px;
  background: var(--panel);
}

.fb-history__row {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  column-gap: 8px;
  row-gap: 1px;
  align-items: baseline;
  padding: 5px 10px 6px;
  border-top: 1px solid var(--line-soft);
  color: var(--ink);
  font-size: var(--fs-md, 12px);
  line-height: 16px;
  cursor: pointer;
}

.fb-history__group > .fb-history__day + .fb-history__row {
  border-top: 0;
}

.fb-history__row:hover {
  background: var(--hover);
}

.fb-history__row.is-current {
  background: var(--select-2);
}

.fb-history__row:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.fb-history__time {
  /* A column of its own in every row, so what changed starts at one place: "11:49 AM" is 8 characters. */
  min-width: 8ch;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  white-space: nowrap;
}

.fb-history__num {
  min-width: 3ch;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
}

.fb-history__who {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 6px;
  min-width: 0;
}

.fb-history__whoname {
  overflow: hidden;
  text-overflow: ellipsis;
}

.fb-history__badge {
  align-self: center;
}

.fb-history__fig {
  justify-self: end;
  font-family: var(--mono);
  font-size: var(--fs-sm, 11px);
  font-weight: 500;
  white-space: nowrap;
}

.fb-history__fig.is-none {
  color: var(--muted);
  font-weight: 400;
}

/* What changed: under who, two lines at most; the full sentence is its tooltip and description. */
.fb-history__what {
  grid-column: 3;
  display: -webkit-box;
  overflow: hidden;
  color: var(--text-2);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.fb-history__sub {
  grid-column: 4;
  justify-self: end;
  color: var(--text-2);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  white-space: nowrap;
}

.fb-history__note {
  grid-column: 3 / span 2;
  overflow: hidden;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-xs, 10px);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fb-history__empty {
  margin: 0;
  padding: 10px 10px 14px;
  color: var(--text-2);
  font-size: var(--fs-md, 12px);
  line-height: 1.45;
}

.fb-history__older {
  margin: 8px 10px 12px;
}

.fb-history__foot {
  flex: 0 0 auto;
  margin: 0;
  padding: 8px 10px 10px;
  border-top: 1px solid var(--line-soft);
  color: var(--text-2);
  font-size: var(--fs-sm, 11px);
  line-height: 1.45;
}

/* The bar over the canvas while an earlier version shows (§20.3): the accent square, the words, then
   Restore this version (primary) · Copy as new board · Back to current. No ×: Back is the way out. */
.fb-banner[data-kind="version"] .fb-banner__mark {
  background: var(--accent);
}

.fb-banner__actions {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 6px;
}

.fb-banner__short,
.fb-banner__list {
  display: none;
}

@media (min-width: 760px) {
  /* The desktop's canvas is the window less its columns (660px at a 1280px window, 500px at 1120px):
     the words keep one line of their own width, the buttons go to a line of their own when they do
     not fit beside them, and where even that line is too narrow (the Russian words need 578px) the
     phone's short words stand in. Never one word per line, never a button past the canvas edge. */
  .fb-banner[data-kind="version"] {
    container-type: inline-size;
    flex-wrap: wrap;
    row-gap: 4px;
  }

  .fb-banner[data-kind="version"] .fb-banner__text {
    flex: 1 0 auto;
    max-width: calc(100% - 14px);
  }

  .fb-banner[data-kind="version"] .fb-banner__actions {
    flex: 0 1 auto;
    flex-wrap: wrap;
    margin-left: auto;
  }

  @container (max-width: 589.98px) {
    .fb-banner[data-kind="version"] .fb-banner__full {
      display: none;
    }

    .fb-banner[data-kind="version"] .fb-banner__short {
      display: inline;
    }
  }
}

@media (max-width: 759.98px) {
  /* Two lines under the header: the words with ˅ (the list again), then Restore · Copy · Back, each
     44px and sharing the width — it fits 360px in Russian. */
  .fb-app .fb-banner[data-kind="version"] {
    flex-wrap: wrap;
    gap: 4px 6px;
    padding: 4px 6px 6px 12px;
  }

  .fb-banner[data-kind="version"] .fb-banner__text {
    flex: 1 1 0;
    font-size: 13px;
  }

  .fb-banner[data-kind="version"] .fb-banner__list:not([hidden]) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-color: transparent;
    background: transparent;
  }

  .fb-banner[data-kind="version"] .fb-banner__actions {
    flex: 1 0 100%;
    display: flex;
    gap: 6px;
  }

  .fb-banner[data-kind="version"] .fb-banner__actions .btn {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    justify-content: center;
    font-size: 14px;
  }

  .fb-banner[data-kind="version"] .fb-banner__full {
    display: none;
  }

  .fb-banner[data-kind="version"] .fb-banner__short {
    display: inline;
  }

  /* The sheet (§20.5): the Model sheet's frame — the same top, ink rule, grab handle and × — over the
     list, whose rows are 56px. */
  .fb-app.is-history-open > .fb-mhistory-scrim {
    display: block;
  }

  .fb-app > .fb-mhistory {
    position: fixed;
    z-index: 200;
    top: calc(var(--safe-top) + var(--mhead-h) + var(--mtabs-h) + var(--msheet-gap));
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    flex-direction: column;
    padding: 0 var(--safe-right) var(--safe-bottom) var(--safe-left);
    border-top: 1.5px solid var(--ink);
    background: var(--surface);
  }

  .fb-mhistory .fb-history {
    flex: 1 1 auto;
    height: auto;
  }

  .fb-mhistory .fb-history__head {
    min-height: 44px;
    padding: 0 60px 4px 16px;
    border-bottom-color: var(--line);
  }

  .fb-mhistory .fb-history__title {
    color: var(--ink);
    font-family: var(--font);
    font-size: 20px;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
  }

  .fb-mhistory .fb-history__head .btn-icon {
    width: 44px;
    height: 44px;
  }

  /* The sheet's own × closes it: the panel's is the desktop's. */
  .fb-mhistory .fb-history__close {
    display: none;
  }

  .fb-mhistory .fb-history__day {
    padding: 12px 16px 6px;
    background: var(--surface);
  }

  .fb-mhistory .fb-history__row {
    min-height: 56px;
    align-content: center;
    padding: 8px 16px;
    font-size: 14px;
    line-height: 19px;
  }

  .fb-mhistory .fb-history__time,
  .fb-mhistory .fb-history__num,
  .fb-mhistory .fb-history__fig {
    font-size: 13px;
  }

  .fb-mhistory .fb-history__sub,
  .fb-mhistory .fb-history__note {
    font-size: 12px;
  }

  .fb-mhistory .fb-history__foot {
    padding: 10px 16px 12px;
    font-size: 13px;
  }

  .fb-mhistory .fb-history__upgrade,
  .fb-mhistory .fb-history__older {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

@media (max-width: 759.98px) {
  /* ＋ and Link while an earlier version shows (§20.5): off, and drawn so. */
  .fb-mbar__plus:disabled,
  .fb-mbar__btn:disabled {
    opacity: 0.4;
    cursor: default;
  }
}
