/* ============================================================================
Warm Paper / Ink — foundation components.
FORM (shape, density, interaction) follows design_reference/ ("Nordwell").
COLOUR and TYPE follow WARM_PAPER_INK_SPEC.md. Where the two differ:
- Field labels: spec type wins (10px/700/uppercase), not the reference's
12.5px sentence case.
- Radii: the reference's softer corners, expressed through the spec's own
radius scale. --r-lg is 11px, which is exactly the reference's input
radius, so nothing is invented.
- Input fill: the reference tints inputs; the spec puts them on --surface
with the darker --field border. Colour rule wins -> white on --field.
- Focus ring: the reference glows lime; there is no lime here. Ink ring.
- Checked controls: the reference fills lime; filled with --accent instead.
========================================================================= */
/* ---------------------------------------------------------------------------
Buttons — spec §4. One primary per view.
------------------------------------------------------------------------ */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    border: 1px solid transparent;
    border-radius: var(--r-lg);
    padding: 9px 16px;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--tr), border-color var(--tr), color var(--tr);
}
.btn svg {
    width: 15px;
    height: 15px;
    stroke-width: 2;
    flex: none;
}
.btn--primary       {
    background: var(--accent);
    color: var(--on-accent);
}
.btn--primary:hover {
    background: var(--accent-hover);
}
.btn--ghost         {
    background: var(--surface);
    border-color: var(--border);
    color: var(--text);
}
.btn--ghost:hover   {
    background: var(--surface-sunken);
}
.btn--quiet         {
    background: transparent;
    color: var(--muted);
}
.btn--quiet:hover   {
    background: var(--surface-sunken);
    color: var(--text);
}
.btn--danger        {
    background: var(--danger);
    color: var(--on-accent);
}
.btn--danger:hover  {
    background: var(--danger-ink);
}
/* Destructive but secondary — used in modal footers beside a ghost cancel. */
.btn--danger-soft       {
    background: var(--danger-soft);
    color: var(--danger-ink);
}
.btn--danger-soft:hover {
    background: var(--danger);
    color: var(--on-accent);
}
.btn--sm {
    padding: 7px 12px;
    font-size: 12px;
}
.btn--lg {
    padding: 11px 20px;
    font-size: 14px;
}
.btn--block {
    width: 100%;
}
.btn:disabled,
.btn.is-disabled {
    opacity: .5;
    cursor: not-allowed;
}
.btn-icon {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--muted);
    cursor: pointer;
    transition: background var(--tr), color var(--tr), border-color var(--tr);
}
.btn-icon:hover {
    background: var(--surface-sunken);
    color: var(--text);
}
.btn-icon svg   {
    width: 16px;
    height: 16px;
    stroke-width: 2;
}
/* ---------------------------------------------------------------------------
Fields — spec §4 inputs, reference field/label/help composition.
------------------------------------------------------------------------ */
.field {
    display: flex;
    flex-direction: column;
    gap: 7px;
    min-width: 0;
}
.field__label {
    display: flex;
    align-items: center;
    gap: var(--s1);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
}
.field__req {
    color: var(--danger);
}
.field__opt {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    color: var(--accent-ink);
    background: var(--accent-soft);
    padding: 2px 6px;
    border-radius: var(--r-sm);
    text-transform: uppercase;
}
.field__help  {
    font-size: 11.5px;
    color: var(--muted);
}
.field__error {
    font-size: 11.5px;
    font-weight: 500;
    color: var(--danger-ink);
}
.input,
.textarea,
select.input {
    width: 100%;
    border: 1px solid var(--field);
    border-radius: var(--r-lg);
    padding: 9px 11px;
    font: inherit;
    font-size: 13px;
    background: var(--surface);
    color: var(--text);
    outline: 0;
    transition: border-color var(--tr), box-shadow var(--tr), background var(--tr);
}
.input::placeholder,
.textarea::placeholder {
    color: var(--faint);
}
.input:hover:not(:disabled):not([readonly]),
.textarea:hover:not(:disabled):not([readonly]) {
    border-color: var(--muted);
}
.input:focus,
.textarea:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}
.input:disabled,
.textarea:disabled {
    background: var(--surface-sunken);
    color: var(--faint);
    border-color: var(--border);
    cursor: not-allowed;
}
.input[readonly],
.textarea[readonly] {
    background: var(--surface-sunken);
    color: var(--muted);
}
.input[readonly]:focus,
.textarea[readonly]:focus {
    border-color: var(--field);
    box-shadow: none;
}
.input.is-invalid,
.textarea.is-invalid {
    border-color: var(--danger);
}
.input.is-invalid:focus,
.textarea.is-invalid:focus {
    box-shadow: 0 0 0 var(--ring-width) var(--ring-danger);
}
.textarea {
    min-height: 104px;
    resize: vertical;
    line-height: 1.5;
}
/* Number inputs carry no spinner arrows — spec §4. */
input[type=number] {
    -moz-appearance: textfield;
    appearance: textfield;
}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
/* Input group: an icon or affix sharing the field's border. */
.input-group {
    display: flex;
    align-items: center;
    gap: var(--s2);
    background: var(--surface);
    border: 1px solid var(--field);
    border-radius: var(--r-lg);
    padding: 0 11px;
    transition: border-color var(--tr), box-shadow var(--tr);
}
.input-group:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}
.input-group .input {
    border: 0;
    border-radius: 0;
    padding: 9px 0;
    background: transparent;
}
.input-group .input:focus {
    box-shadow: none;
}
.input-group svg {
    width: 15px;
    height: 15px;
    stroke-width: 2;
    color: var(--muted);
    flex: none;
}
.input-group__affix {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
}
/* ---------------------------------------------------------------------------
Cards — spec §4. The border does the work; the shadow only lifts.
------------------------------------------------------------------------ */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
}
.card__head {
    padding: var(--s3) var(--s4);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: var(--s3);
}
.card__head h2 {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: -.01em;
}
.card__body {
    padding: var(--s4);
}
.card__foot {
    padding: var(--s3) var(--s4);
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: var(--s2);
}
/* Metric card. One per screen may be inverted — spec §4. */
.metric {
    padding: var(--s4);
    display: flex;
    flex-direction: column;
    gap: var(--s1);
}
.metric__label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--muted);
}
.metric strong {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -.035em;
}
.metric__note  {
    font-size: 11.5px;
    color: var(--muted);
}
.metric--hero {
    background: var(--accent);
    color: var(--on-accent);
    border-color: transparent;
    box-shadow: var(--shadow-ink);
}
.metric--hero .metric__label {
    color: var(--on-accent-dim);
}
.metric--hero .metric__note  {
    color: var(--on-accent-soft);
}
/* ---------------------------------------------------------------------------
Badges — spec §4. All the colour in the palette lives here.
------------------------------------------------------------------------ */
.badge {
    display: inline-block;
    border-radius: var(--r-sm);
    padding: 3px 9px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .02em;
    /* Body leading would make a badge taller than the 38px row it sits in.
    vertical-align keeps it off the baseline, which otherwise reserves
    descender space under it and pushes the row taller again. */
    line-height: 1.2;
    vertical-align: middle;
    white-space: nowrap;
}
.badge--success {
    background: var(--success-soft);
    color: var(--success-ink);
}
.badge--warning {
    background: var(--warning-soft);
    color: var(--warning-ink);
}
.badge--danger  {
    background: var(--danger-soft);
    color: var(--danger-ink);
}
.badge--info    {
    background: var(--info-soft);
    color: var(--info-ink);
}
.badge--neutral {
    background: var(--accent-soft);
    color: var(--accent-ink);
}
/* ---------------------------------------------------------------------------
Table — spec §4. Row height lands near 38px: standard density.
------------------------------------------------------------------------ */
.table-wrap {
    /* The positioning context for anything absolutely placed inside a table
       (screen-reader-only text included), so it stays in the scroll box
       instead of widening the page on a phone. */
    position: relative;
    width: 100%;
    overflow-x: auto;
}
.table {
    width: 100%;
    border-collapse: collapse;
}
/* A date or an amount split over lines is unreadable and makes rows tall. */
.table .numeric,
.table .badge {
    white-space: nowrap;
}
.table thead th {
    background: var(--thead);
    color: var(--thead-text);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    text-align: left;
    padding: 11px 14px;
    white-space: nowrap;
}
.table--sticky thead th {
    position: sticky;
    top: var(--topbar-h);
    z-index: 10;
}
.table tbody td {
    padding: 11px 14px;
    border-top: 1px solid var(--border);
    font-size: 13px;
    /* The body's 1.55 leading pushes rows to ~44px; the spec fixes standard
    density near 38px (--row-h), so cells tighten to 1.2. */
    line-height: 1.2;
    vertical-align: middle;
}
.table tbody tr:nth-child(even) {
    background: var(--zebra);
}
.table tbody tr:hover           {
    background: var(--row-hover);
}
.table .numeric,
.table th.numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 500;
}
/* ERP webhook (2026-10-01): the test result, its steps, Advanced, counts and guide. */
.webhook-test p {
    margin: 6px 0 0;
}
.webhook-test__title {
    font-size: 15px;
}
.webhook-test__url {
    font-size: 12px;
    opacity: .8;
}
.webhook-generate {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}
.webhook-secret__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}
.webhook-secret__key {
    padding: 6px 10px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    font-size: 13px;
    word-break: break-all;
    user-select: all;
}
.webhook-secret .webhook-steps {
    color: inherit;
}
.webhook-secret,
.webhook-secret .stack {
    min-width: 0;
}
.webhook-secret__key,
.webhook-secret .mono {
    max-width: 100%;
    overflow-wrap: anywhere;
    word-break: break-all;
}
.webhook-steps {
    margin: 0;
    padding-left: 22px;
    color: var(--muted);
    list-style: decimal;
}
.webhook-steps li + li {
    margin-top: 2px;
}
.webhook-advanced {
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-sunken);
}
.webhook-advanced > summary {
    padding: 10px 14px;
    cursor: pointer;
    color: var(--muted);
    font-weight: 600;
    font-size: 13px;
}
.webhook-advanced__body {
    padding: 0 14px 14px;
}
.webhook-counts {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.webhook-guide .card__body {
    max-width: 920px;
    line-height: 1.6;
}
.webhook-guide__h2 {
    margin: var(--s5) 0 0;
    padding-top: var(--s4);
    border-top: 1px solid var(--border);
    font-size: 17px;
}
.webhook-guide__h2:first-of-type {
    margin-top: 0;
}
.webhook-guide__h3 {
    margin: var(--s3) 0 0;
    font-size: 14px;
}
.webhook-guide__list {
    margin: 0;
    padding-left: 22px;
    list-style: disc;
}
.webhook-guide__steps {
    list-style: decimal;
}
.webhook-guide__list li + li {
    margin-top: 4px;
}
.webhook-guide__steps li::marker {
    font-weight: 700;
}
.webhook-guide__code {
    margin: 0;
    padding: var(--s3) var(--s4);
    overflow-x: auto;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--r);
    font-size: 12.5px;
    line-height: 1.5;
    white-space: pre;
}
.webhook-guide__key {
    width: 32%;
    font-weight: 600;
}
/* SL: the row's number on every list (tables.js, 2026-09-30). */
.table .table-sl {
    width: 44px;
    color: var(--muted);
    text-align: center;
    padding-inline: 8px;
}
.table th.table-sl .dt-column-header {
    justify-content: center;
}
/* Sortable header — the indicator is ink, never a second colour. */
.table th.is-sortable {
    cursor: pointer;
    user-select: none;
}
.table th.is-sortable:hover {
    color: var(--text);
}
.table th.is-sortable::after {
    content: "";
    display: inline-block;
    width: 0;
    height: 0;
    margin-left: 6px;
    vertical-align: middle;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 4px solid currentColor;
    opacity: .25;
}
.table th.is-asc::after  {
    border-top: 0;
    border-bottom: 4px solid currentColor;
    opacity: .9;
}
.table th.is-desc::after {
    opacity: .9;
}
/* ---------------------------------------------------------------------------
Pagination — spec §4. Required on every table, with a real count.
------------------------------------------------------------------------ */
.pagination {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: var(--s3) var(--s4);
    border-top: 1px solid var(--border);
    color: var(--muted);
    font-size: 12px;
    flex-wrap: wrap;
}
.pagination__info {
    font-variant-numeric: tabular-nums;
}
.pagination__pages {
    display: flex;
    align-items: center;
    gap: var(--s1);
    margin-left: auto;
}
.pagination__page {
    min-width: 30px;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 5px 10px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background var(--tr), border-color var(--tr);
}
.pagination__page:hover:not(:disabled):not(.is-on) {
    background: var(--surface-sunken);
}
.pagination__page.is-on {
    background: var(--accent);
    border-color: transparent;
    color: var(--on-accent);
    font-weight: 700;
}
.pagination__page:disabled {
    opacity: .4;
    cursor: not-allowed;
}
.pagination__dots {
    padding: 0 var(--s1);
    color: var(--faint);
}
.pagination__size {
    display: flex;
    align-items: center;
    gap: var(--s2);
}
.pagination__size select {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 12px;
    padding: 4px 8px;
    cursor: pointer;
}
@media (max-width: 680px) {
    .pagination {
        gap: var(--s3);
    }
    .pagination__pages {
        margin-left: 0;
        width: 100%;
    }
}
/* Project-wide numeric controls: native validation without spin buttons. */
input[type="number"] {
    appearance: textfield;
    -moz-appearance: textfield;
}
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
select.input, select.dt-input {
    appearance: none;
    padding-right: 32px;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
    background-size: 5px 5px;
    background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
   Native select — "fixed choices use styled native selects" (project rule).
   The box is styled with our tokens; the OS keeps drawing the arrow, which
   avoids baking a hard-coded colour into a background image.
   StyledFormMixin adds `.select` to every non-Select2 <select>.
   ------------------------------------------------------------------------ */

.select,
select.input {
    cursor: pointer;
    padding-right: var(--s8);
    background-color: var(--surface);
    /* Replace the OS dropdown arrow with our own chevron. Built from two
       gradients using currentColor, so it inherits --text and needs no SVG
       file and no hard-coded colour. */
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: right 17px center, right 12px center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}
.select:focus,
select.input:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}
.select::-ms-expand,
select.input::-ms-expand {
    display: none;
}
.select:disabled,
select.input:disabled {
    cursor: not-allowed;
    background: var(--surface-sunken);
    color: var(--faint);
}

