/* The design system's components — ONE definition each (docs/design-system/README.md).
 *
 * Every rule here carries all the names the component has been written with, in one selector list: `ref-*` is the
 * name new code uses (D-15), the others — `settings-*` (css/settings-pages.css), `boat-rent-*`, `bs-*` — are aliases
 * of the same rule, so the pages written with them look the same as the new ones without touching their markup.
 * Values come from the tokens (css/ref-tokens.css, css/area-tokens.css); a value carrying a decision cites it.
 *
 * Loaded on every page, right after the tokens (RefUi::headLinks()): a page's own sheet comes later and can still
 * refine a component — but a component that is wrong is changed HERE, for every page at once.
 *
 * A family arrives here from its old homes in one commit, with a computed-style diff of the 40 reference pages
 * (scripts/ds-style-diff.js) showing what it changed: nothing, or exactly the decision it applies.
 */

/* ---- Status chip: a state, in the state's colours ----
   Deliberately NOT tied to the area: «failed» must not turn amber because the page is in the shipyard. The pairs
   read 4.55–8.28:1 (ok 4.70, off 5.30, danger 4.76, info 8.28, warn 4.55). */
.ref-chip-status,
.boat-rent-chip-status,
.settings-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 2px 4px 2px 0;
    padding: 3px 9px;
    border-radius: var(--ref-radius-pill);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
}
.ref-chip-status i,
.boat-rent-chip-status i,
.settings-chip i { font-size: 9px; } /* ds-allow: scale the glyph scales with the 11px label, not the type ramp */
.ref-chip-on,     .boat-rent-chip-on,     .settings-chip-on     { background: var(--ref-ok-bg);     color: var(--ref-ok); }
.ref-chip-off,    .boat-rent-chip-off,    .settings-chip-off    { background: var(--ref-off-bg);    color: var(--ref-off); }
.ref-chip-danger, .boat-rent-chip-danger, .settings-chip-danger { background: var(--ref-danger-bg); color: var(--ref-danger); }
.ref-chip-info,   .boat-rent-chip-info,   .settings-chip-info   { background: var(--ref-info-bg);   color: var(--ref-info); }
.ref-chip-warn,   .boat-rent-chip-warn,   .settings-chip-warn   { background: var(--ref-warn-bg);   color: var(--ref-warn); }
/* A chip with no tone (D-55) — a classification («Individual», a path), a word a page colours itself — stands on the
   neutral ground in the second ink, not as loose bold text in the inherited black. At zero weight: a tone, a page's
   own class and a colour the marina chose (inline, `Color::chipFill()`) all still win; a chip that is a link only
   outweighs the bare `a` of the framework (its blue was 3.29:1 on this ground). */
:where(.ref-chip-status, .boat-rent-chip-status, .settings-chip),
a:where(.ref-chip-status, .boat-rent-chip-status, .settings-chip) { background: var(--ref-surface-sunk); color: var(--ref-ink-2); }

/* ---- Empty state: a card with nothing in it still SAYS something — what would be here, and how it gets here ----
   Rendered by RefUi::emptyState() (the partials _shared/_empty_state.php and _ref_empty_state.php delegate to it). CGridView wraps its emptyText
   in `.empty`, which the framework sheet italicises: hence the explicit normal style. */
.ref-empty,
.settings-empty {
    padding: 28px;
    color: var(--ref-muted);
    font-size: var(--ref-fs-body);
    font-style: normal;
    text-align: center;
}
.ref-empty-icon,
.settings-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-bottom: 12px;
    border-radius: 50%;
    background: var(--ref-surface-faint);
    color: var(--ref-glyph-faint);
    font-size: 17px; /* ds-allow: scale the glyph of a 44px disc */
}
.ref-empty-title,
.settings-empty-title {
    display: block;
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-body);
    font-weight: 600;
}
.ref-empty-hint,
.settings-empty-hint {
    display: block;
    max-width: 470px;
    margin: 5px auto 0;
    color: var(--ref-muted);
    font-size: var(--ref-fs-small);
    line-height: 1.5;
}
.ref-empty-action,
.settings-empty-action { margin-top: 16px; }

/* ---- Card: the primary framing unit (D-2: an 18 px header, 24 px side padding — the settings cards') ----
   Two markups, one look. `section.ref-card > .ref-card-header > h3` + `.ref-card-body` (alias `.boat-rent-card`), and
   the settings markup `div.panel.inner-panel > .panel-body > h2.formSectionTitle`, whose header bleeds over the body's
   padding. The settings one needs `!important` against Bootstrap's `.panel` and the legacy `div.inner-panel` /
   `h2.formSectionTitle { font-weight: 100 !important }` of css/application.css, and lives under `.ref-skin`: a page
   that did not ask for the design system keeps its legacy panel. No overflow:hidden on it — it would clip the
   pop-ups (colour pickers, dropdowns) opened inside a card; the flush header rounds its own corners. */
.ref-card,
.boat-rent-card {
    overflow: hidden;
    margin-bottom: var(--ref-gap-card);
    border: 1px solid var(--ref-hairline);
    border-radius: var(--ref-radius-card);
    background: var(--ref-surface);
    box-shadow: var(--ref-shadow-card);
    transition: box-shadow .2s ease, border-color .2s ease;
}
/* The lift says «this card acts» (§1, D-48): only a card that IS a link, or a collapsible card under its header, rises
   under the pointer. A card holding a form or a list stays at rest — a lift there promised a click that did nothing. */
a.ref-card:hover,
a.boat-rent-card:hover,
details.ref-card:has(> summary.ref-card-header:hover) { border-color: var(--ref-border); box-shadow: var(--ref-shadow-lift); }
.ref-card-header,
.boat-rent-card-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 12px;
    padding: var(--ref-pad-card-y) var(--ref-pad-card-x);
    border-bottom: 1px solid var(--ref-divider);
    background: var(--ref-surface-head);
}
.ref-card-header h3,
.boat-rent-card-header h3 { margin: 0; color: var(--ref-ink); font-size: var(--ref-fs-section); font-weight: var(--ref-fw-title); line-height: 1.3; }
.ref-card-header h3 > i,
.boat-rent-card-header h3 i.icon-marina { margin-right: 8px; color: var(--area-ink); }
.ref-card-body,
.boat-rent-card-body { padding: 20px var(--ref-pad-card-x); }
/* Under a header, 14 px: the gap the settings markup leaves under its `formSectionTitle` (D-2: two markups, one look). */
.ref-card-header + .ref-card-body,
.boat-rent-card-header + .boat-rent-card-body { padding-top: 14px; }
/* A card title that leads to the page explaining the card (RefUi::cardBegin() `titleUrl`): the title's own colour, a quiet
   arrow after it, the area's ink under the pointer — and at least 24 px tall, the target WCAG 2.5.8 asks (the 18 px
   title's line box is 23, D-51). */
.ref-card-header h3 > a.ref-card-title-link { display: inline-block; min-height: 24px; color: inherit; text-decoration: none; }
.ref-card-header h3 > a.ref-card-title-link:hover,
.ref-card-header h3 > a.ref-card-title-link:focus { color: var(--area-ink); }
.ref-card-header h3 > a.ref-card-title-link > i:first-child { margin-right: 8px; color: var(--area-ink); }
.ref-card-title-go { margin-left: 4px; color: var(--ref-glyph); font-size: var(--ref-fs-small); }
/* A sub-heading inside a card (D-54): the sections of one concern («Version», «Engine»), a step under the card's 18 px
   title — 16 px / 600 in the ink. Two classes outweigh `.settings-page h3` (18 px), which would make it the title's
   size again. */
.ref-subhead,
.settings-page .ref-subhead { margin: 20px 0 8px; color: var(--ref-ink); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); line-height: 1.3; }
.ref-subhead > i:first-child { margin-right: 8px; color: var(--area-ink); }
/* A card that is a form closes on its own actions (D-104): the last row of its body, under the card's divider, on the
   right — «Cancel», then the save, which takes Cancel's height as in a dialog's footer (D-24, below). The customer's
   master data edited in place, one card at a time, is the first. */
.ref-card-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--ref-divider);
}
/* A help line that opens a card's body sits on the body's own padding; one with content after it (a lead over a grid,
   a note over a button) keeps the 12 px it has above — a field's help, the last of its group, closes on 0. */
.ref-card-body > .help-block:first-child { margin-top: 0; }
.ref-card-body > .help-block:not(:last-child) { margin-bottom: 12px; }
/* A button written BEFORE the title with Bootstrap's `pull-right` (the float of the block header): still on the right. */
.ref-card-header > .pull-right,
.boat-rent-card-header > .pull-right { order: 2; margin-left: auto; }
/* The card's own buttons, on the header's right (RefUi::cardBegin() `tools`; the settings cards call it
   `settings-toolbar`, in css/settings-pages.css). The negative margin keeps a 34 px button from growing the header. */
.ref-card-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: -5px 0; }
/* What follows the title in a plain header (cardBegin() `extra`: a date, a count) sits BESIDE the title, and the tools
   stay on the right (D-47) — under space-between it floated mid-header, far from what it describes. Only cardBegin()
   writes a <header>, so a hand-written header is untouched; a header with tools and no `extra` keeps its layout (its
   tools, wrapped under the title at 1024, start on the left: the customer hub, the Dashboard). The summary of a
   collapsible card already does this, below. */
header.ref-card-header:has(> h3 + :not(.ref-card-tools)),
header.boat-rent-card-header:has(> h3 + :not(.ref-card-tools)) { justify-content: flex-start; }
header.ref-card-header > h3 ~ :not(.ref-card-tools) ~ .ref-card-tools,
header.boat-rent-card-header > h3 ~ :not(.ref-card-tools) ~ .ref-card-tools { margin-left: auto; }
/* A card that can close: `details.ref-card`, its header the summary (RefUi::cardBegin() `collapsible`; the «Filters»
   card, D-5, and the home's briefing are two). Closed, it is one line; the chevron says which way it goes. */
details.ref-card > summary.ref-card-header { justify-content: flex-start; cursor: pointer; list-style: none; }
details.ref-card > summary.ref-card-header::-webkit-details-marker { display: none; }
details.ref-card > summary.ref-card-header::after {
    content: "";
    width: 8px;
    height: 8px;
    margin-left: auto;
    border-right: 2px solid var(--ref-muted);
    border-bottom: 2px solid var(--ref-muted);
    transform: rotate(45deg);
    transition: transform .15s ease;
}
details.ref-card[open] > summary.ref-card-header::after { transform: rotate(-135deg); }
/* Its tools sit on the right, before the chevron (a link or a button in a summary acts, it does not toggle the card). */
details.ref-card > summary.ref-card-header > .ref-card-tools { margin-left: auto; }
details.ref-card > summary.ref-card-header:has(> .ref-card-tools)::after { margin-left: 12px; }
details.ref-card:not([open]) > summary.ref-card-header { border-bottom: 0; }
details.ref-card > summary.ref-card-header:focus-visible { outline: none; box-shadow: var(--ref-focus-inset); }

.ref-skin .inner-panel {
    margin-bottom: var(--ref-gap-card) !important;
    border: 1px solid var(--ref-hairline) !important;
    border-radius: var(--ref-radius-card) !important;
    background: var(--ref-surface) !important;
    box-shadow: var(--ref-shadow-card) !important;
    transition: box-shadow .2s ease, border-color .2s ease;
}
/* The text of a card on a page of the kit is the ink (D-55), not the black it inherited from the layout. At the skin's
   weight: anything in the card that has a colour of its own keeps it. */
:where(.ref-skin) :is(.ref-card, .boat-rent-card, .inner-panel) { color: var(--ref-ink); }
/* At rest under the pointer, as the card above (D-48); a collapsible one lifts under its header. */
.ref-skin details.inner-panel:has(> summary.formSectionTitle:hover) { border-color: var(--ref-border) !important; box-shadow: var(--ref-shadow-lift) !important; }
.ref-skin .inner-panel .panel-body { padding: 20px var(--ref-pad-card-x) !important; }
.ref-skin .formSectionTitle,
.ref-skin h2.formSectionTitle {
    display: flex;
    flex-wrap: wrap; /* a header may carry several tools (the price-grid matrix has six) */
    align-items: center;
    justify-content: space-between;
    gap: 10px 12px;
    margin: -20px calc(-1 * var(--ref-pad-card-x)) 14px !important;
    padding: var(--ref-pad-card-y) var(--ref-pad-card-x) !important;
    border-bottom: 1px solid var(--ref-divider) !important;
    border-radius: var(--ref-radius-card) var(--ref-radius-card) 0 0;
    background: var(--ref-surface-head);
    color: var(--ref-ink) !important;
    font-size: var(--ref-fs-section) !important;
    font-weight: var(--ref-fw-title) !important;
    line-height: 1.3;
}
.ref-skin .formSectionTitle > span:first-child { display: inline-flex; align-items: center; }
/* A header written without the title's span — `<h2 class="formSectionTitle"><i></i> Title</h2>`, the tenant
   configuration's 90 of them: the glyph and its text stay together on the left (space-between would send the text, an
   anonymous flex item, to the right edge). */
.ref-skin .formSectionTitle:has(> i:first-child) { justify-content: flex-start; column-gap: 8px; }
.ref-skin .formSectionTitle:has(> i:first-child) > i:first-child { margin-right: 0; }
.ref-skin .formSectionTitle > span:first-child i,
.ref-skin .formSectionTitle > i:first-child,
.ref-skin .formSectionTitle > span:first-child svg { margin-right: 8px; color: var(--area-ink); }

/* Inside a card: a field's label bold and dark, its help italic and muted with a gap from the control, a record's title
   (`.ref-title`) in the ink with its glyph in the area's — the label → control → hint hierarchy at a glance (§7). */
