/* Shared components the platform uses beyond fasset-ds: overrides of ds values BB keeps on purpose, the table, lists and pagination, forms, checkboxes, panel spacing.
   Loaded after ds/css/tokens.css and ds/css/app.css; only what fasset-ds
   does not already say lives here. */

:root {
  --cols: minmax(0, 1fr); /* a table sets its own column tracks (js/table.js) */
}

/* ————— buttons — ink pills. Brand color is not chrome. ————— */
.btn {
  gap: var(--space-6);
}
.btn-sm {
  height: var(--control-sm);
}
/* ————— section headers ————— */
/* SPACING, written once (R5-11). Every gap on a screen or in a side sheet is one
   of these, named in css/tokens.css, and a screen does not write its own.

     page         title to subtitle 6 · page head to first section 44
                  section to section 56, with no line: the space separates them
     section      heading row to content 14
     side sheet   padding 24 · header to body 24 · block to block 24 ·
                  the action row 24 above, pinned to the bottom on mobile
     field        label to input 8 · input to hint or error 6 ·
                  field to next field 20 · group of fields to the next 32
     text         paragraph to paragraph 12 · hint or lede to first field 20 ·
                  text to a button 16
     buttons      between buttons 8 · between text actions 16 ·
                  icon to label inside a button 6

   They are written as rules on the components (.section, .panel-body, .field,
   .hint) and as the .stack and .cluster primitives, so a screen reaches for a
   class and never a number. A margin on one element to fix its own spacing is
   what this replaces. */
/* A section sits 36 from the next and its heading 14 from its body, which is the ds's own .section and .section-head and the
   design root's (fasset-biz): nothing here restates them. This file used to halve --rhythm-section around each section (28 below,
   28 more above the next, so 56 between), which no other surface of the product does; the Section primitive in react/ds and the
   spacing leaves in test/functional/design-rules.functional.test.js hold the 36/14. */
/* SECTION ACTIONS, one rule for the whole site (R5-5). Page actions sit right
   of the page title. A section's own button or link sits at the right end of
   its heading row, baseline-aligned with the heading: a lone one needs nothing
   more than being a child of the row, and two go in .section-head-actions.
   Section actions are small buttons (.btn-sm); page actions are regular. New
   sections follow this rather than writing their own margin. */
.section-head > .btn, .section-head > .link, .section-head > .section-head-actions { margin-left: auto; }
.section-head-actions { display: flex; align-items: baseline; gap: var(--space-8); }
/* A disclosure's own control. The system had no rule for one, so it rendered
   at the bare summary's 18px — under the 24px that 2.5.8 asks of a target that
   is not a word inside a sentence, and this one is a block list-item rather
   than inline. The height is the hit area; the marker and the text are
   unchanged. */
summary {
  min-height: 24px;
  padding: 3px 0;
  cursor: pointer;
}
/* A row of text actions: the site's gap between them (R5-9), each with its own
   icon, sitting on the same baseline as the label they belong to. */
.actions-inline { display: inline-flex; align-items: baseline; gap: var(--space-16); }
.detail-head { display: flex; align-items: baseline; justify-content: space-between; padding-block: var(--space-6); }
.status-pending .dot, .status-processing .dot, .status-approved .dot { background: var(--st-warning); }
.status-overdue .dot, .status-failed .dot, .status-rejected .dot, .status-attention .dot { background: var(--st-error); }
/* Neutral: a state that is neither good nor bad nor asking for attention. A
   deposit on its way is the first thing to need one — warning would make an
   ordinary wait look like a problem, and positive would claim it had landed.
   Withdrawn joins it for the same reason: a business pulled its own run back,
   which is not a failure to colour like one. */
.status-neutral .dot, .status-withdrawn .dot { background: var(--st-neutral); }
/* A finished state carries no dot, so the dots left mark what needs a person (Pilgrim's rule, adopted
   2026-10-20). visibility keeps the gap, so every status still starts at the same place. */