/* ---------------------------------------------------------------------------
   Checkbox / radio — a control beside its label, aligned on the first line.

   The control is drawn rather than left native. `accent-color` alone tints the
   browser's own box, which on a warm paper background reads as a grey smudge:
   no visible border at rest, and nothing that matches the ink accent when
   checked. Drawing it means one appearance everywhere, a border in --field
   like every other input, and a focus ring that matches .input.

   Two selectors on purpose. `.check__input` is put on the widget itself by
   common.forms.StyledFormMixin, so any form-rendered checkbox is styled
   wherever its template puts it — including templates that do not use the
   `.check` wrapper. The `.check input[...]` pair covers checkboxes written by
   hand inside a `.check` label. A checkbox outside both (the day picker's
   visually hidden inputs) is deliberately untouched.
   ------------------------------------------------------------------------ */

.check {
    display: flex;
    align-items: flex-start;
    gap: var(--s2);
    cursor: pointer;
    user-select: none;
    font-size: 13px;
}
.check__input,
.check input[type="checkbox"],
.check input[type="radio"] {
    appearance: none;
    -webkit-appearance: none;
    width: 18px;
    height: 18px;
    margin: 1px 0 0;
    flex: none;
    /* inline-grid + place-content is what lets the tick sit centred inside a
       replaced element once appearance is removed. */
    display: inline-grid;
    place-content: center;
    border: 1px solid var(--field);
    border-radius: var(--r-sm);
    background: var(--surface);
    cursor: pointer;
    transition: background var(--tr), border-color var(--tr), box-shadow var(--tr);
}
.check__input[type="radio"],
.check input[type="radio"] {
    border-radius: var(--r-pill);
}
.check__input::before,
.check input[type="checkbox"]::before,
.check input[type="radio"]::before {
    content: "";
    width: 10px;
    height: 10px;
    transform: scale(0);
    transition: transform var(--tr);
    background: var(--on-accent);
    /* The tick, drawn as a clipped block so its colour stays a token rather
       than being baked into an SVG data URI. */
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%);
}
.check__input[type="radio"]::before,
.check input[type="radio"]::before {
    width: 8px;
    height: 8px;
    border-radius: var(--r-pill);
    clip-path: none;
}
.check__input:checked,
.check input[type="checkbox"]:checked,
.check input[type="radio"]:checked {
    background: var(--accent);
    border-color: var(--accent);
}
.check__input:checked::before,
.check input[type="checkbox"]:checked::before,
.check input[type="radio"]:checked::before {
    transform: scale(1);
}
.check__input:hover:not(:disabled),
.check input[type="checkbox"]:hover:not(:disabled),
.check input[type="radio"]:hover:not(:disabled) {
    border-color: var(--muted);
}
.check__input:checked:hover:not(:disabled),
.check input[type="checkbox"]:checked:hover:not(:disabled),
.check input[type="radio"]:checked:hover:not(:disabled) {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
}
/* focus-visible, so a mouse click does not leave a ring behind, but tabbing
   always shows where you are — the same ring .input uses. */