.ref-card .help-block,
.boat-rent-card .help-block { font-style: italic; color: var(--ref-muted); font-size: var(--ref-fs-body); margin-top: 12px; margin-bottom: 0; }
.ref-card .control-label,
.boat-rent-card .control-label { font-weight: 700; color: var(--ref-ink); }
.ref-title,
.boat-rent-title { color: var(--ref-ink); font-weight: var(--ref-fw-title); }
.ref-title i,
.boat-rent-title i { color: var(--area-ink); }

/* ---- The page (D-12): //layouts/main is edge to edge, so a page frames itself — a centred column with its own side
   padding, 1500 px for forms and settings, 1760 px (`--wide`) for lists and hubs. RefUi::pageBegin() / pageEnd();
   `settings-page` is the name it was written with (the customer hub's `settings-page customer-hub` is a wide one). ---- */
.ref-page,
.settings-page {
    max-width: var(--ref-page-max);
    margin: 0 auto;
    padding: var(--ref-page-pad) var(--ref-page-pad) 0;
}
.ref-page--wide { max-width: var(--ref-page-max-wide); }
/* A page drawn inside a dialog (`layout=modal`): the dialog is the frame. Three classes, to beat the customer hub's own
   `.settings-page.customer-hub` padding (css/settings-pages.css loads after the kit). */
.ref-page.settings-page.ref-page--flush { padding: 0; }

/* ---- Page header (D-3): the title and its subtitle on the left, the page's actions on the right ----
   RefUi::pageHead() writes it. The record's identity chips sit on the title's line (D-8). `settings-page-*` and the
   planning's `ow-*` / `h2.ref-title` are the names it was written with by hand. The subtitle sits on the page ground,
   so it takes the second ink (5.87:1 on #e3e3e3), not the hint grey (3.71:1 there). */
.ref-page-head,
.settings-page-header,
.ow-page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin: 0 0 24px;
}
/* The title block takes the line the actions leave, and the subtitle does not size it: a long subtitle wraps under the
   title instead of pushing the actions onto a line of their own at the left (D-3). The head still wraps when the title
   and the actions do not fit side by side. */
.ref-page-head-main,
.settings-page-header-main,
.ow-title-block { flex: 1 1 auto; min-width: 0; }
.ref-page-title,
.settings-page-header h1,
.ref-page-head > h2.ref-title,
.ow-page-head h2.ref-title {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0;
    color: var(--ref-ink-title);
    font-size: var(--ref-fs-page);
    font-weight: 700;
}
.ref-page-title > i,
.ref-page-title > svg,
.settings-page-header h1 i,
.settings-page-header h1 svg,
.ref-page-head > h2.ref-title > i,
.ow-page-head h2.ref-title > i { color: var(--area-ink); font-size: .9em; }
.ref-page-sub,
.settings-page-header .settings-page-sub,
.ow-page-sub { margin: 6px 0 0; color: var(--ref-ink-2); font-size: var(--ref-fs-body); font-style: italic; contain: inline-size; }
.ref-page-actions,
.settings-page-actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; }
.settings-page-action { flex: 0 0 auto; }
.ref-page-title-row,
.settings-page-title-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
.ref-page-identity { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-width: 0; }
.ref-page-identity .ref-chip-status { margin: 0; }
/* A classification path among the identity chips: Group › Category › Type. */
.ref-path,
.settings-hub-path { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; min-width: 0; }
.ref-path-sep,
.settings-hub-sep { color: var(--ref-border-soft); font-size: 10px; } /* ds-allow: scale a separator glyph, not text */

/* ---- Filters (D-5): ONE closable «Filters» card above the list, its header counting the active filters ----
   RefUi::filterCardBegin() / filterCardEnd(): a closable card (above). It opens by itself when a filter is active, so
   a filtered list always says why; closed, it is one line. */
/* The form is the card's only content: no rule under it (the bar draws one when it sits above a grid in the same card). */
.ref-filter-card .settings-filter-bar { margin-bottom: 0; padding-bottom: 0; border-bottom: 0; }
/* A count beside a title: the active filters, the rows of a section. */
.ref-count {
    display: inline-block;
    min-width: 22px;
    padding: 1px 7px;
    border-radius: var(--ref-radius-pill);
    background: var(--ref-surface-sunk);
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* ---- Pills (D-6): the faces of one page and the sibling pages of a cluster — never tabs ----
   RefUi::pills(). Links (`a.ref-pill`, the current one `aria-current="page"`) or Bootstrap's tab machinery kept as it
   is (`ul.nav.ref-pills > li > a[data-toggle=tab]`, the current one `li.active`). `settings-subnav` and
   `nav-tabs.settings-tabs` are the names they were written with; the tabs' underline skin went (Thomas, 2026-10-14:
   tabs are not visible enough in this style). The selectors beat Bootstrap's `.nav-tabs > li.active > a:hover`. */
.ref-pills,
.settings-subnav,
.nav-tabs.settings-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 20px;
    padding: 0;
    border: 0;
    list-style: none;
}
.settings-subnav,
.ref-page-head + .ref-pills,
.settings-page-header + .ref-pills,
.ow-page-head + .ref-pills { margin-top: -8px; } /* under the page header, whose 24 px it shares */
/* The faces of one page (D-6) share one header: a face with buttons in it and one without put the title — and the
   pills under it — at two heights, and both moved at each switch (9 px on «Workload», whose own floor this was,
   css/planning-cards.css until D-74). The floor is a header button's height. */
.ref-page-head:has(+ :is(.ref-pills, .settings-subnav, .settings-tabs)),
.settings-page-header:has(+ :is(.ref-pills, .settings-subnav, .settings-tabs)),
.ow-page-head:has(+ :is(.ref-pills, .settings-subnav, .settings-tabs)) { min-height: var(--ref-head-min); }
.ref-pills > li,
.nav-tabs.settings-tabs > li { float: none; margin: 0; }
.ref-pill,
.ref-pills > li > a,
.settings-subnav-link,
.nav-tabs.settings-tabs > li > a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 7px 16px;
    border: 1px solid var(--ref-border);
    border-radius: var(--ref-radius-pill);
    background: var(--ref-surface);
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-small);
    font-weight: 600;
    line-height: 1.4;
    text-decoration: none;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.ref-pill:hover, .ref-pill:focus,
.ref-pills > li > a:hover, .ref-pills > li > a:focus,
.settings-subnav-link:hover, .settings-subnav-link:focus,
.nav-tabs.settings-tabs > li > a:hover, .nav-tabs.settings-tabs > li > a:focus {
    border-color: var(--area-accent);
    background: var(--ref-surface);
    color: var(--area-ink);
    text-decoration: none;
}
.ref-pill.active, .ref-pill[aria-current="page"], .ref-pill.is-current,
.ref-pills > li.active > a, .ref-pills > li.active > a:hover, .ref-pills > li.active > a:focus,
.settings-subnav-link.active, .settings-subnav-link.active:hover,
.nav-tabs.settings-tabs > li.active > a, .nav-tabs.settings-tabs > li.active > a:hover, .nav-tabs.settings-tabs > li.active > a:focus {
    border-color: var(--area-ink);
    background: var(--area-ink);
    color: var(--ref-on-fill);
}
.ref-pill:focus-visible,
.ref-pills > li > a:focus-visible,
.settings-subnav-link:focus-visible,
.nav-tabs.settings-tabs > li > a:focus-visible { outline: none; box-shadow: var(--ref-focus-ring); }
/* A counter on a pill (the translation editor's «2/4», a section's rows) follows the pill's state. */
.ref-pill .badge,
.ref-pills > li > a .badge,
.nav-tabs.settings-tabs > li > a .badge { margin-left: 2px; background: var(--ref-surface-sunk); color: var(--ref-ink); font-weight: 600; }
.ref-pill.active .badge, .ref-pill[aria-current="page"] .badge,
.ref-pills > li.active > a .badge,
.nav-tabs.settings-tabs > li.active > a .badge { background: var(--ref-on-fill); color: var(--area-ink); }
/* A group of sibling pages under ONE pill (D-112, RefUi::pills() `items`): a button that opens their list, filled like
   the current pill while one of them is the page (`is-current`), which the list marks; `ref-pill--end` sends an item
   to the strip's right end (the cluster's settings, a glyph alone with `iconOnly`). */
.ref-pill-group { position: relative; display: inline-flex; }
button.ref-pill { cursor: pointer; }
.ref-pill-caret { font-size: var(--ref-fs-micro); }
.ref-pill-menu > li > a[aria-current="page"] { color: var(--area-ink); font-weight: 600; }
.ref-pill--end { margin-left: auto; }

/* ---- «New» (RefUi::newMark()): a page or a function that has just arrived, beside its entry wherever it is offered
   again — the top menu shows the same until the same day. `new` on RefUi::button() and RefUi::pills() writes it. On a
   filled pill it turns over, as the pill's counter. */
.ref-new {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: var(--ref-radius-pill);
    background: var(--area-ink);
    color: var(--ref-on-fill);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    letter-spacing: .03em;
    line-height: 1.5;
    text-transform: uppercase;
}
.ref-pill.active .ref-new, .ref-pill[aria-current="page"] .ref-new,
.ref-pills > li.active > a .ref-new { background: var(--ref-on-fill); color: var(--area-ink); }

/* ---- «Show» (D-6): which reading of the SAME list the page shows (Mine / The team, Awaited / All) ----
   RefUi::show(): a caption and buttons side by side, in the page header; the current one is marked like a pressed
   button. A different FACE of the page is a pill, a sibling page is a pill or the «Actions» card (D-7). */
.ref-show { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.ref-show-cap { color: var(--ref-ink-2); font-size: var(--ref-fs-small); font-weight: 600; }
.ref-show-group { display: flex; flex-wrap: wrap; gap: 8px; }
.ref-show-group .btn { white-space: nowrap; }
/* After «Columns» (D-4) the caption keeps closer to its own buttons (10 px) than to «Columns» (20 px), so «Show» never
   seems to caption it; on one line only — wrapped, the actions' 8 px (the warehouse lists, 2026-10-14). */
@media (min-width: 768px) {
    .ref-page-actions > .btn + .ref-show { margin-left: 12px; }
}
.ref-show-group .btn[aria-current="page"] {
    border-color: var(--area-accent);
    background: var(--area-accent-ring);
    color: var(--area-ink);
    font-weight: 600;
}

/* ---- Key-figure tiles (D-9): label → value → note; the emphasised tile carries a filled icon in the area's ink ----
   RefUi::tiles(). A row is a grid that balances itself (auto-fit) and wraps. `settings-stat*` are the names they were
   written with. The emphasis is never a stripe down the edge (D-10). */
.ref-tiles,
.settings-stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 14px;
}
/* A row of tiles in the page's flow, between cards (the stock value, the material requirements): a card's distance. */
.ref-page > .ref-tiles,
.ref-hub-main > .ref-tiles { margin-bottom: var(--ref-gap-card); }
/* Each tile is a SUBGRID of its line (D-50): label, value (or chip), note and a second reading (`footHtml`) share their
   rows with every tile beside it, so the labels sit on one line — the emphasised tile's 22 px icon raises the label row
   for all, its label is no longer 4 px low — and the values start level even when a label wraps. */
.ref-tile,
.settings-stat {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 5px;
    min-width: 0;
    padding: 14px 16px;
    border: 1px solid var(--ref-hairline);
    border-radius: var(--ref-radius-card);
    background: var(--ref-surface-head);
}
/* A tile spans only the rows its line uses: a row no tile fills would still keep the line's 14 px gap (`gap` of the
   row) under the last figure. */