.status-completed .dot, .status-paid .dot { visibility: hidden; }
/* An optional second line of context under a status, in plain words. */
.status-stack { display: inline-flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.status-sub { font-size: var(--text-12); color: var(--text-faint); padding-left: var(--space-12); white-space: nowrap; }
/* Status text is neutral, except the two states a person must act on: overdue and failed read in the
   negative colour as well as the red dot (DESIGN.md; confirmed 2026-10-20 over Pilgrim's neutral-words rule). */
.status-overdue, .status-failed { color: var(--negative-text); }
/* A timeline step that failed reads the same way: red dot, red text (a failed collection or payout). */
.timeline-item.failed .timeline-dot { background: var(--st-error); }
/* A step that ended without money moving (rejected, withdrawn, returned): a neutral dot, never the green done dot. */
.timeline-item.ended .timeline-dot { background: var(--text-faint); }
/* Money that never left: the amount is faint on the row and struck through in the panel (FF-07). */
.amount.ended { color: var(--text-faint); }
.struck { color: var(--text-faint); text-decoration: line-through; }
.timeline-item.failed .timeline-label, .timeline-item.failed .timeline-time { color: var(--negative-text); }
/* ————— money-screen primitives —————

   Every one of these replaces an inline style that four screens were repeating
   with drifting values. They are containers rather than per-element margins,
   which is how onboarding.html was rebuilt: the gap does the spacing, so
   nothing inside has to agree with anything else.

   `.page-actions` already carries `gap: 8px`. Accounts' Add money keeps the
   prototype's own `margin-right: 8px` on top of it, so its two buttons sit
   16px apart as fasset-biz's do (1:1 A1, D33); every other screen's sit 8px. */
/* The figure at the top of a panel body: label, amount, sub-line. */
.panel-figure { padding: 0; }
:is(.hint, p) + .panel-figure, .panel-figure + * { margin-top: var(--rhythm-panel); }
/* A heading inside a def-group, above the rows it introduces. */
.def-head { padding: var(--space-6) 0; }
/* A panel's identity block: name over a quiet qualifier. */
.panel-id h2 { margin: 0; }
/* The close sits at the head's far right in every head: the title block takes the room, as a bare h2 already does. */
.panel-head > .panel-id { flex: 1; min-width: 0; }
.panel-id-sub { font-size: var(--text-12); }
/* An empty state standing in for a list rather than filling a panel. */
.empty-inline { padding: var(--space-24) 0; }
/* ————— the shared table (js/table.js, R5B-22) ————— */
.tbl .table-header, .tbl > .row { grid-template-columns: var(--cols); }
.tbl .cell { min-width: 0; }
.tbl .cell:not(.cell-main):not(.amount) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-subtle); font-size: var(--text-13); }
.tbl .row-meta { display: contents; }
@media (min-width: 901px) {
  .tbl > .row .cell { grid-row: 1; }
  .tbl .cell[data-col="1"] { grid-column: 1; }
  .tbl .cell[data-col="2"] { grid-column: 2; }
  .tbl .cell[data-col="3"] { grid-column: 3; }
  .tbl .cell[data-col="4"] { grid-column: 4; }
  .tbl .cell[data-col="5"] { grid-column: 5; }
  .tbl .cell[data-col="6"] { grid-column: 6; }
  .tbl .cell[data-col="7"] { grid-column: 7; }
  .tbl .cell[data-col="8"] { grid-column: 8; }
  .tbl .cell[data-col="9"] { grid-column: 9; }
  .tbl .cell[data-col="10"] { grid-column: 10; }
  .tbl .cell[data-col="11"] { grid-column: 11; }
  .tbl .cell[data-col="12"] { grid-column: 12; }
}
.tbl .row-loading { display: block; }
.skeleton-row { height: 40px; width: 100%; }
/* Waiting bars: the height a bar reserves is a named step, never a number on the element (js/ui.js skeletonRows,
   react/ds/Skeleton.jsx). The steps are the heights the screens already reserved for the rows they wait on. */