.check__input:focus-visible,
.check input[type="checkbox"]:focus-visible,
.check input[type="radio"]:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}
.check__input:disabled,
.check input:disabled {
    background: var(--surface-sunken);
    border-color: var(--border);
    cursor: not-allowed;
}
.check__input:disabled::before,
.check input:disabled::before {
    background: var(--faint);
}
.check input:disabled + span,
.check__input:disabled ~ .field__label {
    color: var(--faint);
}

/* ---------------------------------------------------------------------------
   Form page — a narrower container centred inside the content area, per the
   project layout rule. Wide data tables use the full width; forms do not.
   ------------------------------------------------------------------------ */

.form-page {
    width: 100%;
    max-width: 880px;
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--s5);
}

/* ---------------------------------------------------------------------------
   Custom select — for STATIC choice lists.

   FORM follows design_reference/ (.om-sel__control / __menu / __option / __tick).
   COLOUR is ours: the reference's lime selection becomes the ink accent, and its
   remote iconify masks are replaced by inline SVG.

   Select2 is NOT used here. It is reserved for database-backed lists that may
   need search or paging. This control exists because a native <select> can style
   its closed box but never its open dropdown, which the OS draws.

   Progressive enhancement: the real <select> keeps the value and posts normally.
   ------------------------------------------------------------------------ */