:is(.ref-tiles, .settings-stat-row):not(:has(> * > :nth-child(4))) > * { grid-row: span 3; }
:is(.ref-tiles, .settings-stat-row):not(:has(> * > :nth-child(3))) > * { grid-row: span 2; }
.ref-tile-label,
.settings-stat-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    letter-spacing: .03em;
    line-height: 1.2;
    text-transform: uppercase;
}
/* A glyph on the tile ground (#fafbfc): the hint grey, 4.3:1 there (the decorative grey measured 2.47:1). */
.ref-tile-label i,
.settings-stat-label i { color: var(--ref-muted); font-size: 12px; } /* ds-allow: scale a glyph beside an 11 px label */
.ref-tile-value,
.settings-stat-value {
    overflow: hidden;
    color: var(--ref-ink);
    font-size: var(--ref-fs-section);
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* A value of words (a supplier's name, a warehouse) wraps rather than being cut with an ellipsis (§2.8, D-9): RefUi::tiles()
   marks it when it has letters and no digit. */
.ref-tile-value--text { white-space: normal; overflow-wrap: break-word; }
/* The middle step of the value ramp — 18 / 22 / 26 (emphasised): a figure that is the card's subject (a KPI board). */
.ref-tile-value--md,
.settings-stat-value--md { font-size: var(--ref-fs-display); }
.ref-tile-unit,
.settings-stat-unit { margin-left: 2px; color: var(--ref-ink-2); font-size: var(--ref-fs-small); font-weight: 500; }
/* Wraps rather than truncates: a tile is ~150 px at 1024 and the note carries no title to recover a cut. */
.ref-tile-note,
.settings-stat-sub { color: var(--ref-muted); font-size: var(--ref-fs-small); font-weight: 500; white-space: normal; }
.ref-tile--emph,
.settings-stat--emph { border-color: var(--ref-border-emph); background: var(--ref-surface); }
.ref-tile--emph .ref-tile-label i,
.settings-stat--emph .settings-stat-label i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: var(--ref-radius-inset);
    background: var(--area-ink);
    color: var(--ref-on-fill);
    font-size: var(--ref-fs-micro);
}
.ref-tile--emph .ref-tile-value,
.settings-stat--emph .settings-stat-value {
    color: var(--area-ink);
    font-size: var(--ref-fs-page);
    font-weight: 700;
    /* An amount never wraps, but a textual fallback («Not set») does not fit on one line at this size. */
    white-space: normal;
    overflow-wrap: break-word;
}
/* A chip in a tile — the state of a chip tile, a page's chip under the figure (`footHtml`) — keeps its own size in its
   row: a grid item would stretch it across the tile and down its row. */
.ref-tile > :is(.ref-chip-status, .boat-rent-chip-status, .settings-chip),
.settings-stat > :is(.ref-chip-status, .boat-rent-chip-status, .settings-chip) { justify-self: start; align-self: start; margin: 0; }
@media (max-width: 480px) {
    .ref-tiles, .settings-stat-row { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    .ref-tile--emph .ref-tile-value, .settings-stat--emph .settings-stat-value { font-size: var(--ref-fs-display); }
}

/* ---- Meter (`progress.ref-meter`, D-106): how far a quantity has gone toward its end — an order's progress, an
   article's monthly load — beside its figure written in text, which it repeats. A native <progress>: its value and its
   name (`aria-labelledby` the label beside it) come with it. On the kit's well, filled in the area's accent; a tone
   says the reading: `--ok` done or comfortable, `--warn` high, `--danger` over the limit (the bar stays full: the figure
   says by how much). Promoted on 2026-10-26 from Yard › Analysis (css/pages/analysis-cards.css `.an-meter`). A
   quantity per row among rows (calls per day) is the settings bar, not a meter. ---- */
.ref-meter {
    --ref-meter-fill: var(--area-accent);
    display: block;
    width: 100%;
    height: 10px;
    border: 0;
    border-radius: var(--ref-radius-pill);
    overflow: hidden;
    background: var(--ref-surface-sunk);
    color: var(--ref-meter-fill);
    -webkit-appearance: none;
    appearance: none;
}
.ref-meter::-webkit-progress-bar { border-radius: var(--ref-radius-pill); background: var(--ref-surface-sunk); }
.ref-meter::-webkit-progress-value { border-radius: var(--ref-radius-pill); background: var(--ref-meter-fill); }
.ref-meter::-moz-progress-bar { border-radius: var(--ref-radius-pill); background: var(--ref-meter-fill); }
.ref-meter--ok { --ref-meter-fill: var(--ref-ok); }
.ref-meter--warn { --ref-meter-fill: var(--ref-warn); }
.ref-meter--danger { --ref-meter-fill: var(--ref-danger); }

/* ---- A page with its «Actions» card (D-7): the content in the main column, the card on the right ----
   RefUi::hubBegin() / hubAside() / hubEnd() and RefUi::actionsCard(). The card is STICKY while the page scrolls and
   lists first the sibling pages of the menu group (MenuSiblings), then what you DO from here, in labelled groups of
   full-width buttons. Under 1200 px it becomes a strip ABOVE the content, its buttons in rows. The left navigation is
   only for a record with many sections (the customer, the boat). `settings-hub-*`, `settings-rail-*` are the names
   it was written with. */
.ref-hub,
.settings-hub-layout { display: flex; align-items: flex-start; gap: var(--ref-gap-card); }
.ref-hub-main,
.settings-hub-main { flex: 1 1 auto; min-width: 0; }
.ref-hub-rail,
.settings-hub-rail {
    position: sticky;
    top: 16px;
    flex: 0 0 264px;
    align-self: flex-start;
    width: 264px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
}
.ref-hub-rail > .ref-card,
.settings-hub-rail > .inner-panel { margin-bottom: 0; }
/* The groups of the card: a quiet label so an action is found by category. */
.ref-actions-group + .ref-actions-group,
.settings-rail-group + .settings-rail-group { margin-top: 16px; }
/* Scoped: `.settings-page h3` / `h4` (0,1,1) would otherwise make a group label the size of the card's title. */
.ref-actions .ref-actions-title,
.settings-rail-group-title,
.settings-page h3.settings-rail-group-title {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 7px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--ref-divider);
    color: var(--ref-muted);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.ref-actions .ref-actions-title i,
.settings-rail-group-title i { color: var(--ref-glyph-faint); font-size: var(--ref-fs-micro); }
/* Full-width buttons, a label wrapping under its own icon (Bootstrap's .btn is nowrap; the Italian labels are long). A
   POST action — a <form> holding its button, or a field and its button — and the PrintButton widget in its dialog mode
   (§2.9: its .row > .col) are items as a button is (D-80): the form stacks what it holds at the list's gap, the widget's
   row gives back the gutters the card already pads, and their button is dressed as the others. */
.ref-actions-list,
.settings-hub-rail .settings-linklist,
.settings-rail-actions .settings-linklist { display: flex; flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 6px; }
.ref-actions-list > form { display: flex; flex-direction: column; gap: 6px; margin: 0; }
.ref-actions-list > .print-button-row { margin: 0; }
.ref-actions-list > .print-button-row > [class*="col-"] { padding: 0; }
.ref-actions-list > .btn,
.ref-actions-list > form > .btn,
.ref-actions-list > .print-button-row > [class*="col-"] > .btn,
.settings-hub-rail .settings-linklist .btn.settings-btn,
.settings-rail-actions .settings-linklist .btn.settings-btn {
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    width: 100%;
    line-height: 1.35;
    text-align: left;
    white-space: normal;
}
.ref-actions-list > .btn i,
.ref-actions-list > form > .btn i,
.ref-actions-list > .print-button-row > [class*="col-"] > .btn i,
.settings-hub-rail .settings-linklist .btn.settings-btn i,
.settings-rail-actions .settings-linklist .btn.settings-btn i { flex: 0 0 16px; margin-top: 2px; margin-right: 8px; text-align: center; }
.ref-actions-list > .btn > span,
.ref-actions-list > form > .btn > span,
.ref-actions-list > .print-button-row > [class*="col-"] > .btn > span,
.settings-hub-rail .settings-linklist .btn.settings-btn > span,
.settings-rail-actions .settings-linklist .btn.settings-btn > span { min-width: 0; }
/* The page you are on, among its siblings: marked like the current reading of «Show», never removed. */
.ref-actions-list > .btn[aria-current="page"] { border-color: var(--area-accent); background: var(--area-accent-ring); color: var(--area-ink); font-weight: 600; }
@media (max-width: 1199px) {
    .ref-hub,
    .settings-hub-layout { flex-direction: column-reverse; align-items: stretch; }
    /* The strip takes the content's width (D-72): the column's own `align-self: flex-start` outweighs the layout's
       `stretch`, so the strip was as wide as its longest text — on the boat sale it stopped at 786 px (832 in Italian)
       over cards reaching 985. */
    .ref-hub-rail,
    .settings-hub-rail { position: static; flex: none; align-self: stretch; width: auto; max-height: none; overflow: visible; }
    .ref-actions > .ref-card-body { display: flex; flex-wrap: wrap; gap: 12px 24px; }
    .ref-actions .ref-actions-group { flex: 1 1 240px; margin-top: 0; }
    .ref-actions-list,
    .settings-hub-rail .settings-linklist,
    .settings-rail-actions .settings-linklist { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
    .ref-actions-list > .btn,
    .ref-actions-list > form > .btn,
    .ref-actions-list > .print-button-row > [class*="col-"] > .btn,
    .settings-hub-rail .settings-linklist .btn.settings-btn,
    .settings-rail-actions .settings-linklist .btn.settings-btn { align-items: center; justify-content: center; width: auto; white-space: nowrap; }
    .ref-actions-list > .btn i,
    .ref-actions-list > form > .btn i,
    .ref-actions-list > .print-button-row > [class*="col-"] > .btn i,
    .settings-hub-rail .settings-linklist .btn.settings-btn i,
    .settings-rail-actions .settings-linklist .btn.settings-btn i { flex: 0 0 auto; margin-top: 0; margin-right: 6px; }
    .settings-rail-actions .settings-linklist > .btn-group,
    .settings-rail-actions .settings-linklist > .btn-group > .btn.settings-btn { width: auto; }
}

/* ---- Steps: a guided flow's stepper ----
   RefUi::steps() (protected/views/shared/_ref_steps.php delegates). A row of cards, the current step ringed in the area
   accent, a finished one with a green check, one holding an error in red, a later one on a quiet ground (never opacity:
   it would pull the hint grey under AA). `--compact` is for flows with more steps than fit as cards (the contract
   wizard has up to ten): numbered pills with the title only; under 1200 px only the current one keeps its title, under
   768 px only the badges and a «Step 3 of 9 — Boat» line. */
.ref-steps { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 20px; padding: 0; list-style: none; }
.ref-step { flex: 1 1 260px; }
.ref-step > a,
.ref-step > span {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    border: 1px solid var(--ref-border);
    border-radius: var(--ref-radius-card);
    background: var(--ref-surface);
    color: var(--ref-ink);
    text-decoration: none;
}
.ref-step > a:hover,
.ref-step > a:focus { border-color: var(--area-accent); color: var(--ref-ink); text-decoration: none; outline: none; }
.ref-step > a:focus-visible { box-shadow: var(--ref-focus-ring); }
.ref-step-badge {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--ref-surface-sunk);
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-body);
    font-weight: 700;
}
.ref-step-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.35; }
.ref-step-text strong { font-size: var(--ref-fs-body); }
.ref-step-text small { color: var(--ref-muted); font-size: var(--ref-fs-small); }
.ref-step.is-active > a,
.ref-step.is-active > span { border-color: var(--area-accent); box-shadow: var(--ref-focus); }
/* White on the raw accent is 2.41:1 under Marina: the number sits on the area PRIMARY, the ring keeps the accent. */
.ref-step.is-active .ref-step-badge { background: var(--area-primary); color: var(--ref-on-fill); }
.ref-step.is-done .ref-step-badge { background: var(--ref-ok-bg); color: var(--ref-ok); }
/* A step holding an error, wherever the operator is: set by RefUi::steps() (`state => error`) or by a page script. */
.ref-step.is-error > a,
.ref-step.is-error > span { border-color: var(--ref-danger-edge); }
.ref-step.is-error .ref-step-badge { background: var(--ref-danger-bg); color: var(--ref-danger); }
.ref-step.is-pending > span { background: var(--ref-surface-head); }
.ref-steps-caption { display: none; margin: -8px 0 16px; color: var(--ref-ink-2); font-size: var(--ref-fs-small); font-weight: 600; }
.ref-steps--compact { gap: 8px; }
.ref-steps--compact .ref-step { flex: 0 1 auto; }
.ref-steps--compact .ref-step > a,
.ref-steps--compact .ref-step > span { gap: 8px; padding: 6px 12px 6px 6px; border-radius: var(--ref-radius-pill); }
.ref-steps--compact .ref-step-badge { width: 26px; height: 26px; font-size: var(--ref-fs-small); }
.ref-steps--compact .ref-step-text strong { font-size: var(--ref-fs-small); font-weight: 600; white-space: nowrap; }
.ref-steps--compact .ref-step-text small { display: none; }
@media (max-width: 1199px) {
    .ref-steps--compact .ref-step:not(.is-active) .ref-step-text { display: none; }
    .ref-steps--compact .ref-step:not(.is-active) > a,
    .ref-steps--compact .ref-step:not(.is-active) > span { padding: 4px; }
}
@media (max-width: 767px) {
    .ref-steps--compact .ref-step.is-active .ref-step-text { display: none; }
    .ref-steps--compact .ref-step.is-active > span { padding: 4px; }
    .ref-steps--compact + .ref-steps-caption { display: block; }
}

/* ---- The grid: a list's table (CGridView / GridExcel with `itemsCssClass`, or a table written in a view) ----
   Uppercase muted headers, soft borders, a rounded frame, a quiet zebra, the ACTION column pinned to the right while
   the others scroll. Every machinery of the grid stays (sort, pager, export, EColumns); this is the skin. Its names:
   `ref-grid-table` (the table) in `ref-grid` (the wrapper that scrolls), and the hand-written `settings-grid-table` /
   `settings-grid` and `boat-rent-grid-table` / `-wrap` — aliases of the same rules.

   Two details are load-bearing: a pinned cell needs its OWN opaque background (the row's lives on the <tr>, which does
   not paint under a sticky child), and no `overflow: hidden` on the table (it would become its own scroll container
   and unpin the column) — so the corners are rounded on the corner cells. */
.ref-grid .grid-view,
.settings-grid .grid-view { padding: 0; border: none; background: transparent; }
/* GridExcel wraps the table in Bootstrap's .table-responsive: the always-on horizontal scroller, and the sticky
   scroll container of the pinned column. */
.ref-grid .table-responsive,
.settings-grid .table-responsive,
.ref-grid-wrap,
.boat-rent-grid-wrap { overflow-x: auto; margin-bottom: 0; border: none; }
.ref-grid-table,
.boat-rent-grid-table,
.settings-grid-table {
    /* auto + min-width: fills the card when the columns fit, scrolls when they do not — but the browser narrows a
       wrapping column to its longest word before it lets the table scroll: a prose column takes `.ref-col-text`, a
       table whose columns the page decides takes `ref-grid-table--fixed` (below, D-40). */
    width: auto;
    min-width: 100%;
    border: 1px solid var(--ref-hairline);
    border-radius: var(--ref-radius-card);
    border-collapse: separate;
    border-spacing: 0;
    background: var(--ref-surface);
}
/* A table whose columns the PAGE decides (a <colgroup> of widths: the configurator's sections, the delivery note's
   lines) asks for the fixed layout: the `width: auto` above makes `table-layout: fixed` inert, and a nowrap chip then
   took the room of the columns beside it (the configurator's quantity, ~30 px at 1024). In a fixed table nothing may
   set a column's minimum, so a chip wraps inside its cell (D-40). */
.ref-grid-table.ref-grid-table--fixed,
.boat-rent-grid-table.ref-grid-table--fixed,
.settings-grid-table.ref-grid-table--fixed { width: 100%; table-layout: fixed; }
.ref-grid-table--fixed :is(.ref-chip-status, .boat-rent-chip-status, .settings-chip) { white-space: normal; }
/* …and in an automatic table a prose column (a question, an answer, a note) keeps a reading width: the table scrolls
   in its card instead of running the text one word a line. */
