/* ============================================================================
   Temp-wearable loan desk (#200–#203)
   ----------------------------------------------------------------------------
   Built entirely on the --yb-* tokens (ui-refinement.css), light and dark.
   The signature element is the STATE RIBBON: five count-tiles that ARE the
   filter and partition the pool exactly as the API does; each device card
   carries the state on a left spine (the safety-alert severity-spine idiom),
   so a wall of cards reads by colour + icon + label — never colour alone.
   Chips are rounded-rects on --yb-radius-sm, not pills (house rule).
   ========================================================================== */

/* Per-state accents, defined once and consumed by tile, spine and chip. */
.yb-tw-tile--available, .yb-tw-card--available, .yb-tw-chip--available,
.yb-tw-history__row--returned, .yb-tw-chip--returned { --tw-accent: var(--yb-success); --tw-accent-rgb: var(--yb-success-rgb, 25, 135, 84); }
.yb-tw-tile--issued, .yb-tw-card--issued, .yb-tw-chip--issued { --tw-accent: var(--yb-info); --tw-accent-rgb: var(--yb-info-rgb, 13, 110, 253); }
.yb-tw-tile--overdue, .yb-tw-card--overdue, .yb-tw-chip--overdue { --tw-accent: var(--yb-warning); --tw-accent-rgb: var(--yb-warning-rgb, 255, 153, 0); }
.yb-tw-tile--abandoned, .yb-tw-card--abandoned, .yb-tw-chip--abandoned,
.yb-tw-chip--voided, .yb-tw-history__row--voided { --tw-accent: var(--yb-danger); --tw-accent-rgb: var(--yb-danger-rgb, 220, 53, 69); }
.yb-tw-tile--out_of_service, .yb-tw-card--out_of_service, .yb-tw-chip--out_of_service,
.yb-tw-tile--unknown, .yb-tw-card--unknown, .yb-tw-chip--unknown { --tw-accent: var(--yb-text-muted); --tw-accent-rgb: 120, 128, 140; }

/* ── Toolbar: ribbon + actions ─────────────────────────────────────────── */
.yb-tw-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    justify-content: space-between;
    gap: 12px;
    margin: 14px 0 18px;
}

.yb-tw-ribbon {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.yb-tw-tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 96px;
    padding: 8px 12px 7px;
    background: var(--yb-surface);
    border: 1px solid var(--yb-border);
    border-bottom: 3px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
    cursor: pointer;
    transition: border-color var(--yb-dur, .18s) var(--yb-ease, ease), box-shadow var(--yb-dur, .18s) var(--yb-ease, ease);
}

.yb-tw-tile:hover { box-shadow: var(--yb-shadow-sm); }
.yb-tw-tile:focus-visible { outline: none; box-shadow: var(--yb-ring); }

.yb-tw-tile.is-active {
    border-bottom-color: var(--tw-accent, var(--yb-accent));
    box-shadow: var(--yb-shadow-sm);
}

.yb-tw-tile--all { --tw-accent: var(--yb-accent); }

.yb-tw-tile__count {
    font-family: var(--yb-font-display);
    font-size: 1.35rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--yb-text);
}

.yb-tw-tile__label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .74rem;
    letter-spacing: .02em;
    color: var(--yb-text-muted);
}

.yb-tw-tile__label .bi { color: var(--tw-accent, var(--yb-text-muted)); }

.yb-tw-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* ── The board ─────────────────────────────────────────────────────────── */
.yb-tw-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
    gap: 12px;
}

.yb-tw-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px 12px 18px;
    background: var(--yb-card, var(--yb-surface));
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius);
    box-shadow: var(--yb-shadow-xs);
}

/* The state spine — the card's one loud element. */
.yb-tw-card::before {
    content: "";
    position: absolute;
    inset: 8px auto 8px 6px;
    width: 4px;
    border-radius: 2px;
    background: var(--tw-accent, var(--yb-border-strong));
}

.yb-tw-card__head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.yb-tw-card__pick { margin: 0; }

.yb-tw-card__code {
    font-family: var(--yb-font-display);
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--yb-text);
    margin-right: auto;
}