.cs {
    position: relative;
    width: 100%;
}
.cs__native {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}

.cs__control {
    display: flex;
    align-items: center;
    gap: var(--s2);
    width: 100%;
    border: 1px solid var(--field);
    border-radius: var(--r-lg);
    padding: 9px 11px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--tr), box-shadow var(--tr), background var(--tr);
}
.cs__control:hover {
    border-color: var(--muted);
}
.cs__control:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}
.cs__control--open {
    outline: none;
    background: var(--accent-soft);
    border-color: var(--accent);
}
.cs__control--disabled {
    background: var(--surface-sunken);
    color: var(--faint);
    cursor: not-allowed;
}
.cs__value {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cs__value--empty {
    color: var(--faint);
}
.cs__caret {
    flex: none;
    width: 14px;
    height: 14px;
    color: var(--muted);
    transition: transform .2s ease;
}
.cs__control--open .cs__caret {
    transform: rotate(180deg);
}

/* Menu is appended to <body> and fixed-positioned, because .card uses
   overflow:hidden for its rounded corners and would clip it. */
.cs__menu {
    position: fixed;
    z-index: 200;
    top: 0;
    left: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    padding: 6px;
    max-height: 280px;
    overflow-y: auto;
    opacity: 0;
    transform: translateY(-6px) scale(.97);
    pointer-events: none;
    transition: opacity .16s ease, transform .18s ease;
}
.cs__menu--open {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}

.cs__option {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--r);
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: background var(--tr), color var(--tr);
}
.cs__option:hover,
.cs__option--active {
    background: var(--surface-sunken);
}
/* Reference form: the chosen option is a soft tint with a tick on the right -
   NOT a solid ink block. The solid ink block is reserved for the active nav
   item, which is the single strongest moment in the interface. */