.ref-col-text { min-width: 16em; }
.ref-grid-table > thead > tr > th:first-child,
.boat-rent-grid-table > thead > tr > th:first-child,
.settings-grid-table > thead > tr > th:first-child { border-top-left-radius: var(--ref-radius-card); }
.ref-grid-table > thead > tr > th:last-child,
.boat-rent-grid-table > thead > tr > th:last-child,
.settings-grid-table > thead > tr > th:last-child { border-top-right-radius: var(--ref-radius-card); }
.ref-grid-table > tbody > tr:last-child > td:first-child,
.boat-rent-grid-table > tbody > tr:last-child > td:first-child,
.settings-grid-table > tbody > tr:last-child > td:first-child { border-bottom-left-radius: var(--ref-radius-card); }
.ref-grid-table > tbody > tr:last-child > td:last-child,
.boat-rent-grid-table > tbody > tr:last-child > td:last-child,
.settings-grid-table > tbody > tr:last-child > td:last-child { border-bottom-right-radius: var(--ref-radius-card); }
/* A table with no header (the configurator's sections, a boat model's rules, the attachments) rounds its FIRST row's
   corners too: there the pinned action cell's own opaque ground painted over the frame's top-right corner (D-45). */
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table):not(:has(> thead)) > tbody:first-of-type > tr:first-child > td:first-child { border-top-left-radius: var(--ref-radius-card); }
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table):not(:has(> thead)) > tbody:first-of-type > tr:first-child > td:last-child { border-top-right-radius: var(--ref-radius-card); }
.ref-grid-table > thead > tr > th,
.boat-rent-grid-table > thead > tr > th,
.settings-grid-table > thead > tr > th {
    padding: 11px 14px;
    border-top: none;
    border-bottom: 1px solid var(--ref-hairline);
    background: var(--ref-surface-head);
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-micro);
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    vertical-align: middle;
    white-space: nowrap;
}
/* The sort link: a 24 × 24 target at least (WCAG 2.2, 2.5.8), the label keeping its size. */
.ref-grid-table > thead > tr > th a,
.settings-grid-table > thead > tr > th a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    min-height: 24px;
    color: var(--ref-ink-2);
}
.ref-grid-table > thead > tr > th a.asc, .ref-grid-table > thead > tr > th a.desc,
.settings-grid-table > thead > tr > th a.asc, .settings-grid-table > thead > tr > th a.desc { color: var(--area-ink); }
.ref-grid-table > tbody > tr > td,
.boat-rent-grid-table > tbody > tr > td,
.settings-grid-table > tbody > tr > td {
    padding: 10px 14px;
    border-top: 1px solid var(--ref-divider);
    color: var(--ref-ink);
    font-size: var(--ref-fs-body);
    vertical-align: middle;
}
.ref-grid-table > tbody > tr:first-child > td,
.boat-rent-grid-table > tbody > tr:first-child > td,
.settings-grid-table > tbody > tr:first-child > td { border-top: none; }
.ref-grid-table > tbody > tr.even, .settings-grid-table > tbody > tr.even { background: var(--ref-surface); }
.ref-grid-table > tbody > tr.odd, .settings-grid-table > tbody > tr.odd { background: var(--ref-row-odd); }
.ref-grid-table > tbody > tr:hover,
.boat-rent-grid-table > tbody > tr:hover,
.settings-grid-table > tbody > tr:hover { background: var(--ref-row-hover); }
/* The pinned ACTION column (D-41): the column that stays in sight while the others scroll is the ACTIONS, by role and
   under every name of the table — the last column when it is CButtonColumn's (`button-column` on its header, cells
   and footer) or one a view writes and marks `ref-col-actions`. Never a data column: until 2026-10-21 the kit's name
   pinned ANY last column and the alias only `button-column`, so one table behaved two ways by its name — a pinned
   total or field covered the columns scrolling under it (the warehouse unpinned them by hand). */
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > thead > tr > th:last-child:is(.button-column, .ref-col-actions),
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > tbody > tr > td:last-child:is(.button-column, .ref-col-actions),
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > tfoot > tr > td:last-child:is(.button-column, .ref-col-actions) { position: sticky; right: 0; }
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > thead > tr > th:last-child:is(.button-column, .ref-col-actions) { z-index: 3; background: var(--ref-surface-head); }
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > tbody > tr > td:last-child:is(.button-column, .ref-col-actions) { z-index: 2; background: var(--ref-surface); }
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > tbody > tr:hover > td:last-child:is(.button-column, .ref-col-actions) { background: var(--ref-row-hover); }
:is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > tfoot > tr > td:last-child:is(.button-column, .ref-col-actions) { z-index: 2; background: var(--ref-surface-head); }
/* The divider of the pinned column shows only while the table really overflows: the wrapper (`.settings-grid` or
   `.ref-grid`) gets `has-x-scroll` from settingsGridEnhance() (js/settings-pages.js) or the planning grids' script. */
.has-x-scroll :is(.ref-grid-table, .boat-rent-grid-table, .settings-grid-table) > :is(thead, tbody, tfoot) > tr > :is(th, td):last-child:is(.button-column, .ref-col-actions) {
    border-left: 1px solid var(--ref-hairline);
    box-shadow: var(--ref-shadow-pin);
}
/* The row's buttons (HubRowActions): quiet 30 × 30 squares, coloured by what they do (settings-pages.css), the delete
   last and set apart (D-13). */
.ref-grid-table .button-column,
.settings-grid-table .button-column,
.settings-grid-table td.button-column { white-space: nowrap; }
.ref-grid-table .button-column a,
.settings-grid-table .button-column a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    margin: 0 1px;
    border: 1px solid var(--ref-border);
    border-radius: var(--ref-radius-control);
    background: var(--ref-surface);
    color: var(--ref-muted);
    text-decoration: none;
    transition: all .15s ease;
}
.ref-grid-table .button-column a:hover,
.settings-grid-table .button-column a:hover { border-color: var(--area-accent); background: var(--ref-row-hover); color: var(--area-ink); }
.ref-grid-table .button-column a + a.settings-row-danger,
.settings-grid-table .button-column a + a.settings-row-danger { margin-left: 8px; }
/* A disabled row button (CustomButtonColumn `disabled`) is css/settings-pages.css's: it must come after the per-action
   colours it overrides, at the same specificity — and so is the pressed toggle (`aria-pressed`, D-46). */

/* ---- Cell note (`.ref-cell-note` + `-ok` / `-warn` / `-danger` / `-off`, D-42): a status SENTENCE under a cell's text —
   «Included in …», «Not available with …», a rule's own message. 13 px in the tone's ink, an icon, and it wraps: the
   11 px chip is for a one-word state (§1: 11 px is never a sentence), and a chip that does not wrap took the room of
   the columns beside it. The inks are the chips': 4.5:1 and more on white and on the notes' grounds. ---- */
.ref-cell-note {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-top: 4px;
    color: var(--ref-ink-2);
    font-size: var(--ref-fs-small);
    font-weight: 500;
    line-height: 1.4;
    white-space: normal;
}
.ref-cell-note > i { flex: 0 0 auto; font-size: 12px; } /* ds-allow: scale a glyph beside a 13 px line */
.ref-cell-note-ok     { color: var(--ref-ok); }
.ref-cell-note-warn   { color: var(--ref-warn); }
.ref-cell-note-danger { color: var(--ref-danger); }
.ref-cell-note-off    { color: var(--ref-off); }
.ref-cell-note[hidden] { display: none; }

/* ---- Buttons (D-1: the primary is filled with the area's ink; D-15: `ref-btn*`, the other names aliases) ----
   Neutral, primary, danger: one box (8 px radius, the same padding family) so they line up side by side.
   The primary's hover is a 12% black wash over the ink, not a darker token: for some areas the dark step and the ink
   are the same value (master), which would leave the button with no hover; the wash only darkens the fill and RAISES
   the label's contrast (master 4.72 -> 5.81:1). */
.ref-btn,
.boat-rent-btn,
.btn.settings-btn {
    padding: 8px 16px;
    border: 1px solid var(--ref-border);
    border-radius: var(--ref-radius-control);
    background: var(--ref-surface);
    color: var(--ref-ink);
    font-weight: var(--ref-fw-button);
    transition: all .15s ease;
}
.ref-btn:hover, .ref-btn:focus, .ref-btn:active,
.boat-rent-btn:hover, .boat-rent-btn:focus, .boat-rent-btn:active,
.btn.settings-btn:hover, .btn.settings-btn:focus, .btn.settings-btn:active {
    border-color: var(--area-ink);
    background: var(--ref-surface-hover);
    color: var(--area-ink);
    outline: none;
    box-shadow: none;
}
/* One gap between a button's glyph and its label, 6 px, in every tone and under every name (it was 4, 5 or 6). */
.ref-btn i,
.boat-rent-btn i,
.btn.settings-btn i { margin-right: 6px; color: var(--area-ink); }
/* Disabled (D-105): a neutral button that cannot be used NOW — another card of the page is being edited, the printer
   is busy — stays in its place and says so: the muted ink on the surface (4.76:1, its glyph too: never under a glyph's
   3:1), no wash and no area ink under the pointer, the not-allowed cursor. `[disabled]`, Bootstrap's `.disabled` and
   `aria-disabled="true"` are one state, written for :hover, :focus and :active too (Chrome matches :hover on a disabled
   button, §4). Bootstrap's 65 % opacity is dropped: over the muted ink it fell under 3:1. */
.ref-btn:is([disabled], .disabled, [aria-disabled="true"]),
.ref-btn:is([disabled], .disabled, [aria-disabled="true"]):is(:hover, :focus, :active),
.boat-rent-btn:is([disabled], .disabled, [aria-disabled="true"]),
.boat-rent-btn:is([disabled], .disabled, [aria-disabled="true"]):is(:hover, :focus, :active),
.btn.settings-btn:is([disabled], .disabled, [aria-disabled="true"]),
.btn.settings-btn:is([disabled], .disabled, [aria-disabled="true"]):is(:hover, :focus, :active) {
    border-color: var(--ref-border);
    background: var(--ref-surface);
    color: var(--ref-muted);
    opacity: 1;
    cursor: not-allowed;
}
.ref-btn:is([disabled], .disabled, [aria-disabled="true"]) i,
.boat-rent-btn:is([disabled], .disabled, [aria-disabled="true"]) i,
.btn.settings-btn:is([disabled], .disabled, [aria-disabled="true"]) i { color: var(--ref-muted); }

/* SMALL means smaller: the family sets its own padding, which outranks Bootstrap's `.btn-sm`, so a small button measured
   39 px — taller than the 38 px one it compacts. 32 px, like the grid's row buttons beside it (§7.0). It was the settings
   area's alone until 2026-10-16; a card's own buttons (RefUi::card() `tools`) are small too.
   ONE small size for a button with a label (D-23): `btn-sm`, 32 px. A kit button written with Bootstrap's `btn-xs` is the
   same small button (D-22): Bootstrap's xs (12 px type) is not a step of the kit's scale. */
.btn.ref-btn.btn-sm, .btn.ref-btn-primary.btn-sm, .btn.ref-btn-danger.btn-sm,
.btn.settings-btn.btn-sm, .btn.settings-btn-primary.btn-sm, .btn.settings-btn-danger.btn-sm,
.btn.ref-btn.btn-xs, .btn.ref-btn-primary.btn-xs, .btn.ref-btn-danger.btn-xs,
.btn.settings-btn.btn-xs, .btn.settings-btn-primary.btn-xs, .btn.settings-btn-danger.btn-xs {
    padding: 5px 12px;
    border-radius: var(--ref-radius-control);
    font-size: var(--ref-fs-small);
    line-height: 1.5;
}

.ref-btn-primary,
.boat-rent-btn-primary,
.btn.settings-btn-primary {
    padding: 8px 18px;
    border: 1px solid var(--area-ink);
    border-radius: var(--ref-radius-control);
    background: var(--area-ink);
    color: var(--ref-on-fill);
    font-weight: 600;
    transition: all .15s ease;
}
.ref-btn-primary:hover, .ref-btn-primary:focus, .ref-btn-primary:active,
.boat-rent-btn-primary:hover, .boat-rent-btn-primary:focus, .boat-rent-btn-primary:active,
.btn.settings-btn-primary:hover, .btn.settings-btn-primary:focus, .btn.settings-btn-primary:active {
    border-color: var(--area-ink);
    background: var(--area-ink);
    color: var(--ref-on-fill);
    outline: none;
    box-shadow: var(--ref-wash);
}
.ref-btn-primary i,
.boat-rent-btn-primary i,
.btn.settings-btn-primary i { margin-right: 6px; color: var(--ref-on-fill); }
/* Disabled (a support session shows the person's buttons disabled, SupportSession): no wash on hover, focus or press —
   nothing happens there (from settings-pages.css on master, 2026-10). */
.ref-btn-primary[disabled], .ref-btn-primary[disabled]:hover, .ref-btn-primary[disabled]:focus, .ref-btn-primary[disabled]:active,
.boat-rent-btn-primary[disabled], .boat-rent-btn-primary[disabled]:hover, .boat-rent-btn-primary[disabled]:focus, .boat-rent-btn-primary[disabled]:active,
.btn.settings-btn-primary[disabled], .btn.settings-btn-primary[disabled]:hover, .btn.settings-btn-primary[disabled]:focus, .btn.settings-btn-primary[disabled]:active {
    border-color: var(--area-ink);
    background: var(--area-ink);
    color: var(--ref-on-fill);
    box-shadow: none;
}