.yb-tw-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--tw-accent, var(--yb-text-muted));
    background: rgba(var(--tw-accent-rgb, 120, 128, 140), .12);
    border: 1px solid rgba(var(--tw-accent-rgb, 120, 128, 140), .35);
    border-radius: var(--yb-radius-sm);
    white-space: nowrap;
}

.yb-tw-card__mac {
    font-size: .74rem;
    color: var(--yb-text-soft, var(--yb-text-muted));
    letter-spacing: .04em;
}

/* One grid for the whole list rather than a flex row per pair (#281).

   `flex: 0 0 40px` on the label was fine for the board card, whose labels are all one short word
   (With / Out / Due), and broke in the dialog, which reuses this class with longer ones: "Out
   since" and "Due back" wrapped inside 40px and left their value sitting against the SECOND line,
   so the eye paired "since" with the timestamp and lost "Out". The guest block below it is worse
   again — "ID checked", "Reach at", "From drop".

   Two columns shared by every row, so the label column sizes itself to the longest label present
   and the values still line up with each other. `minmax(40px, auto)` keeps the floor: the board
   card is unchanged (all its labels are under 40px) while the dialog's grow instead of wrapping.
   Any label added later widens the column rather than breaking. */
.yb-tw-card__facts {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(40px, auto) 1fr;
    gap: 2px 8px;
    align-items: baseline;
    font-size: .84rem;
}

/* The wrapper div only exists to pair a dt with its dd in the markup. Removing its box promotes
   both to items of the grid above — without this each row would size its own label column
   independently, which is the misalignment being fixed. A plain div carries no implicit ARIA role,
   so nothing is lost from the accessibility tree. */
.yb-tw-card__facts > div { display: contents; }

.yb-tw-card__facts dt { color: var(--yb-text-muted); font-weight: 500; }
.yb-tw-card__facts dd { margin: 0; color: var(--yb-text); }

.yb-tw-card__warn {
    margin: 2px 0 0;
    font-size: .78rem;
    color: var(--yb-danger);
    display: flex;
    gap: 6px;
    align-items: baseline;
}

.yb-tw-card__sensed {
    margin: 0;
    font-size: .76rem;
    color: var(--yb-text-muted);
    display: flex;
    gap: 6px;
    align-items: baseline;
}

.yb-tw-card__note { margin: 2px 0 0; font-size: .82rem; color: var(--yb-text-muted); }

.yb-tw-idheld { color: var(--yb-accent); margin-left: 4px; }

.yb-tw-card__actions {
    display: flex;
    gap: 8px;
    margin-top: auto;
    padding-top: 8px;
}

/* ── Sweep ─────────────────────────────────────────────────────────────── */
.yb-tw-sweep__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 12px;
    background: var(--yb-surface-2, var(--yb-surface));
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
}

.yb-tw-sweep__selectall {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: .85rem;
    color: var(--yb-text-muted);
    margin: 0;
}

.yb-tw-outcomes {
    list-style: none;
    margin: 0 0 12px;
    padding: 10px 14px;
    display: grid;
    gap: 4px;
    background: var(--yb-surface);
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
    font-size: .84rem;
}

.yb-tw-outcomes li { display: flex; gap: 8px; align-items: baseline; color: var(--yb-text); }
.yb-tw-outcomes li.is-ok .bi { color: var(--yb-success); }
.yb-tw-outcomes li.is-fail .bi { color: var(--yb-danger); }

/* ── Empty and loading states ──────────────────────────────────────────── */
/* The loan desk's empty / error blocks moved to the shared .yb-state primitive in
   ui-refinement.css (see YbStateBlock). The old .yb-tw-loading was bare muted text with px
   padding and no ARIA, so the page changed silhouette between "loading" and "empty" — one of
   eleven separate treatments the app carried. Nothing page-specific was lost. (#208 review) */

/* ── The tray, before we know what is on it ────────────────────────────── */
/* Loading no longer uses a state block: a notice reads as a settled answer, and the operator could
   not tell the screen was working. These reuse the REAL ribbon/grid/card classes and fill them
   with .yb-skel shapes, so the skeleton inherits the board's exact geometry and cannot drift from
   it — change the card and the ghost changes with it.

   The spine stays neutral because a device's state is precisely what we do not know yet; it is the
   one thing the skeleton must not guess. */