.cs__option--on,
.cs__option--on:hover {
    background: var(--accent-soft);
    color: var(--accent-ink);
    font-weight: 600;
}
.cs__option-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cs__tick {
    flex: none;
    width: 13px;
    height: 13px;
    opacity: 0;
    transition: opacity .12s ease;
}
.cs__option--on .cs__tick {
    opacity: 1;
}
.cs__option[disabled] {
    color: var(--faint);
    cursor: not-allowed;
}

/* ---------------------------------------------------------- day picker
   Several weekdays chosen at once, e.g. weekly off days. Real checkboxes stay
   in the form and post normally; each is visually hidden but still focusable,
   and the span after it is the button face. Selected uses the same filled ink
   as the calendar's chosen day, so the two read as one system. */

.day-picker {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}
.day-picker > legend {
    padding: 0;
}
.day-picker__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
}
.day-picker__day {
    position: relative;
    cursor: pointer;
}
.day-picker__input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    margin: 0;
    pointer-events: none;
}
.day-picker__name {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 52px;
    height: 40px;
    padding: 0 var(--s3);
    border: 1px solid var(--field);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    user-select: none;
    transition: background var(--tr), border-color var(--tr), color var(--tr);
}
.day-picker__day:hover .day-picker__name {
    background: var(--surface-sunken);
}
.day-picker__input:checked + .day-picker__name {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}
.day-picker__input:focus-visible + .day-picker__name {
    outline: none;
    box-shadow: 0 0 0 var(--ring-width) var(--ring);
}

/* ---------------------------------------------------------------------------
   File input — the field box stays, and the browser's own "Choose file" button
   is dressed as a quiet button so it belongs with the rest of the controls.
   ------------------------------------------------------------------------ */

.input--file {
    padding: 6px 8px;
    line-height: 1.6;
}
.input--file::file-selector-button {
    margin-right: var(--s3);
    padding: 5px 10px;
    border: 1px solid var(--field-border);
    border-radius: var(--r-sm);
    background: var(--surface-sunken);
    color: var(--ink);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.input--file::file-selector-button:hover {
    background: var(--surface);
}

/* A logo, its preview and its controls side by side; the preview never grows
   with the image (a 1000x800 upload is scaled into the same box). */
.logo-field {
    display: flex;
    align-items: flex-start;
    gap: var(--s4);
    flex-wrap: wrap;
}
.logo-field__preview {
    flex: none;
    display: grid;
    place-items: center;
    width: 132px;
    height: 72px;
    padding: var(--s2);
    border: 1px solid var(--field-border);
    border-radius: var(--r-sm);
    background: var(--surface-sunken);
}
.logo-field__preview img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}
.logo-field__controls {
    flex: 1 1 260px;
    display: flex;
    flex-direction: column;
    gap: var(--s2);
}

/* ---------- Modal dialog (native <dialog>, opened with showModal) ----------
   Top layer, so it sits above the sidebar and topbar. Pop-ups inside it
   (Select2 with dropdownParent, the date picker) attach to the dialog. */