.ref-btn-danger,
.boat-rent-btn-danger,
.btn.settings-btn-danger {
    padding: 8px 16px;
    border: 1px solid var(--ref-danger-edge);
    border-radius: var(--ref-radius-control);
    background: var(--ref-surface);
    color: var(--ref-danger);
    font-weight: var(--ref-fw-button);
    transition: all .15s ease;
}
.ref-btn-danger:hover, .ref-btn-danger:focus, .ref-btn-danger:active,
.boat-rent-btn-danger:hover, .boat-rent-btn-danger:focus, .boat-rent-btn-danger:active,
.btn.settings-btn-danger:hover, .btn.settings-btn-danger:focus, .btn.settings-btn-danger:active {
    border-color: var(--ref-danger-strong);
    background: var(--ref-danger-bg);
    color: var(--ref-danger);
    outline: none;
}
.ref-btn-danger i,
.boat-rent-btn-danger i,
.btn.settings-btn-danger i { margin-right: 6px; color: var(--ref-danger); }

.ref-btn:focus-visible, .ref-btn-primary:focus-visible, .ref-btn-danger:focus-visible,
.boat-rent-btn:focus-visible, .boat-rent-btn-primary:focus-visible, .boat-rent-btn-danger:focus-visible,
.btn.settings-btn:focus-visible, .btn.settings-btn-primary:focus-visible, .btn.settings-btn-danger:focus-visible { outline: none; box-shadow: var(--ref-focus-ring); }

/* ---- Note: a framed, tinted block that states ONE thing — a problem with the data, a warning, a piece of context ----
   D-10: the tone is the tinted ground and the full border, never a coloured stripe down the left edge. The settings
   cards that carry a note (`.inner-panel.settings-note-warn|info`) take the same tones. The pale grounds leave the
   tone to the title: #c0392b on #fdf8f7 is 4.63:1, #9a6410 on #fffdf7 4.44:1 at 13px/600. */
.ref-note,
.boat-rent-note {
    margin-bottom: 10px;
    padding: 10px 12px;
    border: 1px solid var(--ref-note-edge);
    border-radius: var(--ref-radius-control);
    background: var(--ref-note-bg);
}
.ref-note:last-child,
.boat-rent-note:last-child { margin-bottom: 0; }
.ref-note-danger, .boat-rent-note-danger { border-color: var(--ref-note-danger-edge); background: var(--ref-note-danger-bg); }
.ref-note-warn,   .boat-rent-note-warn   { border-color: var(--ref-note-warn-edge);   background: var(--ref-note-warn-bg); }
.ref-note-info,   .boat-rent-note-info   { border-color: var(--ref-note-info-edge);   background: var(--ref-note-info-bg); }
/* Something done or in order (D-52): the success tone of the family, as `.alert-success` (the Epson panel's «Issued»). */
.ref-note-ok,     .boat-rent-note-ok     { border-color: var(--ref-note-ok-edge);     background: var(--ref-note-ok-bg); }
.ref-note-title,
.boat-rent-note-title { display: flex; align-items: center; gap: 6px; color: var(--ref-ink); font-size: var(--ref-fs-small); font-weight: 600; }
.ref-note-danger .ref-note-title i, .boat-rent-note-danger .boat-rent-note-title i { color: var(--ref-danger); }
.ref-note-warn   .ref-note-title i, .boat-rent-note-warn   .boat-rent-note-title i { color: var(--ref-warn); }
.ref-note-info   .ref-note-title i, .boat-rent-note-info   .boat-rent-note-title i { color: var(--ref-info); }
.ref-note-ok     .ref-note-title i, .boat-rent-note-ok     .boat-rent-note-title i { color: var(--ref-ok); }
.ref-note p,
.boat-rent-note p { margin: 4px 0 0; color: var(--ref-muted); font-size: var(--ref-fs-small); }
.ref-note ul,
.boat-rent-note ul { margin: 6px 0 0; padding-left: 18px; color: var(--ref-ink-2); font-size: var(--ref-fs-small); }
.ref-note ul > li,
.boat-rent-note ul > li { margin-bottom: 2px; }
/* An HTMX failure inside a table (D-27, js/htmx-error.js): a compact danger note in a row of its own under the row that
   failed, one cell across the columns — never the page's white-on-red flash strip squeezed into a cell, which widened
   the column and shifted every other one. The sentence wraps under its icon. */
.ref-note.bs-htmx-error { margin: 0; padding: 6px 10px; }
.ref-note.bs-htmx-error .ref-note-title { align-items: flex-start; font-weight: 500; line-height: 1.4; }
.ref-note.bs-htmx-error .ref-note-title i { margin-top: 2px; }
.ref-note.bs-htmx-error .btn { margin-top: 6px; }
tr.bs-htmx-error-row > td { padding-top: 4px; }
.ref-skin .inner-panel.settings-note-warn,
.ref-skin .inner-panel.settings-note-warn:hover { border-color: var(--ref-note-warn-edge) !important; background: var(--ref-note-warn-bg) !important; }
.ref-skin .inner-panel.settings-note-info,
.ref-skin .inner-panel.settings-note-info:hover { border-color: var(--ref-note-info-edge) !important; background: var(--ref-note-info-bg) !important; }

/* ---- Inline code (D-57): a token, a function name, an article code — ONE chip on every page of the kit, whatever its
   area. Bootstrap's is crimson #c7254e on pink and `nowrap`; the chip of the settings area (until 2026-10-21 fenced to
   `body.bs-area-app .settings-page code`) turned back into it the moment a page moved to another area. It wraps (a
   snippet of ~90 characters, a list of ten function names) and keeps its ground on both halves; a `<pre>` block is
   not a chip. At the element's own weight (§2.1): a component that dresses its code (a chip's, a dropdown's) still
   does. ---- */
:where(.ref-skin) :not(pre) > code {
    padding: 1px 5px;
    border: 1px solid var(--ref-hairline);
    border-radius: var(--ref-radius-inset);
    background: var(--ref-surface-hover);
    color: var(--ref-ink);
    font-size: var(--ref-fs-small);
    white-space: normal;
    overflow-wrap: break-word;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}

/* =====================================================================================================================
   MODALS AND SERVICE MESSAGES (D-18) — one skin for the whole application, legacy pages included.
   306 views define a Bootstrap modal and every page can raise a dialog, a toast or a flash; their skin used to live in
   five places, each loaded by some pages only, so most of them showed Bootstrap's square modal (netwing's build zeroes
   its radius), SweetAlert2's own dialog, and flash strips that failed contrast. A modal is an object of its own: the
   design system's skin is right on an old page too. Properties a page may legitimately colour (a header's ground, a
   title's colour) are set at zero specificity (`:where()`), so a page's own class still wins whatever the order.
   ===================================================================================================================== */

/* ---- Bootstrap modal (D-15: 8 px) ---- */
.modal-content {
    border: none;
    border-radius: var(--ref-radius-control);
    box-shadow: var(--ref-shadow-modal);
}
.modal-header {
    padding: var(--ref-pad-card-y) 20px;
    border-bottom: 1px solid var(--ref-divider);
    border-radius: var(--ref-radius-control) var(--ref-radius-control) 0 0;
}
:where(.modal-header) { background: var(--ref-surface-head); }
:where(.modal-title) { color: var(--ref-ink); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); }
:where(.modal-title) > i { margin-right: 6px; color: var(--area-ink); }
.modal-body { padding: 16px 20px; }
/* Its actions at the bottom right, the primary last (D-109): Bootstrap's own alignment, stated by the kit. */
.modal-footer { padding: 12px 20px; border-top: 1px solid var(--ref-divider); text-align: right; }
/* The save beside the standard buttons (D-24): `bs-btn-save` is sized for the save pill (16 px type, 45 px tall); in a
   dialog's footer, beside «Cancel» (38 px), it takes their height. The guided form's step navigation (`cf-step-nav`,
   protected/views/shared/creationForm/_body.php) is the same line — «Back», then the save — and wrote it by hand; a
   card's own foot (`.ref-card-foot`, D-104) is the same line again. */
.modal-footer .bs-btn-save,
.cf-step-nav .bs-btn-save,
.ref-card-foot .bs-btn-save { min-height: 38px; padding: 8px 16px; font-size: var(--ref-fs-body); line-height: 20px; }
/* The dismiss glyph: Bootstrap's is #000 at .2 with a white text-shadow, about 1.6:1 on the header — often the only
   way out of a dialog. A 24 px target in the secondary ink. */
.modal .close {
    min-width: 24px;
    min-height: 24px;
    color: var(--ref-ink-2);
    line-height: 24px;
    text-align: center;
    text-shadow: none;
    opacity: 1;
}
.modal .close:hover,
.modal .close:focus { color: var(--ref-ink); opacity: 1; }

/* ---- The dialogs (js/bs-dialog.js puts `bs-dialog-popup` on every bsConfirm / bsChoice / bsError) ----
   SweetAlert2 measures its internals in `em` from a root this page does not control: the sizes are stated here, in
   the page's own steps. The buttons are `buttonsStyling: false` + Bootstrap classes, hence `.btn`. */
.swal2-popup.bs-dialog-popup { border-radius: var(--ref-radius-control); }
.swal2-popup.bs-dialog-popup .swal2-title { color: var(--ref-ink); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); }
/* The body in the second ink (SweetAlert2's #545454 is no step of the kit, D-26). */
.swal2-popup.bs-dialog-popup .swal2-html-container { color: var(--ref-ink-2); font-size: var(--ref-fs-body); }
.swal2-popup.bs-dialog-popup .swal2-footer { font-size: var(--ref-fs-small); }
/* The buttons at the bottom right, the primary last (D-109): bsConfirm / bsChoice write the confirm last
   (`reverseButtons`), SweetAlert2 centred the row. Through its own properties: the row as wide as the dialog, on the
   footer's 20 px, its buttons 8 px apart (bs-dialog.js gave each a side margin). */
.swal2-popup.bs-dialog-popup {
    --swal2-actions-justify-content: flex-end;
    --swal2-actions-width: 100%;
    --swal2-actions-margin: 1.25em 0 0;
    --swal2-actions-padding: 0 20px;
}
.swal2-popup.bs-dialog-popup .swal2-actions { gap: 8px; }
.bs-dialog-popup .swal2-actions .btn {
    margin: 0;
    padding: 8px 16px;
    border-radius: var(--ref-radius-control);
    font-weight: var(--ref-fw-button);
    box-shadow: none;
    transition: all .15s ease;
}
.bs-dialog-popup .swal2-cancel.btn,
.bs-dialog-popup .swal2-confirm.btn-default { border: 1px solid var(--ref-border); background: var(--ref-surface); color: var(--ref-ink); }
.bs-dialog-popup .swal2-cancel.btn:hover, .bs-dialog-popup .swal2-cancel.btn:focus,
.bs-dialog-popup .swal2-confirm.btn-default:hover, .bs-dialog-popup .swal2-confirm.btn-default:focus { border-color: var(--area-ink); background: var(--ref-surface-hover); color: var(--area-ink); }
.bs-dialog-popup .swal2-confirm.btn-danger { border: 1px solid var(--ref-danger-edge); background: var(--ref-surface); color: var(--ref-danger); }
.bs-dialog-popup .swal2-confirm.btn-danger:hover,
.bs-dialog-popup .swal2-confirm.btn-danger:focus { border-color: var(--ref-danger-strong); background: var(--ref-danger-bg); color: var(--ref-danger); }
.bs-dialog-popup .swal2-confirm.btn-primary { border: 1px solid var(--area-ink); background: var(--area-ink); color: var(--ref-on-fill); }
.bs-dialog-popup .swal2-confirm.btn-primary:hover,
.bs-dialog-popup .swal2-confirm.btn-primary:focus { border-color: var(--area-ink); background: var(--area-ink); color: var(--ref-on-fill); box-shadow: var(--ref-wash); }
/* SweetAlert2 focuses a button by script when the dialog opens: after a mouse click the browser drew its black ring on
   OK. The kit's own ring answers the keyboard (`:focus-visible`), and only it (D-26). */
.bs-dialog-popup .swal2-actions .btn:focus { outline: none; }
.bs-dialog-popup .swal2-actions .btn:focus-visible { outline: none; box-shadow: var(--ref-focus-ring); }
/* The icons in the kit's state tones (D-26): SweetAlert2's own read 2.79:1 (error), 1.69:1 (warning) and 2.05:1 (info)
   on white, under the 3:1 a glyph needs. A toast is a `.swal2-popup` too. Which icon a confirmation shows is the
   callers' rule: a destructive action the warning, any other the question (`js-settings-confirm(-form)`,
   `data-wh-confirm`, an htmx `data-confirm`). */
.swal2-popup .swal2-icon.swal2-error { border-color: var(--ref-danger); color: var(--ref-danger); }
.swal2-popup .swal2-icon.swal2-error [class^="swal2-x-mark-line"] { background-color: var(--ref-danger); }
.swal2-popup .swal2-icon.swal2-warning { border-color: var(--ref-warn); color: var(--ref-warn); }
.swal2-popup .swal2-icon.swal2-info,
.swal2-popup .swal2-icon.swal2-question { border-color: var(--ref-info); color: var(--ref-info); }
.swal2-popup .swal2-icon.swal2-success { border-color: var(--ref-ok); color: var(--ref-ok); }
.swal2-popup .swal2-icon.swal2-success .swal2-success-ring { border-color: var(--ref-ok-bg); }
.swal2-popup .swal2-icon.swal2-success [class^="swal2-success-line"] { background-color: var(--ref-ok); }
/* A dialog that asks for a text (the planning's «Write to the operators», a preset's name): the kit's field, not
   SweetAlert's own border and blue glow (review, 2026-10-19). */