.yb-tw-card--ghost {
    --tw-accent: var(--yb-border-strong);
    gap: 10px;
    min-height: 168px;
    pointer-events: none;
}

.yb-tw-tile--ghost {
    pointer-events: none;
    min-height: 58px;
    justify-content: center;
    gap: 6px;
}

/* Ghost tiles keep the ribbon's bottom rule but drop its state colour — nothing is selected yet. */
.yb-tw-tile--ghost { border-bottom-color: var(--yb-border); }

.yb-tw-ghost-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.yb-tw-ghost-actions .yb-skel {
    height: 34px;
    border-radius: var(--yb-radius-sm);
}

/* ── Dialogs: issue + detail ───────────────────────────────────────────── */
/* The shared .yb-dialog zeroes the content's top padding (right for text-first
   bodies, whose header padding is enough air). These bodies open on a BORDERED
   plate, so flush against the header divider reads as a defect: 10px roughly
   mirrors the 12px the title keeps above that divider. */
.yb-tw-dialog__body { display: flex; flex-direction: column; gap: 14px; padding-top: 10px; }

.yb-tw-field { display: flex; flex-direction: column; gap: 4px; }

/* Labels match the data-entry screens (owner feedback 2026-07-24): the same semibold, small,
   muted look Syncfusion's e-form-label and the search panels compute — not Bootstrap's
   body-sized default, which made these dialogs read as a different screen family. */
.yb-tw-field .form-label,
.yb-tw-extend .form-label {
    margin-bottom: 0;
    font-weight: 600;
    font-size: .84rem;
    letter-spacing: .01em;
    color: var(--yb-text-muted);
}

.yb-tw-hint { margin: 2px 0 0; font-size: .76rem; color: var(--yb-text-muted); }

.yb-tw-kinds { display: flex; gap: 8px; }

.yb-tw-kind {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
    background: var(--yb-surface);
    color: var(--yb-text);
    font-size: .86rem;
    cursor: pointer;
    margin: 0;
}

.yb-tw-kind input { position: absolute; opacity: 0; pointer-events: none; }
.yb-tw-kind.is-active { border-color: var(--yb-accent); background: rgba(var(--yb-accent-rgb, 79, 70, 229), .08); }
.yb-tw-kind.is-disabled { opacity: .55; cursor: not-allowed; }
.yb-tw-kind:focus-within { box-shadow: var(--yb-ring); }

.yb-tw-check {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: .86rem;
    color: var(--yb-text);
    margin: 0;
}

.yb-tw-now {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 14px 12px 18px;
    position: relative;
    background: var(--yb-surface-2, var(--yb-surface));
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius);
}

/* The flex column stretches the state chip into a full-width bar — keep it the
   same compact rounded-rect it is on the board cards. */
.yb-tw-now > .yb-tw-chip { align-self: flex-start; }

.yb-tw-now::before {
    content: "";
    position: absolute;
    inset: 8px auto 8px 6px;
    width: 4px;
    border-radius: 2px;
    background: var(--tw-accent, var(--yb-border-strong));
}

.yb-tw-now--available, .yb-tw-now--out_of_service { --tw-accent: var(--yb-text-muted); }
.yb-tw-now--available { --tw-accent: var(--yb-success); }
.yb-tw-now--issued { --tw-accent: var(--yb-info); }
.yb-tw-now--overdue { --tw-accent: var(--yb-warning); }
.yb-tw-now--abandoned { --tw-accent: var(--yb-danger); }

.yb-tw-now__actions { display: flex; gap: 8px; align-items: center; }

.yb-tw-extend { display: flex; flex-direction: column; gap: 6px; padding-top: 4px; }