.modal {
    border: 0;
    padding: 0;
    background: transparent;
    max-width: min(520px, calc(100vw - 32px));
    width: 100%;
    overflow: visible;
}
.modal::backdrop {
    background: rgba(17, 17, 19, .32);
    animation: modal-fade .18s ease-out;
}
.modal[open] .modal__card {
    animation: modal-rise .2s cubic-bezier(.2, .8, .2, 1);
}
.modal__card {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 48px);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-ink);
    color: var(--text);
}
.modal__head,
.modal__foot {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: 16px 20px;
}
.modal__head {
    justify-content: space-between;
    border-bottom: 1px solid var(--border);
}
.modal__head h2 {
    margin: 0;
    font-size: 1rem;
}
.modal__foot {
    justify-content: flex-end;
    border-top: 1px solid var(--border);
    background: var(--surface-sunken);
    border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.modal__body {
    padding: 20px;
    overflow-y: auto;
}
.modal__close {
    border: 0;
    background: transparent;
    color: var(--muted);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: var(--r);
}
.modal__close:hover {
    background: var(--accent-soft);
    color: var(--text);
}
@keyframes modal-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes modal-rise {
    from { opacity: 0; transform: translateY(8px) scale(.98); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .modal::backdrop,
    .modal[open] .modal__card { animation: none; }
}

/* A read-only value laid out like an input (e.g. the branch in the Map dialog). */
.input--static {
    display: flex;
    align-items: center;
    background: var(--surface-sunken);
    color: var(--muted);
}

/* Several small buttons in one table cell. */
.row-actions {
    display: flex;
    flex-wrap: nowrap;
    gap: 4px;
    white-space: nowrap;
}

/* ---------- Row selection: custom checkbox + floating selection bar ---------- */
.pick-cell {
    width: 40px;
    padding-right: 0 !important;
}
.pick {
    position: relative;
    display: inline-flex;
    width: 18px;
    height: 18px;
    cursor: pointer;
}
.pick input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.pick__box {
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--field);
    border-radius: var(--r-sm);
    background: var(--surface);
    transition: background .15s ease, border-color .15s ease, transform .1s ease;
}
.pick:hover .pick__box { border-color: var(--muted); }
.pick input:focus-visible + .pick__box { box-shadow: 0 0 0 3px var(--ring); }
.pick input:checked + .pick__box,
.pick input:indeterminate + .pick__box {
    background: var(--accent);
    border-color: var(--accent);
}
.pick input:checked + .pick__box {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
    background-size: 14px;
    background-position: center;
    background-repeat: no-repeat;
}
.pick input:indeterminate + .pick__box {
    background-image: linear-gradient(white, white);
    background-size: 9px 2px;
    background-position: center;
    background-repeat: no-repeat;
}
.pick input:active + .pick__box { transform: scale(.9); }
tr.is-picked > td { background: var(--accent-soft) !important; }

.selection-bar {
    position: sticky;
    bottom: 16px;
    z-index: 20;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 12px 16px 16px;
    padding: 10px 12px 10px 18px;
    background: var(--accent);
    color: var(--on-accent);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-ink);
    opacity: 0;
    transform: translateY(12px);
    transition: opacity .2s ease, transform .22s cubic-bezier(.2, .8, .2, 1);
}
.selection-bar--open { opacity: 1; transform: none; }
.selection-bar__count {
    display: flex;
    align-items: center;
    gap: 8px;
}
.selection-bar__count .btn { color: var(--on-accent); }
.selection-bar__count .btn:hover { background: rgba(255, 255, 255, .12); }
.selection-bar__action {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: min(360px, 100%);
}
.selection-bar__action .select2-container { min-width: 200px; flex: 1; }
.selection-bar .btn--primary {
    background: var(--on-accent);
    color: var(--accent);
    border-color: var(--on-accent);
}
@media (prefers-reduced-motion: reduce) {
    .selection-bar, .pick__box { transition: none; }
}
@media (max-width: 640px) {
    .selection-bar {
        margin: 12px 8px;
        padding: 10px 12px;
    }
    .selection-bar__count { flex-wrap: wrap; }
    .selection-bar__action {
        width: 100%;
        min-width: 0;
    }
    .selection-bar__action .select2-container {
        min-width: 0;
        width: auto !important;
    }
}

/* ---------- Notice: a message that needs a decision ----------
   Icon, heading, one line of explanation, the actions together underneath and
   any fine print last. Unlike .alert (a one-line flash message) it stacks. */
.notice {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 14px;
    padding: 18px 20px;
    margin-bottom: var(--s4, 16px);
    border-radius: var(--r-lg);
    border: 1px solid transparent;
    animation: notice-in .25s ease-out;
}
.notice--warning {
    background: var(--warning-soft);
    border-color: rgba(154, 106, 18, .18);
}
.notice__icon {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(154, 106, 18, .14);
    color: var(--warning-ink);
}
.notice__icon svg {
    width: 18px;
    height: 18px;
}
.notice__body {
    min-width: 0;
}
.notice__title {
    margin: 0 0 4px;
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
}
.notice__text {
    margin: 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.5;
    max-width: 68ch;
}
.notice__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 14px;
}
.notice__actions form { margin: 0; }
.notice__hint {
    margin: 12px 0 0;
    color: var(--faint);
    font-size: 12px;
    line-height: 1.5;
    max-width: 72ch;
}
@keyframes notice-in {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .notice { animation: none; }
}
@media (max-width: 640px) {
    .notice { grid-template-columns: 1fr; padding: 16px; }
    .notice__actions .btn { width: 100%; justify-content: center; }
    .notice__actions form { width: 100%; }
}
.selection-bar__number {
    display: inline-grid;
    place-items: center;
    min-width: 26px;
    height: 26px;
    padding: 0 8px;
    border-radius: var(--r-pill);
    background: var(--on-accent);
    color: var(--accent);
    font-weight: 700;
    font-size: 13px;
}
.selection-bar .btn--ghost {
    background: transparent;
    color: var(--on-accent);
    border-color: rgba(255, 255, 255, .35);
}
.selection-bar .btn--ghost:hover {
    background: rgba(255, 255, 255, .12);
    border-color: rgba(255, 255, 255, .6);
}
.selection-bar__divider {
    width: 1px;
    align-self: stretch;
    background: rgba(255, 255, 255, .25);
    margin: 0 4px;
}
.selection-bar__action {
    flex-wrap: wrap;
}
@media (max-width: 640px) {
    .selection-bar__divider { display: none; }
    .selection-bar__action .btn { flex: 1 1 auto; justify-content: center; }
}
.empty__action {
    margin-top: 16px;
}