.bs-dialog-popup .swal2-input,
.bs-dialog-popup .swal2-textarea {
    border: 1px solid var(--ref-border-field);
    border-radius: var(--ref-radius-control);
    box-shadow: none;
    color: var(--ref-ink);
    font-family: inherit;
    font-size: var(--ref-fs-body);
}
.bs-dialog-popup .swal2-input:focus,
.bs-dialog-popup .swal2-textarea:focus { border-color: var(--area-accent); outline: none; box-shadow: var(--ref-focus); }
.bs-dialog-popup .swal2-input::placeholder,
.bs-dialog-popup .swal2-textarea::placeholder { color: var(--ref-muted); opacity: 1; }
/* bsToast passes no class of its own: the toast is reached by SweetAlert2's. */
.swal2-toast { border-radius: var(--ref-radius-control); }
.swal2-toast .swal2-title { color: var(--ref-ink); font-size: var(--ref-fs-body); font-weight: var(--ref-fw-title); }
/* The sentence under a toast's title (what changed, who was told): SweetAlert2 sizes it 1em of the 10 px root, 10 px
   (D-26). `body` lifts it over SweetAlert2's own `.swal2-popup.swal2-toast .swal2-html-container`. */
body .swal2-popup.swal2-toast .swal2-html-container { color: var(--ref-ink-2); font-size: var(--ref-fs-small); }

/* ---- Bootstrap's tooltip (D-26): the page's typeface at 13 px on the kit's ink, the inset radius — it was Helvetica
   12 px on a square black box beside the page's Quicksand. `body` lifts it over the framework sheet. ---- */
body .tooltip { font-family: inherit; font-size: var(--ref-fs-small); }
body .tooltip.in { opacity: 1; }
body .tooltip .tooltip-inner { padding: 4px 8px; border-radius: var(--ref-radius-inset); background-color: var(--ref-ink); color: var(--ref-on-fill); }
body .tooltip.top .tooltip-arrow,
body .tooltip.top-left .tooltip-arrow,
body .tooltip.top-right .tooltip-arrow { border-top-color: var(--ref-ink); }
body .tooltip.bottom .tooltip-arrow,
body .tooltip.bottom-left .tooltip-arrow,
body .tooltip.bottom-right .tooltip-arrow { border-bottom-color: var(--ref-ink); }
body .tooltip.left .tooltip-arrow { border-left-color: var(--ref-ink); }
body .tooltip.right .tooltip-arrow { border-right-color: var(--ref-ink); }

/* ---- toastr (the notifications' toasts): the state colours, which carry a white label at AA ----
   `body` raises the selectors above toastr's own sheet, which the layouts load after this one. */
body #toast-container > div { border-radius: var(--ref-radius-control); box-shadow: var(--ref-shadow-pop); opacity: 1; }
body #toast-container > .toast-success { background-color: var(--ref-ok); }
body #toast-container > .toast-error   { background-color: var(--ref-danger); }
body #toast-container > .toast-info    { background-color: var(--ref-info); }
body #toast-container > .toast-warning { background-color: var(--ref-warn); }

/* ---- The layout's flash strip (`.heavy-alert-*`, css/application.css): the state colours under the white text ----
   The legacy fills failed: warning #FF8800 2.39:1, info #0099CC 3.27:1 (the «unbilled services and/or unpaid
   invoices» strip on every customer record). Until 2026-10-14 only a settings page got measured ones. */
.heavy-alert { border-radius: var(--ref-radius-control); }
.heavy-alert-success { background-color: var(--ref-ok); }
.heavy-alert-info    { background-color: var(--ref-info); }
.heavy-alert-warning { background-color: var(--ref-warn); }
.heavy-alert-danger  { background-color: var(--ref-danger); }
/* …and on the page's frame (D-71). The strip spans #page (15 px from the screen's edges, 15–1485 at 1500) while a page
   on the kit frames itself (RefUi::pageBegin(): 1500 or 1760 px, 24 px of padding): the cards ran 40–1460 under a
   strip wider than the page. Where the frame is the page itself (//layouts/main: `#page > .ref-page`), the layout's
   strip takes the frame's content box; a frame in a dialog (`--flush`) has none, and an htmx error built inside a
   card wears the same class and keeps its card's width. The customer hub's own padding: css/settings-pages.css. */
body:has(#page > :is(.ref-page, .settings-page):not(.ref-page--flush)) #page > .row > .col-xs-12 > .heavy-alert {
    width: calc(100% - 2 * var(--ref-page-pad));
    max-width: calc(var(--ref-page-max) - 2 * var(--ref-page-pad));
    margin-left: auto;
    margin-right: auto;
}
body:has(#page > .ref-page--wide:not(.ref-page--flush)) #page > .row > .col-xs-12 > .heavy-alert {
    max-width: calc(var(--ref-page-max-wide) - 2 * var(--ref-page-pad));
}

/* ---- Bootstrap's `.alert` in a view: a note (tinted ground, full border, the tone in the border and the ground) ---- */
.alert { padding: 12px 14px; border-radius: var(--ref-radius-control); }
.alert-info    { border-color: var(--ref-note-info-edge);   background-color: var(--ref-note-info-bg);   color: var(--ref-ink); }
.alert-warning { border-color: var(--ref-note-warn-edge);   background-color: var(--ref-note-warn-bg);   color: var(--ref-ink); }
.alert-danger  { border-color: var(--ref-note-danger-edge); background-color: var(--ref-note-danger-bg); color: var(--ref-ink); }
.alert-success { border-color: var(--ref-note-ok-edge);     background-color: var(--ref-note-ok-bg);     color: var(--ref-ink); }
/* Its links (D-53): one style in every note — the area's ink at 600, underlined under the pointer — instead of
   Bootstrap's blue (3.45:1 on the danger ground) beside a dark-red `alert-link`. Not in the layout's flash strip
   (`.alert.heavy-alert`: white on a filled tone, css/application.css). A record's value that is a link (a customer,
   a document) on a page of the kit is written the same.
   And a link in a kit note, `.ref-note` in every tone, on a page of the kit (D-107): there it was Bootstrap's blue,
   3.5:1 on the info tint. Its selector weighs one class, so a page that colours its notes' links on purpose keeps its
   colour (the warehouse pages: the ink, underlined); a kit link button keeps its own look; a page off the kit (the
   invoice upload pages) is not touched. */
.alert:not(.heavy-alert) a:not(.btn),
:where(.ref-skin) .form-control-static a:not(.btn),
:where(.ref-skin) :where(.ref-note, .boat-rent-note) a:not(.btn, .ref-link-btn) { color: var(--area-ink); font-weight: 600; }
.alert:not(.heavy-alert) a:not(.btn):is(:hover, :focus),
:where(.ref-skin) .form-control-static a:not(.btn):is(:hover, :focus),
:where(.ref-skin) :where(.ref-note, .boat-rent-note) a:not(.btn, .ref-link-btn):is(:hover, :focus) { color: var(--area-ink); text-decoration: underline; }

/* ---- Search box (docs/reference-style.md §6): `.ref-search` around a Bootstrap input-group — the magnifier, the field,
   an optional clear (`.btn-clear`); borderless addons, the focus ring on the whole box. `.boat-rent-search` is its alias.
   The field skin of css/settings-pages.css stays out of it (`:where(:not(.ref-search *))`): it draws its own field.
   The magnifier is a decorative glyph (`--ref-glyph`, say nothing the placeholder does not); the clear is a control,
   so its ink is the readable `--ref-muted`, and its red only on hover. ---- */
.ref-search,
.boat-rent-search { background: var(--ref-surface); border: 1px solid var(--ref-border-field); border-radius: var(--ref-radius-control); box-shadow: var(--ref-shadow-soft); } /* a control's boundary, ≥ 3:1 (D-31) */
.ref-search .input-group,
.boat-rent-search .input-group { width: 100%; }
.ref-search .input-group-addon,
.boat-rent-search .input-group-addon { background: transparent; border: none; }
.ref-search .input-group-addon:first-child,
.boat-rent-search .input-group-addon:first-child { padding: 0 8px 0 14px; color: var(--ref-glyph); }
.ref-search .form-control,
.boat-rent-search .form-control { border: none; box-shadow: none; height: 40px; font-size: var(--ref-fs-body); color: var(--ref-ink); background: transparent; }
.ref-search .form-control:focus,
.boat-rent-search .form-control:focus { box-shadow: none; }
/* Bootstrap's placeholder is #999 (2.85:1): the muted ink, as the Select2 placeholder below. */
.ref-search .form-control::placeholder,
.boat-rent-search .form-control::placeholder { color: var(--ref-muted); opacity: 1; }
.ref-search:focus-within,
.boat-rent-search:focus-within { border-color: var(--area-accent); box-shadow: var(--ref-focus); }
.ref-search .btn-clear,
.boat-rent-search .btn-clear { padding: 0 14px 0 8px; cursor: pointer; color: var(--ref-muted); transition: color .2s ease; }
.ref-search .btn-clear:hover,
.boat-rent-search .btn-clear:hover { color: var(--ref-danger-strong); }

/* ---- Native field (`.ref-native-field`, alias `.boat-rent-native-field`): a date, time or number input dressed as the
   Select2 box beside it, so a row of mixed controls lines up (§7). ---- */
.ref-native-field,
.boat-rent-native-field {
    height: 42px; border: 1px solid var(--ref-border-field); border-radius: var(--ref-radius-control); padding: 6px 12px;
    box-shadow: none; color: var(--ref-ink); transition: all .2s ease;
}
.ref-native-field:focus,
.boat-rent-native-field:focus { border-color: var(--area-accent); box-shadow: var(--ref-focus); }
.ref-native-field::-webkit-calendar-picker-indicator,
.boat-rent-native-field::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .55; transition: opacity .2s ease; }
.ref-native-field:hover::-webkit-calendar-picker-indicator,
.boat-rent-native-field:hover::-webkit-calendar-picker-indicator { opacity: .9; }

/* ---- A label ABOVE its field in a legacy `form-horizontal` (D-35): Bootstrap right-aligns `.form-horizontal
   .control-label` from 768 px for a label BESIDE its field, and a stacked label that wraps — in a column, followed by its
   control — came out right-aligned (the contract forms' estimated arrival and departure at 1024). Left, on every page;
   a side label alone in its own column (the last child) keeps Bootstrap's. ---- */
.form-horizontal [class*="col-"] > .control-label:not(:last-child) { text-align: left; }

/* ---- Choice chip (`.ref-chip`, alias `.boat-rent-chip`): a preset, a filter, an add-on to pick. Selected it is filled
   with the area's ink (it carries a white label: the ink is the step that clears 4.5:1 in every area); an add-on
   already taken is quiet and inert. ---- */
.ref-chip,
.boat-rent-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--ref-surface); border: 1px solid var(--ref-border); border-radius: var(--ref-radius-pill); color: var(--ref-ink); font-size: var(--ref-fs-small); font-weight: var(--ref-fw-button); padding: 6px 14px; cursor: pointer; transition: all .15s ease; }
.ref-chip i,
.boat-rent-chip i { color: var(--area-ink); font-size: var(--ref-fs-micro); }
.ref-chip:hover:not(.is-added):not(.is-active),
.boat-rent-chip:hover:not(.is-added) { background: var(--area-accent-ring); border-color: var(--area-accent); color: var(--area-ink); }
.ref-chip:focus-visible,
.boat-rent-chip:focus-visible { outline: none; box-shadow: var(--ref-focus-ring); }
.ref-chip.is-active { background: var(--area-ink); border-color: var(--area-ink); color: var(--ref-on-fill); }
.ref-chip.is-active i { color: var(--ref-on-fill); }
.ref-chip.is-added,
.boat-rent-chip.is-added { background: var(--ref-surface-hover); border-color: var(--ref-border); color: var(--ref-glyph); cursor: default; }
.ref-chip.is-added i,
.boat-rent-chip.is-added i { color: var(--area-ink); }

/* ---- Choice list (`.ref-choice-list` > `label.ref-choice`, D-49): pick ONE record among a few — a radio per row, the
   whole row its label: the title (`<strong>`), its chips and a link to open it on one wrapping line, a hint under
   them. The rows are divided, never cards in the card; the chosen one reads chosen by more than its 13 px dot (the
   header's ground and a ring in the area's accent, drawn inside the row). From the delivery note's review, where it
   was `.wh-choices`. ---- */
.ref-choice-list { overflow: hidden; border: 1px solid var(--ref-hairline); border-radius: var(--ref-radius-control); }
.ref-choice-list > .ref-choice {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin: 0;
    padding: 12px 14px;
    border-top: 1px solid var(--ref-divider);
    color: var(--ref-ink);
    font-weight: 400;
    cursor: pointer;
}
.ref-choice-list > .ref-choice:first-child { border-top: none; }
.ref-choice-list > .ref-choice:hover { background: var(--ref-surface-head); }
.ref-choice-list > .ref-choice:has(> input:checked) { background: var(--ref-surface-head); outline: 1px solid var(--area-ink); outline-offset: -1px; }
.ref-choice-list > .ref-choice.is-disabled { color: var(--ref-muted); cursor: not-allowed; }
/* A fill under a white glyph is the area's ink. */
.ref-choice-list > .ref-choice > input[type="radio"] { flex: 0 0 auto; margin: 3px 0 0; accent-color: var(--area-ink); }
.ref-choice-text { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-width: 0; }
/* The «open it» icon link: a 24 × 24 target in the area's ink. */
.ref-choice-text > a { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px; color: var(--area-ink); }
.ref-choice-text > a:hover,
.ref-choice-text > a:focus { color: var(--ref-ink); }
/* A date beside the title, and the hint on a line of its own under it. */
.ref-choice-meta,
.ref-choice-hint { color: var(--ref-muted); font-size: var(--ref-fs-small); }
.ref-choice-hint { flex-basis: 100%; }
/* ---- Link list (`.ref-link-list` in a card's body, D-64): a card that is a list of pages — each row a link with its
   title, a 13 px line saying what it is for, and a trailing glyph (`.ref-link-list-go`): the chevron to go, a padlock
   where the person may not open the page (`is-locked`, a row without a link), an action's glyph where the row RUNS
   something (`is-action`, it asks first). The row answers the pointer; the card stays at rest (D-48). Promoted from the
   Settings hub (2026-10-21), whose cards were built by hand: a 20 px header, a 16 px title, a 4 px lift. ---- */