.yb-tw-history__title {
    font-family: var(--yb-font-display);
    font-size: 1rem;
    margin: 6px 0 2px;
    color: var(--yb-text);
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.yb-tw-history__count { font-family: var(--yb-font-body); font-size: .78rem; color: var(--yb-text-muted); }

.yb-tw-history { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }

.yb-tw-history__row {
    padding: 8px 12px;
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
    background: var(--yb-surface);
    display: grid;
    gap: 2px;
}

.yb-tw-history__who { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: .9rem; color: var(--yb-text); }
.yb-tw-history__when { font-size: .8rem; color: var(--yb-text); }
.yb-tw-history__meta { font-size: .76rem; color: var(--yb-text-muted); }

/* ── Guest registration + consent (#210) ───────────────────────────────── */
/* The consent block is a legal instrument, not a hint: bordered, quiet, and
   the notice text is real body copy the desk can read aloud. Rides the same
   tokens as every other card; only the wash needs a dark-side nudge below. */
.yb-tw-consent {
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--yb-border);
    border-left: 3px solid var(--yb-accent, #4f46e5);
    border-radius: var(--yb-radius-sm);
    background: rgba(var(--yb-accent-rgb, 79, 70, 229), .05);
    display: grid;
    gap: 8px;
}

.yb-tw-consent__text {
    margin: 0;
    font-size: .82rem;
    line-height: 1.5;
    color: var(--yb-text);
}

.yb-tw-consent.yb-field-invalid { border-color: var(--yb-danger, #b3261e); }

.yb-tw-guest {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--yb-border);
}

.yb-tw-guest a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* ── Pool management (#198, admin dialog) ──────────────────────────────── */
/* The add row leads (that is the job the dialog exists for); the stock list
   below it is a quiet ledger — mono macs, the same state chips as the board,
   actions at the row's end. All tokens, no bespoke colours. */
.yb-tw-pooladd {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 150px auto;
    gap: 10px;
    align-items: end;
}

.yb-tw-pooladd .yb-tw-field { margin: 0; }

.yb-tw-pooladd__go { white-space: nowrap; }

.yb-tw-pool-empty {
    margin: 14px 0 0;
    font-size: .88rem;
    color: var(--yb-text-muted);
}

.yb-tw-pool-list {
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--yb-border);
    border-radius: var(--yb-radius-sm);
    overflow: hidden;
}

.yb-tw-pool-row {
    display: grid;
    grid-template-columns: minmax(72px, auto) minmax(0, 1fr) auto auto;
    gap: 10px;
    align-items: center;
    padding: 8px 12px;
}

.yb-tw-pool-row + .yb-tw-pool-row { border-top: 1px solid var(--yb-border); }

.yb-tw-pool-row__code {
    font-weight: 600;
    font-size: .88rem;
    color: var(--yb-text);
}

.yb-tw-pool-row__mac {
    font-family: var(--bs-font-monospace, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: .8rem;
    color: var(--yb-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.yb-tw-pool-row__actions {
    display: inline-flex;
    gap: 6px;
}

@media (max-width: 640px) {
    .yb-tw-pooladd { grid-template-columns: 1fr; align-items: stretch; }
    .yb-tw-pool-row { grid-template-columns: auto minmax(0, 1fr); }
    .yb-tw-pool-row__actions { grid-column: 1 / -1; justify-content: flex-end; }
}

/* ── Dark theme ────────────────────────────────────────────────────────── */
/* Everything above rides the tokens, which flip under [data-theme="dark"].
   Only the translucent chip/pick washes need a nudge: on a dark plate a
   translucent tint must lean lighter to stay legible. */
[data-theme="dark"] .yb-tw-chip { background: rgba(var(--tw-accent-rgb, 148, 155, 170), .18); }
[data-theme="dark"] .yb-tw-kind.is-active { background: rgba(var(--yb-accent-rgb, 129, 140, 248), .16); }
[data-theme="dark"] .yb-tw-consent { background: rgba(var(--yb-accent-rgb, 129, 140, 248), .1); }

@media (prefers-reduced-motion: reduce) {
    .yb-tw-tile { transition: none; }
}

@media (max-width: 640px) {
    .yb-tw-toolbar { flex-direction: column; }
    .yb-tw-actions { justify-content: stretch; }
    .yb-tw-actions .btn { flex: 1; }
}