:root {
  --skeleton-h-20: 20px;
  --skeleton-h-24: 24px;
  --skeleton-h-26: 26px;
  --skeleton-h-32: 32px;
  --skeleton-h-36: 36px;
  --skeleton-h-40: 40px;
  --skeleton-h-44: 44px;
  --skeleton-h-48: 48px;
  --skeleton-h-52: 52px;
  --skeleton-h-56: 56px;
  --skeleton-h-60: 60px;
  --skeleton-h-70: 70px;
  --skeleton-h-76: 76px;
  --skeleton-h-summary-label: 14px;
  --skeleton-h-summary-figure: 32px;
}
.skeleton-h-20 { height: var(--skeleton-h-20); }
.skeleton-h-24 { height: var(--skeleton-h-24); }
.skeleton-h-26 { height: var(--skeleton-h-26); }
.skeleton-h-32 { height: var(--skeleton-h-32); }
.skeleton-h-36 { height: var(--skeleton-h-36); }
.skeleton-h-40 { height: var(--skeleton-h-40); }
.skeleton-h-44 { height: var(--skeleton-h-44); }
.skeleton-h-48 { height: var(--skeleton-h-48); }
.skeleton-h-52 { height: var(--skeleton-h-52); }
.skeleton-h-56 { height: var(--skeleton-h-56); }
.skeleton-h-60 { height: var(--skeleton-h-60); }
.skeleton-h-70 { height: var(--skeleton-h-70); }
.skeleton-h-76 { height: var(--skeleton-h-76); }
.skeleton-spaced { margin-bottom: var(--space-8); }
.skeleton-summary-label { height: var(--skeleton-h-summary-label); width: 40%; margin-bottom: var(--space-12); }
.skeleton-summary-figure { height: var(--skeleton-h-summary-figure); width: 60%; }
@media (max-width: 900px) {
  .tbl .table-header { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .tbl > .row { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--space-4); padding-block: var(--space-12); }
  .tbl .cell[data-m="main"] { grid-column: 1; grid-row: 1; }
  .tbl .cell[data-m="end"] { grid-column: 2; grid-row: 1; }
  .tbl .cell[data-m="hide"] { display: none; }
  .tbl .row-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-12); grid-column: 1 / -1; grid-row: 2; min-width: 0; }
  .tbl .cell .name { overflow-wrap: anywhere; }
}
.row {
  transition: background var(--dur-1) var(--ease);
}
.panel-back:focus-visible { outline: 1.5px solid var(--focus-ring); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) {
  .panel-view { transition: none; }
}
.panel-head {
  padding: var(--space-16) var(--rhythm-panel);
}
.panel-head-actions { display: flex; align-items: center; gap: var(--space-4); flex-shrink: 0; }
.panel-close, .panel-download {
  color: var(--text-faint);
  padding: var(--space-4);
  border-radius: var(--r-control);
  display: inline-flex;
}
.panel-close:hover, .panel-download:hover { color: var(--text-default); background: var(--bg-selected); }
/* The shared icon button (R5-17): square, ghost, named by its aria-label.
   No hover label: anything a person needs to read is written on the page. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-sm); height: var(--control-sm);
  color: var(--text-faint);
  border-radius: var(--r-control);
}
.icon-btn:hover { color: var(--text-default); background: var(--bg-selected); }
.icon-btn:focus-visible { outline: 1.5px solid var(--focus-ring); outline-offset: 1px; }
.icon-btn:disabled { opacity: .5; cursor: default; }
.panel-body {
  padding: var(--rhythm-panel);
}
/* Block to block inside a sheet is 24: a grouped block (a definition list, a
   table, a card) is set off from what it sits beside by the panel gap, and a
   hint or lede sits 20 above the first field. */