.ref-card-body:has(> .ref-link-list) { padding: 0; }
.ref-link-list-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ref-gap);
    padding: var(--ref-gap) var(--ref-pad-card-x);
    border-bottom: 1px solid var(--ref-divider);
    color: var(--ref-ink);
    text-decoration: none;
    transition: background-color .2s ease;
}
.ref-link-list-item:last-child { border-bottom: 0; }
a.ref-link-list-item:hover,
a.ref-link-list-item:focus { background: var(--ref-surface-hover); color: var(--ref-ink); text-decoration: none; }
a.ref-link-list-item:focus { outline: none; }
a.ref-link-list-item:focus-visible { box-shadow: var(--ref-focus-inset); }
.ref-link-list-body { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; }
.ref-link-list-title { margin-bottom: 2px; color: var(--ref-ink); font-size: var(--ref-fs-body); font-weight: var(--ref-fw-button); }
.ref-link-list-desc { color: var(--ref-ink-2); font-size: var(--ref-fs-small); line-height: 1.4; }
.ref-link-list-go { flex: 0 0 auto; color: var(--ref-muted); font-size: var(--ref-fs-small); transition: transform .2s ease, color .2s ease; }
a.ref-link-list-item:hover .ref-link-list-go,
a.ref-link-list-item:focus-visible .ref-link-list-go { color: var(--area-ink); }
a.ref-link-list-item:not(.is-action):hover .ref-link-list-go { transform: translateX(3px); }
.ref-link-list-item.is-locked { cursor: default; }
/* Not paler than its own description. */
.ref-link-list-item.is-locked .ref-link-list-title { color: var(--ref-ink-2); }

/* ---- Document as printed (`.ref-receipt`, D-61, alias `.epson-receipt`): a receipt as it comes out — the lines in the
   printer's monospace, a line that only carries text muted and set in, a discount as a minus in the danger ink, the
   TOTAL under a dashed rule. Alone it is a paper-like card; in a kit card's body it drops its own frame. Written by the
   partial admin/views/_shared/_receipt_preview.php (ReceiptPreview), on the point-of-sale receipt and the Epson page. ---- */
.ref-receipt,
.epson-receipt {
    padding: 20px var(--ref-pad-card-x);
    border: 1px solid var(--ref-hairline);
    border-radius: var(--ref-radius-card);
    background: var(--ref-surface);
    color: var(--ref-ink-title);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--ref-fs-body);
}
.ref-card-body > .ref-receipt,
.ref-card-body > .epson-receipt { padding: 0; border: 0; border-radius: 0; background: none; }
.ref-receipt-row,
.epson-receipt__row { display: flex; justify-content: space-between; gap: 16px; padding: 4px 0; }
.ref-receipt-row--message,
.epson-receipt__row--message { padding-left: 12px; color: var(--ref-muted); }
.ref-receipt-row--minus .ref-receipt-amount,
.epson-receipt__row--minus .epson-receipt__amount { color: var(--ref-danger); }
.ref-receipt-qty,
.epson-receipt__qty { margin-left: var(--ref-gap-sm); color: var(--ref-muted); white-space: nowrap; }
.ref-receipt-amount,
.epson-receipt__amount { white-space: nowrap; }
.ref-receipt-total,
.epson-receipt__total { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--ref-border-soft); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); }

/* ---- Drop zone (`.ref-dropzone` on a Dropzone form, D-62; aliases `.bs-invup-drop` and a settings page's `.dropzone`):
   ONE skin for «drop a file here» — the soft dashes, the control's radius, the area's accent under the pointer and while
   a file is over it (the message stays readable: the library fades it to half), and a keyboard focus that shows (the
   library's button inherits no outline). The legacy box of css/application.css is fenced off these names, so nothing
   here needs `!important`. A settings page's zone keeps its lower floor. ---- */
.settings-page .dropzone,
.ref-dropzone.dropzone,
.bs-invup-drop.dropzone {
    min-height: 120px;
    background: var(--ref-surface-head);
    border: 2px dashed var(--ref-border-soft);
    border-radius: var(--ref-radius-control);
    transition: border-color .15s ease, background-color .15s ease;
}
.ref-dropzone.dropzone,
.bs-invup-drop.dropzone { min-height: 150px; padding: 20px; }
.settings-page .dropzone:hover,
.settings-page .dropzone.dz-drag-hover,
.ref-dropzone.dropzone:hover,
.ref-dropzone.dropzone.dz-drag-hover,
.bs-invup-drop.dropzone:hover,
.bs-invup-drop.dropzone.dz-drag-hover { border-style: dashed; border-color: var(--area-accent); background: var(--ref-surface-hover); }
.settings-page .dropzone.dz-drag-hover .dz-message,
.ref-dropzone.dropzone.dz-drag-hover .dz-message,
.bs-invup-drop.dropzone.dz-drag-hover .dz-message { opacity: 1; color: var(--area-ink); }
.ref-dropzone.dropzone .dz-message,
.bs-invup-drop.dropzone .dz-message { margin: 24px 0; color: var(--ref-muted); font-size: var(--ref-fs-body); }
/* The keyboard: the library's button takes the focus and shows the kit's ring; the zone's border says where it is. */
.settings-page .dropzone .dz-message .dz-button:focus-visible,
.ref-dropzone.dropzone .dz-message .dz-button:focus-visible,
.bs-invup-drop.dropzone .dz-message .dz-button:focus-visible { outline: none; border-radius: var(--ref-radius-inset); box-shadow: var(--ref-focus-ring); }
.settings-page .dropzone:has(.dz-button:focus-visible),
.ref-dropzone.dropzone:has(.dz-button:focus-visible),
.bs-invup-drop.dropzone:has(.dz-button:focus-visible) { border-color: var(--area-ink); }
/* A zone that is itself the button (the attachments' uploader, `role="button"`). */
.settings-page .dropzone[role="button"]:focus-visible { outline: none; border-color: var(--area-ink); box-shadow: var(--ref-focus-ring); }
.ref-dropzone.dropzone .dz-preview .dz-image,
.ref-dropzone.dropzone .dz-preview.dz-file-preview .dz-image,
.bs-invup-drop.dropzone .dz-preview .dz-image,
.bs-invup-drop.dropzone .dz-preview.dz-file-preview .dz-image { border-radius: var(--ref-radius-control); }

/* ---- Picture slot (`.ref-picture-slot`, D-62): one picture a record keeps (a boat model's logo, its photo) — its title,
   what it is for, the frame of the current picture, then «Replace» (the drop zone drawn as a small button: a file
   dropped on it still replaces the picture) and «Remove» on one line; with no picture yet, the drop zone itself. A
   picture that may be see-through (a logo) is `--transparent`: a light checkerboard shows it. ---- */
.ref-picture-slot-title { margin: 0 0 var(--ref-gap-sm); color: var(--ref-ink); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); }
.ref-picture-slot-title > i { margin-right: 6px; color: var(--area-ink); }
.ref-picture-slot-help { margin: 0 0 var(--ref-gap); }
.ref-picture-slot-frame {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 180px;
    margin-bottom: var(--ref-gap-sm);
    padding: var(--ref-gap);
    overflow: hidden;
    border: 1px solid var(--ref-border);
    border-radius: var(--ref-radius-control);
    background: var(--ref-surface-sunk);
}
.ref-picture-slot--transparent .ref-picture-slot-frame {
    background-color: var(--ref-surface);
    background-image: repeating-conic-gradient(var(--ref-surface-sunk) 0% 25%, var(--ref-surface) 0% 50%);
    background-size: 16px 16px;
}
.ref-picture-slot-frame img { max-width: 100%; max-height: 100%; object-fit: contain; }
.ref-picture-slot-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ref-gap-sm); margin-bottom: var(--ref-gap); }
.ref-picture-slot-actions > form { margin: 0; }
.ref-picture-slot-actions .ref-dropzone.dropzone { min-height: 0; padding: 0; border: 1px solid var(--ref-border); background: var(--ref-surface); }
.ref-picture-slot-actions .ref-dropzone.dropzone:hover,
.ref-picture-slot-actions .ref-dropzone.dropzone.dz-drag-hover { border-style: solid; border-color: var(--area-accent); background: var(--ref-surface-hover); }
.ref-picture-slot-actions .ref-dropzone.dropzone .dz-message { margin: 0; }
.ref-picture-slot-actions .ref-dropzone.dropzone .dz-message .dz-button { padding: 5px 12px; color: var(--ref-ink); font-size: var(--ref-fs-body); font-weight: var(--ref-fw-button); }
.ref-picture-slot-actions .ref-dropzone.dropzone .dz-message .dz-button > i { margin-right: 6px; color: var(--area-ink); }
/* While the file goes up the button stays, dimmed (the page reloads on success): no preview tile in a button. */
.ref-picture-slot-actions .ref-dropzone.dropzone .dz-preview { display: none; }
.ref-picture-slot-actions .ref-dropzone.dropzone.dz-started .dz-message { display: block; opacity: .6; }

/* ---- Signature cards (`ref-sign-*`, D-63): the simple signature as three ordered cards — the document to sign, how to
   sign (one tile per way offered, two by two), where the signature is — written by //signature/_sidebar_cards.php for
   the contract wizard and, in its main column, the boat sale. Promoted by ADDING these names beside the wizard's `cw-*`
   ones: the wizard's own rules (css/contract-wizard.css, under `.contract-wizard`) outweigh these and declare the same
   properties, so the wizard does not change. `ref-link-btn` is the kit's link button: an action that reads as a link
   (a preview, a refresh, a download), never the primary. ---- */
.ref-sign-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 20px; }
.ref-sign-save-state { margin: 0; min-height: 20px; text-align: right; }
.ref-sign-preview { margin: 0 0 14px; }
.ref-sign-methods { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.ref-sign-method { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding: 16px; border: 1px solid var(--ref-border); border-radius: var(--ref-radius-control); }
.ref-sign-method h4 { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; color: var(--ref-ink); font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); }
.ref-sign-method h4 > i { width: 18px; color: var(--area-ink); text-align: center; }
.ref-sign-method p { margin: 0; color: var(--ref-ink-2); }
.ref-sign-method .form-group { width: 100%; margin-bottom: 0; }
.ref-sign-method > .btn { margin-top: auto; }
.ref-sign-qr { width: 160px; height: 160px; align-self: center; }
.ref-sign-list li { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--ref-divider); font-size: var(--ref-fs-body); }
@media (max-width: 767px) {
    .ref-sign-grid-2,
    .ref-sign-methods { grid-template-columns: minmax(0, 1fr); }
}
.ref-link-btn { min-height: 24px; padding: 3px 0; border: 0; background: none; color: var(--area-primary); font-weight: var(--ref-fw-button); text-decoration: underline; text-decoration-color: var(--area-accent); text-underline-offset: 2px; }
.ref-link-btn:hover { color: var(--area-primary-dark); text-decoration-thickness: 2px; }
.ref-link-btn:focus { outline: none; }
.ref-link-btn:focus-visible { border-radius: var(--ref-radius-inset); box-shadow: var(--ref-focus-ring); }
/* Disabled (D-105), as the neutral button: the muted ink, the underline a soft line, nothing under the pointer — the
   Epson panel's «Test print» while the printer works. */
.ref-link-btn:is([disabled], .disabled, [aria-disabled="true"]),
.ref-link-btn:is([disabled], .disabled, [aria-disabled="true"]):is(:hover, :focus, :active) {
    color: var(--ref-muted);
    text-decoration-color: var(--ref-border-soft);
    text-decoration-thickness: auto;
    opacity: 1;
    cursor: not-allowed;
}

/* ---- App badge (`AppBadge::html()`, D-65, alias `bs-app-badge`): an installable app as the back office names it — its
   icon (root's, or the app's glyph on a tile in the area's ink) and its commercial name, grey when the app is off. On
   the ramps, with no shadow of its own: 8 px, 12 px in the heading of an app's pages. Promoted from css/app-badge.css
   (2026-10-21), whose tile was the Settings blue written by hand, at 7 and 10 px. ---- */