/* Which devices an employee is on (Employees list), and who a device user is. */
.device-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
.device-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px 2px 6px;
    border-radius: var(--r-pill);
    background: var(--success-soft);
    color: var(--success-ink);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}
.device-chip svg {
    width: 12px;
    height: 12px;
}
.device-chip--none {
    padding: 2px 8px;
    background: var(--warning-soft);
    color: var(--warning-ink);
}
/* Linked, but deleted on the terminal since (latest user list). */
.device-removed {
    margin-top: 4px;
    color: var(--warning-ink);
    font-size: 12px;
}
.device-bio {
    margin-top: 4px;
    color: var(--muted);
    font-size: 12px;
}
.linked-employee {
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}
/* Why a device user is not linked, and what links them (2026-09-29). */
.unlinked-why {
    margin-top: 6px;
    min-width: 260px;
    max-width: 42ch;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.45;
    white-space: normal;
}
.unlinked-reasons {
    display: grid;
    gap: 8px;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
    max-width: 760px;
}
.unlinked-reasons__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
}
.unlinked-reasons__label {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
}
.unlinked-reasons__hint {
    margin-top: 2px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.45;
}
.unlinked-reasons__row .btn { flex-shrink: 0; }
.unlinked-reasons__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    flex-shrink: 0;
}
.unlinked-reasons__actions form,
.unlinked-fix { margin: 0; }
.unlinked-fix { margin-top: 8px; }
@media (max-width: 640px) {
    .unlinked-reasons__row { flex-direction: column; align-items: stretch; }
}

/* The shared confirm dialog (confirm.js). */
.modal--confirm { max-width: min(440px, calc(100vw - 32px)); }
.confirm__text {
    margin: 0;
    color: var(--muted);
    font-size: 14px;
    line-height: 1.55;
}
.selection-bar .btn--danger-ghost {
    border-color: rgba(255, 170, 160, .55);
    color: #ffd9d3;
}
.selection-bar .btn--danger-ghost:hover {
    background: rgba(255, 120, 100, .18);
    border-color: rgba(255, 170, 160, .9);
    color: #fff;
}