.panel-body > :is(.def-group, .table, .card) + *,
.panel-body > * + :is(.def-group, .table, .card) { margin-top: var(--rhythm-panel); }
.panel-body > :is(.hint, p) + .field { margin-top: var(--rhythm-field); }
.panel-body > .field:last-child { margin-bottom: 0; }
:is(.hint, p) + .btn:not(.btn-ghost) { margin-top: var(--rhythm-body-actions); }
/* That gap is for a button under a paragraph in a column. In a row of
   controls (a panel foot, any actions row or cluster) a refusal or a question
   lands before the buttons and the margin only made the first button taller
   than the rest; the row's own gap spaces them there. */
:is(.panel-foot, .cluster, [class*="actions"], [class*="-foot"]) > :is(.hint, p) + .btn { margin-top: 0; }
:is(.hint, p, .def-group, .table, .stack-actions) + .field { margin-top: var(--rhythm-field); }
:is(.hint, p) + :is(.table, .def-group) { margin-top: var(--rhythm-body-actions); }
/* fasset-ds says this too, but its copy loads before the two rules above and
   would lose to them; two groups in a row sit 12 apart, not a panel gap. */
.def-group + .def-group { margin-top: var(--space-12); padding-top: var(--space-12); }
.panel-foot {
  padding: var(--space-16) var(--rhythm-panel);
  flex-wrap: wrap;
}
/* A foot with nothing to hold draws nothing: no bar, no rule, no padding. */
.panel-foot:empty { display: none; }
/* ————— forms — focus darkens the hairline to ink; no colored glow ————— */
.field {
  margin-bottom: var(--rhythm-field);
}
/* A label is stronger than the hint under the field (R12-15): the label names the
   thing, the hint only helps with it, so they are not the same colour and weight. */
.field-label {
  display: block;
  font-size: var(--text-13);
  color: var(--text-default);
  font-weight: var(--w-medium);
  margin-bottom: var(--rhythm-label);
}
.field label {
  font-size: var(--text-13);
  color: var(--text-default);
  font-weight: var(--w-medium);
  margin-bottom: var(--rhythm-label);
}
.field > .hint, .field > .form-error { margin-top: var(--rhythm-hint); }
/* One paragraph under another is 12 apart (R5-11), a hint or a line of text alike. */
:is(.hint, p) + :is(.hint, p) { margin-top: var(--rhythm-paragraph); }
.field > .hint + .hint { margin-top: var(--rhythm-hint); }
.btn-flush { margin-inline-start: calc(var(--space-8) * -1); }
.option-row-flush { margin: calc(var(--space-4) * -1) calc(var(--space-10) * -1) var(--space-12); }
/* design/bb-pay-run-flow-spec.md §2.4 point 4: an amount field failing its
   row's own limit check gets a hairline, same convention as kyb.css's
   .ob-input[aria-invalid="true"] — this platform app had no equivalent yet
   since nothing on it flagged a single field invalid before this. */
.input[aria-invalid="true"],
.input[aria-invalid="true"]:hover,
.input[aria-invalid="true"]:focus { border-color: var(--negative); }
.input[aria-invalid="true"]:focus { box-shadow: none; }
/* `--text-subtle`, not `--text-faint`. The hint carries every status detail,
   every outcome body, the submit error and the link out of a finished
   application, so it is text somebody has to read rather than decoration —
   and `--text-faint` renders 2.91:1 on the sheet in light and 2.94:1 in dark,
   against AA's 4.5:1 for 12px. `--text-subtle` is 5.33:1 and is already what
   `.page-sub` and `label` use, so this takes a step the page was on anyway
   rather than introducing a value. `--text-faint` keeps the placeholder, which
   is the decorative half of what it was doing. */
.hint {
  color: var(--text-subtle);
}
/* The support reference wherever the dashboard shows one (R5-10): its own
   block under the message, never glued to the end of a wrapped line, the
   reference in mono hint style with a small Copy link beside it. */