.ref-app-badge,
.bs-app-badge { display: inline-flex; align-items: center; gap: var(--ref-gap-sm); vertical-align: middle; }
.ref-app-badge-icon,
.bs-app-badge__icon { flex: 0 0 28px; width: 28px; height: 28px; border-radius: var(--ref-radius-control); object-fit: cover; }
.ref-app-badge-icon--glyph,
.bs-app-badge__icon--glyph { display: inline-flex; align-items: center; justify-content: center; background: var(--area-ink); color: var(--ref-on-fill); font-size: var(--ref-fs-body); }
/* White on its tile wherever it sits (a settings heading paints its own glyphs). */
.ref-app-badge .ref-app-badge-icon--glyph i,
.bs-app-badge .bs-app-badge__icon--glyph i { color: var(--ref-on-fill); font-size: inherit; }
.ref-app-badge-name,
.bs-app-badge__name { font-weight: var(--ref-fw-title); }
.ref-app-badge.is-off .ref-app-badge-icon,
.bs-app-badge.is-off .bs-app-badge__icon { filter: grayscale(1); opacity: .45; }
.ref-app-badge.is-off .ref-app-badge-name,
.bs-app-badge.is-off .bs-app-badge__name { color: var(--ref-muted); }
/* As a button (My profile, an app's page): Bootstrap's own button, the badge inside. */
.btn.ref-app-badge,
.btn.bs-app-badge { padding: 6px 12px 6px 6px; }
.btn.ref-app-badge[disabled],
.btn.ref-app-badge[disabled]:hover,
.btn.ref-app-badge[disabled]:focus,
.btn.ref-app-badge[disabled]:active,
.btn.bs-app-badge[disabled],
.btn.bs-app-badge[disabled]:hover,
.btn.bs-app-badge[disabled]:focus,
.btn.bs-app-badge[disabled]:active { opacity: 1; border-color: var(--ref-border); background: var(--ref-surface-sunk); cursor: not-allowed; }
/* A row of them (My profile). */
.ref-app-badges,
.bs-app-badges { display: flex; flex-wrap: wrap; gap: var(--ref-gap-sm); }
/* The heading of an app's own pages (AppBadge::title()). */
.ref-app-badge--title,
.bs-app-badge--title { gap: var(--ref-gap); }
.ref-app-badge--title .ref-app-badge-icon,
.bs-app-badge--title .bs-app-badge__icon { flex-basis: 40px; width: 40px; height: 40px; border-radius: var(--ref-radius-card); }
.ref-app-badge--title .ref-app-badge-icon--glyph,
.bs-app-badge--title .bs-app-badge__icon--glyph { font-size: var(--ref-fs-section); }
/* In a title of its own (an app's page, a row of the Settings hub): the title's weight. */
.ref-app-badge--title .ref-app-badge-name,
.bs-app-badge--title .bs-app-badge__name,
.ref-link-list-title .ref-app-badge-name { font-weight: inherit; }
/* ---- Toggle pill (`.toggle-pill`, §7, D-33): one option of a selection, on or off — a checkbox for a multiple choice, a
   radio for a single one, nested INSIDE the label so the whole pill is the target. Moved here from css/application.css
   (2026-10-21), where it had a literal green, no keyboard focus and a ✕ at 2.0:1:
   - on: filled with the area's ink under a white label (D-1, §1.1) — the class the pages set (`pill-active`) or the
     checked input itself (a «select all» that sets `.checked` fires no event);
   - off: the sunk ground, its ✕ in the readable muted ink; a RADIO off is an empty ring — a ✕ read «refused»;
   - the kit's focus ring on the pill when its (invisible) input has the keyboard focus. ---- */
.toggle-pill {
    display: inline-flex; align-items: center; margin: 0; padding: 6px 14px;
    border: 1px solid var(--ref-border); border-radius: var(--ref-radius-pill); background-color: var(--ref-surface-sunk);
    color: var(--ref-ink-2); font-size: var(--ref-fs-small); font-weight: var(--ref-fw-title);
    cursor: pointer; user-select: none; white-space: nowrap; transition: all .2s cubic-bezier(.4, 0, .2, 1);
}
.toggle-pill:hover { border-color: var(--ref-glyph); }
.toggle-pill .toggle-pill-input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-pill .pill-icon { display: inline-flex; justify-content: center; width: 14px; margin-right: 6px; }
.toggle-pill .pill-icon-on { display: none; }
.toggle-pill .pill-icon-off { display: inline; color: var(--ref-muted); }
.toggle-pill:has(.toggle-pill-input[type="radio"]:not(:checked)):not(.pill-active) .pill-icon-off { display: none; }
.toggle-pill:has(.toggle-pill-input[type="radio"]:not(:checked)):not(.pill-active) .pill-icon::before {
    content: ""; display: block; box-sizing: border-box; width: 12px; height: 12px;
    border: 2px solid var(--ref-muted); border-radius: var(--ref-radius-pill);
}
.toggle-pill.pill-active,
.toggle-pill:has(.toggle-pill-input:checked) {
    background-color: var(--area-ink); border-color: var(--area-ink); color: var(--ref-on-fill); box-shadow: var(--ref-shadow-on);
}
.toggle-pill.pill-active .pill-icon-on,
.toggle-pill:has(.toggle-pill-input:checked) .pill-icon-on { display: inline; color: var(--ref-on-fill); }
.toggle-pill.pill-active .pill-icon-off,
.toggle-pill:has(.toggle-pill-input:checked) .pill-icon-off { display: none; }
.toggle-pill:has(.toggle-pill-input:focus-visible) { box-shadow: var(--ref-focus-ring); }

/* ---- Select2 v3.5 page skin, off the settings field skin (§5): `containerCssClass: 'ref-page-select', dropdownCssClass:
   'ref-drop'` (aliases `boat-rent-page-select` / `boat-rent-drop`). The same 42 px box as `.ref-native-field`; a
   MULTIPLE select (`.select2-choices`) wears it too. The arrow sprite sits at 7 px, the centre of THIS box, not the
   vendor's 3 px. The highlighted result is a light surface with dark text and an ink bar — never an accent fill, which
   carries select2-bootstrap's white label at 2.41:1 (ReferenceComponentContractTest). ---- */
.ref-page-select .select2-choice,
.boat-rent-page-select .select2-choice {
    height: 42px !important; padding: 6px 12px !important; border: 1px solid var(--ref-border-field) !important; border-radius: var(--ref-radius-control) !important;
    background-color: var(--ref-surface) !important; background-image: none !important; box-shadow: none !important;
    display: flex !important; align-items: center; color: var(--ref-ink); font-size: var(--ref-fs-body); transition: all .2s ease;
}
.ref-page-select .select2-choice > .select2-chosen,
.boat-rent-page-select .select2-choice > .select2-chosen { margin-right: 0; overflow: hidden; text-overflow: ellipsis; }
.ref-page-select .select2-choice .select2-arrow,
.boat-rent-page-select .select2-choice .select2-arrow { background: transparent !important; border-left: none !important; width: 28px !important; }
.ref-page-select .select2-choice .select2-arrow b,
.boat-rent-page-select .select2-choice .select2-arrow b { display: block !important; width: 18px !important; margin: 0 auto !important; background-position: 0 7px !important; }
.ref-page-select.select2-dropdown-open .select2-choice .select2-arrow b,
.boat-rent-page-select.select2-dropdown-open .select2-choice .select2-arrow b { background-position: -18px 7px !important; }
.ref-page-select.select2-container-active .select2-choice,
.boat-rent-page-select.select2-container-active .select2-choice { border-color: var(--area-accent) !important; box-shadow: var(--ref-focus) !important; }
.ref-page-select .select2-choices,
.boat-rent-page-select .select2-choices {
    min-height: 42px !important; padding: 0 6px !important; border: 1px solid var(--ref-border-field) !important; border-radius: var(--ref-radius-control) !important;
    background-color: var(--ref-surface) !important; background-image: none !important; box-shadow: none !important;
    color: var(--ref-ink); font-size: var(--ref-fs-body); transition: all .15s ease;
}
.ref-page-select.select2-container-active .select2-choices,
.boat-rent-page-select.select2-container-active .select2-choices { border-color: var(--area-accent) !important; box-shadow: var(--ref-focus) !important; }
.ref-page-select.select2-dropdown-open .select2-choices,
.boat-rent-page-select.select2-dropdown-open .select2-choices,
.ref-page-select.select2-dropdown-open .select2-choice,
.boat-rent-page-select.select2-dropdown-open .select2-choice { border-bottom-left-radius: 0 !important; border-bottom-right-radius: 0 !important; }
/* The chosen values of a MULTIPLE select (D-37): ONE skin, wherever the select is — the field skin of a page on the kit
   (css/settings-pages.css: radius 6, literal greys) and this page skin (radius 4, tokens) had two, and their «×» sat
   4 px above the text's centre. The sunk ground, the chip's line, the ink (9.95:1), the grid's radius; the «×» — a
   SPRITE slice of select2.png, the vendor's 12 × 13 box (the sheet's rows are 11 px apart) — centred on the line,
   5 px from the edge and 5 px from the text. The margins keep a 42 px box with one row of chips (3 + 4 + 28 + 4 + 3). */
:where(.ref-skin) .select2-container-multi .select2-choices .select2-search-choice,
.ref-page-select .select2-search-choice,
.boat-rent-page-select .select2-search-choice {
    background: var(--ref-surface-sunk) !important; background-image: none !important; border: 1px solid var(--ref-border) !important;
    border-radius: var(--ref-radius-inset) !important; box-shadow: none !important; color: var(--ref-ink) !important;
    margin: 4px 0 4px 4px !important; padding: 4px 8px 4px 22px !important; line-height: 18px !important;
}
:where(.ref-skin) .select2-container-multi .select2-choices .select2-search-choice-close,
.ref-page-select .select2-search-choice .select2-search-choice-close,
.boat-rent-page-select .select2-search-choice .select2-search-choice-close {
    left: 5px !important; top: 50% !important; margin-top: -7px !important;
}
/* The single select's clear «×»: the vendor's anchor and box; only the width is ours, for the hit area. */
.ref-page-select .select2-choice .select2-search-choice-close,
.boat-rent-page-select .select2-choice .select2-search-choice-close { width: 16px; height: 13px; background-position: right top; }
.ref-page-select .select2-choices .select2-search-field input,
.boat-rent-page-select .select2-choices .select2-search-field input { height: 32px; }
.ref-page-select .select2-choices .select2-search-field input::placeholder,
.boat-rent-page-select .select2-choices .select2-search-field input::placeholder { color: var(--ref-muted); opacity: 1; }
/* The placeholder: Select2 ships #999 (2.85:1); `select2-default` sits on the choice anchor, hence the descendant. */
.ref-page-select .select2-default .select2-chosen,
.boat-rent-page-select .select2-default .select2-chosen,
.ref-page-select .select2-search-field input.select2-default,
.boat-rent-page-select .select2-search-field input.select2-default { color: var(--ref-muted) !important; }
/* …and a MULTIPLE select writes its placeholder as the input's value with `select2-default` (select2.css: #999
   !important), never as ::placeholder: the same muted ink. The page's typeface on the box and the list, which
   select2-bootstrap.css (every layout) sets to Helvetica. (Both from reference-cards.css on master, 2026-10.) */
.ref-page-select .select2-choice,
.boat-rent-page-select .select2-choice,
.ref-page-select .select2-choices,
.boat-rent-page-select .select2-choices,
.ref-page-select .select2-search-field input,
.boat-rent-page-select .select2-search-field input,
.ref-drop,
.boat-rent-drop { font-family: inherit; }
.ref-drop,
.boat-rent-drop { border: 1px solid var(--area-accent) !important; border-top: none !important; border-radius: 0 0 var(--ref-radius-control) var(--ref-radius-control) !important; box-shadow: var(--ref-shadow-pop) !important; margin-top: -1px !important; }
.ref-drop .select2-results .select2-highlighted,
.boat-rent-drop .select2-results .select2-highlighted {
    background: var(--ref-surface-hover) !important;
    color: var(--ref-ink) !important;
    box-shadow: inset 3px 0 0 var(--area-ink); /* ds-allow: scale — the Select2 bar is not the retired stripe (D-10) */
}
.ref-drop .select2-results li,
.boat-rent-drop .select2-results li { border-radius: var(--ref-radius-inset); }
.ref-drop .select2-search input,
.boat-rent-drop .select2-search input { border: 1px solid var(--ref-border-field); border-radius: var(--ref-radius-control); box-shadow: none; height: 34px; font-family: inherit; }
.ref-drop .select2-search input:focus,
.boat-rent-drop .select2-search input:focus,
.ref-drop.select2-drop .select2-search input:focus,
.boat-rent-drop.select2-drop .select2-search input:focus { border-color: var(--area-accent) !important; box-shadow: var(--ref-focus) !important; } /* above the settings field skin's navy (`.select2-drop .select2-search input:focus`, 0,3,1) */

/* ---- Colour legend (`.ref-legend`, alias `.boat-rent-legend`) ---- */
.ref-legend,
.boat-rent-legend { display: flex; flex-wrap: wrap; gap: 14px; margin: 0 0 14px; font-size: var(--ref-fs-small); color: var(--ref-ink-2); align-items: center; }
.ref-legend .swatch,
.boat-rent-legend .swatch { display: inline-block; width: 12px; height: 12px; border-radius: var(--ref-radius-inset); vertical-align: middle; margin-right: 5px; }

/* ---- The icon-only button of a row (D-23): a glyph alone in a grid row, a list line or a toolbar of glyphs, 30 px like
   the row buttons beside it (HubRowActions). A button with a LABEL is never xs, it is the small button (`btn-sm`, 32 px):
   the xs had grown to four heights (27 with a label under a 42 px field, 30, 32, 34) — DsSmallButtonTest. ---- */
.ref-btn-xs { padding: 5px 9px; border-radius: var(--ref-radius-control); font-size: var(--ref-fs-small); line-height: 18px; }
.ref-btn-xs i { margin-right: 0; }

/* ---- Focus bar (Controller::$focusMode, protected/views/layouts/_focus_bar.php): in place of the menu, the marina's
   mark, what is being done, a quiet status line and ONE way out. ---- */
.ref-focus-bar { display: flex; align-items: center; gap: 14px; padding: 10px 20px; background: var(--ref-surface); border-bottom: 1px solid var(--ref-hairline); box-shadow: var(--ref-shadow-soft); margin-bottom: 20px; position: sticky; top: 0; z-index: 1020; }
.ref-focus-bar-brand { display: flex; align-items: center; flex: 0 0 auto; }
.ref-focus-bar-brand img { display: block; }
.ref-focus-bar-title { flex: 1 1 auto; min-width: 0; margin: 0; font-size: var(--ref-fs-title); font-weight: var(--ref-fw-title); color: var(--ref-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ref-focus-bar-title i { color: var(--area-ink); margin-right: 8px; }
.ref-focus-bar-status { flex: 0 1 auto; color: var(--ref-muted); font-size: var(--ref-fs-small); white-space: nowrap; }
.ref-focus-bar-exit { flex: 0 0 auto; }
@media (max-width: 767px) { .ref-focus-bar-status { display: none; } }
.ref-focus-bar--inline { position: static; z-index: auto; }