/* ---------- A long job the device is working through (job_progress.js) ---------- */
.job {
    margin-bottom: var(--s4, 16px);
    padding: 14px 18px;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.job__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.job__title { font-weight: 600; }
.job__count { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.job__bar {
    position: relative;
    height: 8px;
    margin: 10px 0 8px;
    border-radius: var(--r-pill);
    background: var(--surface-sunken);
    overflow: hidden;
}
.job__bar > span {
    display: block;
    height: 100%;
    width: 0;
    border-radius: var(--r-pill);
    background: var(--accent);
    transition: width .4s ease;
}
.job--running .job__bar > span {
    background-image: linear-gradient(90deg, rgba(255,255,255,.28) 25%, transparent 25%,
        transparent 50%, rgba(255,255,255,.28) 50%, rgba(255,255,255,.28) 75%, transparent 75%);
    background-size: 18px 18px;
    animation: job-stripes 1s linear infinite;
}
.job--done .job__bar > span { background: var(--success); }
.job--refused .job__bar > span { background: var(--warning); }
.job__meta {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    flex-wrap: wrap;
}
.job__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--faint);
}
.job__dot--done { background: var(--success); }
.job__dot--wait { background: var(--accent); }
.job__dot--bad { background: var(--warning); }
.job__left { margin-left: auto; }
.job__note { margin: 8px 0 0; font-size: 12px; }
/* "Load employees": preparing them here, before the device collects them. */
.job__prep {
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.job__bar--thin { height: 6px; }
.job__failures {
    margin: 8px 0 0;
    padding-left: 18px;
    font-size: 12px;
    color: var(--muted);
    max-height: 140px;
    overflow-y: auto;
}
.job__failures li { margin: 2px 0; overflow-wrap: anywhere; }
@keyframes job-stripes { to { background-position: 18px 0; } }
@media (prefers-reduced-motion: reduce) {
    .job--running .job__bar > span { animation: none; }
    .job__bar > span { transition: none; }
}

/* "Saved on this server": did the save work, and in which format. */
.saved-line {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: var(--s4, 16px);
    padding: 10px 14px;
    border-radius: var(--r);
    background: var(--success-soft);
    color: var(--success-ink);
    font-size: 13px;
}
.saved-line svg { width: 16px; height: 16px; flex: none; }
.saved-line strong { font-weight: 700; }
.saved-line__formats {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-left: auto;
}
.trial-readback {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* Measuring the one command a protocol has not proven (delete). */
.delete-trial {
    padding: 14px 16px;
    border: 1px dashed var(--field);
    border-radius: var(--r);
    background: var(--surface-sunken);
}
.delete-trial__title {
    margin: 0 0 6px;
    font-size: 14px;
}
.delete-trial__form {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 10px;
}
.delete-trial__form .select2-container { min-width: 320px; flex: 1; }

/* "Needs setup" filter on the Employees list: one row of choices with a
   count each, under the search toolbar. */
.setup-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 0 16px 12px;
}
.setup-filter__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    color: var(--text);
    font-size: 12px;
    text-decoration: none;
    white-space: nowrap;
}
.setup-filter__item:hover {
    background: var(--surface-sunken);
}
.setup-filter__item.is-active {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--surface);
}
.setup-filter__count {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.setup-gaps {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 3px;
}

/* Reports (2026-09-26): the summary figures above a report, and the
   day-by-day grid of the weekly and monthly registers. */
.report-summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2);
    padding: var(--s3) var(--s4) 0;
}
.report-summary__item {
    display: flex;
    flex-direction: column;
    min-width: 88px;
    padding: var(--s2) var(--s3);
    border: 1px solid var(--line, #e3e7ec);
    border-radius: 10px;
}
.report-summary__value {
    font-size: 18px;
    font-weight: 700;
    line-height: 1.2;
}
.report-summary__label {
    font-size: 11.5px;
    opacity: .7;
}
.report-notes {
    padding: var(--s2) var(--s4) 0;
    margin: 0;
}
.report-pages {
    align-items: center;
    padding: var(--s3) var(--s4);
}
.table--grid th,
.table--grid td {
    padding-inline: 6px;
    white-space: nowrap;
}

/* A radio or checkbox list drawn by leaves/includes/field.html: one .check per option. */
.check-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s2) var(--s4);
    padding-block: var(--s1);
}

/* Leave balances: how a balance adds up (Phase E, 2026-09-27). */
.balance-entries > summary {
    cursor: pointer;
    font-size: .85em;
}
.balance-entries__list {
    margin: 6px 0 0;
    padding-left: 18px;
    font-size: .9em;
}
.balance-entries__list li {
    margin: 2px 0;
}

/* Show or hide a password (2026-09-28, password_toggle.js). */
.pw-field {
    position: relative;
    display: block;
}
.pw-field > input {
    width: 100%;
    padding-right: 42px;
}
.pw-toggle {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--muted);
    cursor: pointer;
}
.pw-toggle svg {
    width: 18px;
    height: 18px;
}
.pw-toggle:hover,
.pw-toggle:focus-visible {
    color: var(--text);
    background: var(--surface-sunken);
    outline: none;
}

/* ERP webhook: debug messages, 15 minutes (2026-10-03). */
.webhook-debug__views { gap: 6px; }
.webhook-debug__list { display: flex; flex-direction: column; gap: 10px; }
.debug-entry {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--border);
    border-radius: var(--r-md, 8px);
    background: var(--surface);
}
.debug-entry--ok { border-left-color: var(--success); }
.debug-entry--fail { border-left-color: var(--danger); }
.debug-entry__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 13px;
}
.debug-entry__head time { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.debug-entry__message { margin: 6px 0 0; overflow-wrap: anywhere; }
.debug-entry details { margin-top: 6px; }
.debug-entry summary { cursor: pointer; color: var(--muted); font-size: 12px; }
.webhook-debug__json,
.debug-entry pre {
    margin: 6px 0 0;
    padding: 10px 12px;
    max-height: 420px;
    overflow: auto;
    border-radius: var(--r-md, 8px);
    background: var(--surface-sunken);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* An on/off switch: a real checkbox, drawn as a track and thumb (2026-10-03). */
.switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    font-weight: 600;
}
.switch input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}
.switch__track {
    position: relative;
    flex: none;
    width: 40px;
    height: 22px;
    border-radius: var(--r-pill);
    background: var(--border);
    transition: background .15s ease;
}
.switch__thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    transition: transform .15s ease;
}
.switch input:checked + .switch__track { background: var(--success); }
.switch input:checked + .switch__track .switch__thumb { transform: translateX(18px); }
.switch input:focus-visible + .switch__track { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
    .switch__track, .switch__thumb { transition: none; }
}

/* Register / Edit device: the serial number checked as it is typed. */
.serial-check:empty { display: none; }
.serial-check--taken { color: var(--danger); font-weight: 600; }
.serial-check--free { color: var(--success); }