.support-reference {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8);
  margin-top: var(--space-8);
  overflow-wrap: anywhere;
  color: var(--text-subtle);
  font-family: var(--font-mono);
  font-size: var(--text-12);
}
.push-end { margin-inline-start: auto; }
.monogram-24 { width: 24px; height: 24px; }
.option-row-static { cursor: default; }
.option-row-amount { margin-left: auto; }
/* The line that introduces the currency choices in Add money (js/screens/money.js PICK_HINT). */
.pick-hint { margin-bottom: var(--space-12); }
.grow { flex: 1; }
.input-affix { position: relative; display: flex; align-items: center; }
.input-affix .input { flex: 1; padding-inline-end: var(--space-56); }
.input-affix .affix { position: absolute; inset-inline-end: var(--space-12); color: var(--text-subtle); pointer-events: none; }
.option-row .opt-name {
  display: block;
}
.option-row .opt-detail {
  display: block;
}
.option-row.active { background: var(--bg-selected); }
.option-list {
  max-height: 240px;
  overflow-y: auto;
  margin-top: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
}
.check-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-8);
  padding: var(--space-12);
  margin-top: var(--space-12);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  color: var(--text-default);
  cursor: pointer;
}
.check-row input { margin-top: var(--space-2); flex: 0 0 auto; }
.check-row .strong,
.check-row .opt-detail { display: block; }
.check-row .opt-detail { margin-top: var(--space-2); font-size: var(--text-12); color: var(--text-subtle); }
.rhythm-tight { margin-top: var(--space-8); }
.rhythm-item { margin-top: var(--rhythm-item); }
.rhythm-actions { margin-top: var(--rhythm-body-actions); }
/* Field rules (js/field-rules.js): the error under its field. */
/* ————— checkbox / radio (bb-design-decisions.md D17) —————
   The prototype's 14px ink box is a plain div with no input behind it, so it
   carries none of a checkbox's own keyboard, focus, label or screen-reader
   behaviour. This re-skins the real input instead of replacing it: it is
   still the native element, so all of that keeps working exactly as it did
   unstyled — only appearance:none plus these rules change what it looks
   like. A `<label>` around the input, the existing pattern everywhere this
   is used, keeps the click target and the accessible name it always had. */
input.checkbox, input.radio {
  appearance: none;
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  margin: 0;
  border: 1px solid var(--border-strong);
  background: var(--input);
  position: relative;
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
input.checkbox { border-radius: 4px; }
input.radio { border-radius: 50%; }
input.checkbox:checked, input.checkbox:indeterminate,
input.radio:checked {
  background: var(--accent);
  border-color: var(--accent);
}
/* A pure-CSS tick: two box edges, rotated into a checkmark. */
input.checkbox:checked::after {
  content: "";
  position: absolute;
  left: 4px; top: 1px;
  width: 4px; height: 7px;
  border: solid var(--on-accent);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
input.checkbox:indeterminate::after {
  content: "";
  position: absolute;
  left: 3px; top: 6px;
  width: 8px; height: 1.5px;
  background: var(--on-accent);
}
input.radio:checked::after {
  content: "";
  position: absolute;
  left: 4px; top: 4px;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--on-accent);
}
input.checkbox:disabled, input.radio:disabled { opacity: 0.5; cursor: default; }
input.checkbox:focus-visible, input.radio:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--text-strong);
}
.list-pagination { container-type: inline-size; padding: var(--space-16) 0; font-size: var(--text-12); color: var(--text-subtle); min-width: 0; }
.list-pagination-layout { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: var(--space-12); }
.list-count { min-width: 0; overflow-wrap: anywhere; }
.list-page { white-space: nowrap; }
.list-page-actions { display: flex; gap: var(--space-8); }
.list-page-actions .icon { display: none; }
.page-size-control { display: flex; align-items: center; gap: var(--space-8); margin: 0; min-width: 0; }
.page-size-label { max-width: 120px; overflow-wrap: anywhere; }
.page-size-control .select { width: 56px; min-width: 56px; height: 32px; padding: 0 var(--space-8); }
@container (max-width: 600px) {
  .list-page-action-label { display: none; }
  .list-page-actions .icon { display: block; }
  .list-page-actions .btn { width: 32px; height: 32px; padding: var(--space-8); }
}
@container (max-width: 380px) {
  .list-pagination-layout { grid-template-columns: minmax(0, 1fr) auto auto; }
  .list-pagination-layout .page-size-control { grid-column: 1 / -1; justify-self: end; }
}
a.seg-btn { text-decoration: none; }
#balance-history-status:empty { display: none; }
/* ————— boot and stop screens —————
   What the page is while it is reaching the service, and what it becomes when
   it cannot. Deliberately not inside .shell: a sidebar around an error is a
   business's own navigation with no business behind it. */
/* `hidden` is an attribute the markup uses to mean gone, and a `display` rule
   silently outranks it: giving .kyb-note `display: flex` put three hidden
   sections of the account-opening page back on screen, and a leaf caught it
   saying a business was being shown an outcome beside a failure to ask.

   Any rule that sets display on something the markup can hide has this. So the
   guard is here, once, rather than beside each of them. */
[hidden] { display: none !important; }
/* ————— ds CodeInput, recovery —————
   ds sizes the host from its cells; a recovery code also has the gap after
   its fourth character (sign-in.css), so the host is that much wider. */
.code-input.is-recovery {
  --code-cells: 8; /* CodeInput also sets the real count on the host */
  width: calc(var(--code-cells) * var(--code-cell-w) + (var(--code-cells) - 1) * var(--code-gap) + var(--space-8));
}

/* ————— selecting rows and sorting a column (Pilgrim comparison, 2026-10-20) —————
   A checkbox column on a list, a bar that takes the toolbar's place while rows are ticked, and sortable
   headers whose arrow sits outside the words so it never moves them. */
.cell-pick { display: grid; place-items: center start; min-width: var(--space-24); min-height: var(--space-24); cursor: pointer; }
.cell-pick input { accent-color: var(--text-strong); width: 15px; height: 15px; margin: 0; cursor: pointer; }
/* A box is hidden at rest and shows on row hover or focus; once one is ticked every box shows, and the master box shows only
   while selecting (BP-11). Hidden is opacity, so the box stays in the tab order and focus reveals it. */
.cell-pick input { opacity: 0; transition: opacity var(--dur-1) var(--ease); }
.row:hover .cell-pick input, .cell-pick input:focus-visible, .cell-pick input:checked, .table:has([data-pick]:checked) .cell-pick input { opacity: 1; }
.row.is-picked { background: var(--bg-selected); }
.bulk-bar { display: flex; align-items: center; gap: var(--space-12); flex-wrap: wrap; min-height: var(--space-32); font-size: var(--text-13); color: var(--text-default); }
.bulk-bar[hidden] { display: none; }
.th-sort { font: inherit; font-size: var(--text-12); font-weight: var(--w-body); color: var(--text-faint); text-align: left; padding: 0; min-height: var(--space-24); display: inline-flex; align-items: center; position: relative; cursor: pointer; }
.th-sort:hover, .th-sort:focus-visible { color: var(--text-default); }
.table-header .th-sort.amount-right { justify-self: end; text-align: right; }
.th-sort .th-arrow { position: absolute; left: 100%; margin-left: var(--space-4); color: var(--text-faint); opacity: 0; transition: opacity var(--dur-1) var(--ease); }
.th-sort.amount-right .th-arrow { left: auto; right: 100%; margin-left: 0; margin-right: var(--space-4); }
[aria-sort="ascending"] .th-arrow, [aria-sort="descending"] .th-arrow { opacity: 1; color: var(--text-default); }
.th-sort:hover .th-arrow, .th-sort:focus-visible .th-arrow { opacity: 1; }
@media (max-width: 900px) { .tbl .cell-pick { display: none; } .tbl .table-header .cell-pick { display: none; } }

/* "Show all N · k showing": a short list's one quiet control, in place of its page controls. */
.list-more { display: flex; align-items: center; gap: var(--space-6); width: 100%; padding: var(--space-12); min-height: var(--space-24); font-size: var(--text-12); color: var(--text-faint); text-align: left; border-radius: var(--r-card); cursor: pointer; }
.list-more:hover, .list-more:focus-visible { background: var(--bg-hover); color: var(--text-default); }

/* Hit targets of at least 24px (Pilgrim comparison, 2026-10-20). A text link or the wordmark is drawn smaller
   than that, so its press area reaches past its box without moving anything, and the sidebar's toggle is
   brought up to the minimum. */
.link, .wordmark { position: relative; }
.link::after, .wordmark::after { content: ""; position: absolute; inset: -4px -2px; }
.sidebar-toggle { min-width: var(--space-24); min-height: var(--space-24); }

/* The confirmation dialog (js/step-up.js) stacks a summary, a sentence, the code field, a button and a resend link in one body: one gap
   between them, not the paragraphs' own margins. */
#su-body { display: grid; gap: var(--space-12); align-content: start; justify-items: start; }
#su-body > * { margin: 0; }
#su-body > form { justify-self: stretch; }

/* ————— touch —————
   On a touch screen every control has a hit area of at least 44 by 44. Written once here, for the whole platform, and only for a coarse
   pointer, so a desktop keeps the drawn sizes fasset-biz designed. Controls that are bigger already are left alone. Two ways, by what the
   control is: a button, field or icon is made that tall (a hit area you can see is one nobody has to guess at), while a pill segment, a text
   link or a sort heading keeps its drawn size and gets an invisible 44 by 44 area centred on it (test/functional/touch-targets). */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  button.btn-ghost, button.search-affordance, button.nav-open { min-width: 44px; min-height: 44px; }
  .input, .select, textarea.input { min-height: 44px; }
  .tx-search { height: 44px; }
  .tx-search-input { align-self: stretch; }
  .panel-back { min-height: 44px; }
  .icon-btn, .panel-close, .panel-download { min-width: 44px; min-height: 44px; align-items: center; justify-content: center; }
  .cell-pick { min-width: 44px; min-height: 44px; }
  /* A scrolling row of segments clips an invisible area that sticks out of it, so there the segment itself is tall enough. */
  .ins-range .seg-btn { min-height: 44px; }
  .seg-btn, .th-sort, .link, .set-back { position: relative; }
  .seg-btn::after, .th-sort::after, .link::after, .set-back::after {
    content: ""; position: absolute; left: 50%; top: 50%;
    width: max(100%, 44px); height: max(100%, 44px); transform: translate(-50%, -50%);
  }
}

/* The tooltip pattern (js/info-tip.js): a small info icon that opens the design system's Popover with a few plain lines. The design system
   has no info icon, so the glyph is the letter i in a ring; the hit area is wider than the ring. */
.info-tip {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--space-16); height: var(--space-16); padding: 0;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: transparent; color: var(--text-subtle);
  font: inherit; font-size: var(--text-12); font-weight: var(--w-medium); line-height: 1;
  cursor: pointer;
}
.info-tip::after { content: ""; position: absolute; inset: calc(var(--space-8) * -1); }
/* On a touch screen the hit area is at least 44 by 44 (the ring is 16, so 14 more on every side). */
@media (pointer: coarse) { .info-tip::after { inset: calc(var(--space-14) * -1); } }
.info-tip:hover { background: var(--bg-hover); color: var(--text-default); }
.tip-body { padding: var(--space-12) var(--space-14); font-size: var(--text-13); color: var(--text-default); }
.tip-body p + p { margin-top: var(--space-8); }

/* One compact meta line under a figure: a date, a status chip, a short label and an info icon (Insights' readout). */
.ins-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-12); margin-top: var(--space-6); }
.ins-basis { color: var(--text-faint); font-size: var(--text-13); }
