/* ── Baton — the shared-systems register ─────────────────────────────────────
 *
 * Prefix is `bat-`, not `btn-`: the latter is taken by buttons everywhere
 * (baton-plan.md §2). Every value here is a design token — a rule referencing a
 * token nothing defines fails SILENTLY, rendering unstyled and looking intentional.
 */

/* Status indicators are inline dots, never pill badges (patterns §12). Three states,
 * three colours: held, free, reserved. Defined here because the pattern is a snippet
 * each section brings, not a shared class — grep confirmed nothing else defines it. */
.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 4px;
    vertical-align: middle;
}

.status-dot--held {
    background: var(--accent-confirm);
}

.status-dot--free {
    background: var(--text-muted);
}

.status-dot--reserved {
    background: var(--accent-caution);
}

/* ── Lane A — the list, the rows, the inline create/edit form ─────────────── */

/* Every token below was grepped out of main.css `:root` before being used. A rule
 * referencing a token nothing defines fails SILENTLY — the element renders, unstyled,
 * and looks intentional (patterns §23.5). */

/* The thumbnail slot. RESERVED, NOT BUILT: Lane E fills the cell, and it carries its
 * size here so the row does not change height the day it does. An empty cell with no
 * width would let every row shuffle when the pictures land. */
.bat-thumb {
    width: 44px;
    min-width: 44px;
    height: 32px;
    border-radius: var(--border-radius-sm);
    background-color: var(--bg-muted);
    overflow: hidden;
}

.bat-name {
    color: var(--text-primary);
    font-weight: 600;
}

.bat-desc {
    display: block;
    margin-top: var(--spacing-xs);
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

/* `↗ console`, a small affordance and never a second title (baton-plan.md §10). */
.bat-console {
    display: inline-block;
    margin-top: var(--spacing-xs);
    color: var(--accent-main);
    font-size: var(--font-size-body-xs);
    text-decoration: none;
}

.bat-console:hover {
    text-decoration: underline;
}

/* ⚠ The gap is a MARGIN here rather than a flex `gap`, because this cell is not a flex row: the
 * dot, the face and the name are inline, and the note below is a block. A face sitting flush
 * against a name renders as "PRPriya Raman", which is exactly the class of defect a node suite
 * cannot see and a screenshot cannot hide. (Found in the manual's capture, 2026-08-28.) */
.bat-holder,
.bat-queue-text {
    color: var(--text-primary);
    margin-left: var(--spacing-xs, 4px);
}

.bat-queue-text {
    color: var(--text-secondary);
}

/* The reason someone has it, and the reason a reserved row names its window in
 * minutes. Both answer "should I go and ask them", which is the question people
 * actually have. */
.bat-holder-note {
    display: block;
    margin-top: var(--spacing-xs);
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
    font-style: italic;
}

.bat-queue {
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

.bat-queue--empty {
    color: var(--text-muted);
}

/* ── The inline create/edit form ──────────────────────────────────────────────
 * Inline, not a modal, and emphatically not a native prompt() (conformance #5;
 * patterns §23.2 bans prompt outright). It sits in the list view above the table. */
.bat-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-md);
    /* ⚠ flex-START, and the difference is the whole bug this replaced. Each .form-group is a
     * column of label / input / optional hint, so bottom-aligning them lines up their BOTTOM
     * edges — which means a field carrying a hint sits higher than one without, and the row
     * climbs like a ladder. Top-aligning puts every label on one line and every input on the
     * next, with the hints hanging below where they exist. Reported from real use, 2026-08-27. */
    align-items: flex-start;
}

.bat-form .form-group {
    margin-bottom: 0;
    flex: 1 1 200px;
}

.bat-form .form-group--wide {
    flex: 2 1 320px;
}

.bat-form .form-group--narrow {
    flex: 0 1 140px;
}

/* The grace window's explanation is a visible hint, NOT a placeholder: a placeholder
 * truncates at the input width and disappears the moment anyone types, so anything a
 * user must know to operate the control cannot live there (patterns, prohibitions). */
.bat-field-hint {
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
}

.bat-form-actions {
    display: flex;
    gap: var(--spacing-sm);
    align-items: center;
    /* Its own full-width row. Without a basis this was a fifth flex item competing with the
     * fields — squeezed to the end of the same line and bottom-aligned, which made Save and
     * Cancel genuinely easy to miss. The way out of a form must not be something you hunt for. */
    flex: 1 1 100%;
}

/* A failed save says why, in the form, next to the field the user is looking at.
 * "Looked like it worked" is the worst outcome available (patterns, prohibitions). */
.bat-form-error {
    flex: 1 1 100%;
    color: var(--accent-danger);
    font-size: var(--font-size-body-sm);
}

.bat-row-actions {
    display: flex;
    gap: var(--spacing-xs);
    justify-content: flex-end;
}

/* Lane B fills this cell with take/pass; Lane A renders it and leaves it empty. The rule exists so
 * the class is not a name nothing defines — a rule referencing an undefined class fails silently
 * and looks intentional — and so whatever B lands here does not wrap mid-control. */
.bat-action-cell {
    white-space: nowrap;
    text-align: right;
}


/* ── Lane B — the take/pass affordances and the losing-race message ───────── */
/*
 * Lane B is behaviour, not markup: js/baton/claimActions.js renders nothing and owns
 * no DOM, so the row's buttons and layout belong to Lane A. What follows is the one
 * thing that is genuinely Lane B's — the shape of the losing number.
 *
 * ⚠ If Lane A ends up rendering the losing line only as a toast (plain text, no
 * markup), DELETE this rule rather than leaving it. A class nothing applies is dead
 * CSS; a class nothing DEFINES fails silently and looks intentional. Both are bad,
 * and only one of them is visible.
 */

/* "You missed the baton by 50.32499392 ms." The digits are the joke, so they are set
 * in a monospaced face and allowed to keep their own width — a proportional font
 * makes the absurd precision look like a typo instead of a deadpan.
 *
 * ⚠ The stack is a literal because there is no --font-mono token in main.css. Five
 * other stylesheets already hardcode this exact stack (audit-trail, cache-management
 * and friends); this is the sixth, and the token is worth adding once somebody owns
 * that sweep. */
.bat-missed-by {
    font-family: 'SF Mono', 'Fira Code', monospace;
    font-variant-numeric: tabular-nums;
    font-size: var(--font-size-body-xs);
    color: var(--text-secondary);
}

/* A row whose take is refused has to SAY WHY — "reserved for Matt for another 52
 * minutes" — because a disabled control with no explanation is the "silently does
 * nothing" failure the patterns doc bans outright. */
.bat-claim-reason {
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
    line-height: var(--line-height-body-xs);
}


/* ── Lane C — the queue and the reservation window ────────────────────────── */

/* THE LIMIT, SAID OUT LOUD, and permanently rather than only in a toast somebody
 * may have missed. v1's notifier reaches nobody who is not looking at MagGyver
 * (baton-plan.md §11), and a queue that only pings you when you are already looking
 * should admit it — otherwise people trust it further than it deserves and stop
 * watching the box themselves, which is worse than having no queue at all.
 *
 * Quiet by design: a standing caveat, not a warning. It sits between the filters and
 * the table so it is read once on the way in rather than competing with a row. */
.bat-notice {
    margin: 0;
    padding: var(--spacing-xs, 4px) var(--spacing-sm);
    border-left: 2px solid var(--border-default);
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
    line-height: var(--line-height-body-xs);
}

/* Where the READER stands in a queue, under the "next up" names.
 *
 * ⚠ `flex: 1 1 100%` and `flex-wrap` on the parent, and both are load-bearing —
 * this is the same bug the create form shipped with. `.bat-queue` is a flex ROW, so
 * without a basis this becomes a third item competing with the faces and the summary
 * on one line and squeezed to nothing. It is its own row, deliberately. */
.bat-queue {
    flex-wrap: wrap;
}

/* ⚠ NOT `--accent-main`. That is the link colour, and this is a statement about the reader, not a
 * control — a row that renders unclickable text in link blue reads as broken the moment somebody
 * tries it (§23.4's failure, arrived at from the other direction). `--text-primary` lifts it clear
 * of the `--text-secondary` summary beside it without promising anything. */
.bat-queue-yours {
    flex: 1 1 100%;
    color: var(--text-primary);
    font-size: var(--font-size-body-xs);
    line-height: var(--line-height-body-xs);
}

/* The reserved user's own window. The mirror image of `.bat-take-why`, which explains
 * a DISABLED button on somebody else's window — this one explains an ENABLED one, and
 * it is the only thing a queue ever actually gives anybody, so it is coloured as the
 * good news it is rather than as muted furniture. */
.bat-take-why--yours {
    color: var(--accent-confirm);
}



/* ── Lane D — the detail view and the history list ────────────────────────── */

/* The system's own page: a picture, its name, and what it is. `align-items:
 * flex-start`, NOT flex-end — bottom-aligning a row of columns whose heights differ
 * makes the shorter ones climb like a ladder, which is exactly the bug the create
 * form shipped with and somebody had to report. */
.bat-detail-head {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-md);
}

.bat-detail-head__text {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs, 4px);
}

.bat-detail-name {
    margin: 0;
    font-size: var(--font-size-h4);
    font-weight: 600;
    color: var(--text-primary);
}

/* An archived system still answers — history outlives it — so the page has to say
 * why nothing on it works rather than leaving somebody to find out by clicking. */
.bat-detail-archived {
    margin: 0;
    color: var(--accent-caution);
    font-size: var(--font-size-body-sm);
}

.bat-detail-subhead {
    margin: var(--spacing-sm) 0 0;
    font-size: var(--font-size-body-sm);
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.bat-detail-holder,
.bat-detail-queue {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
}

.bat-detail-holder__line {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs, 4px);
}

/* The actions row. `flex-wrap` plus the explanation taking a full basis, for the same
 * reason the queue cell does: without it, "held open for Matt — 4 min left" becomes a
 * third flex item squeezed against two buttons instead of a line under them. */
.bat-detail-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-sm);
}

.bat-detail-actions .bat-take-why {
    flex: 1 1 100%;
}

/* Taking the baton off somebody. Deliberately NOT primary: it is a real action, it is
 * available, and it must not look like the obvious thing to do — the queue button
 * beside it is. Coloured as a caution rather than a danger, because forcing a
 * forgotten hold is the NORMAL case and a tool that makes the normal case feel like a
 * transgression gets worked around instead of used (D19, D24). */
.bat-force {
    color: var(--accent-caution);
    border-color: var(--accent-caution);
}

/* ── The queue, in full, with real positions ──────────────────────────────── */

.bat-queue-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs, 4px);
}

.bat-queue-row {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    padding: var(--spacing-xs, 4px) 0;
    border-bottom: 1px solid var(--border-subtle);
}

/* Whoever the window is currently open for. They are not waiting — they are up — and
 * the row says so in words ("up now") as well as in colour, because colour alone is
 * not an explanation. */
.bat-queue-row--up .bat-queue-place {
    color: var(--accent-caution);
    font-weight: 600;
}

.bat-queue-place {
    min-width: 4.5em;
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
}

.bat-queue-name {
    color: var(--text-primary);
}

.bat-queue-waited {
    margin-left: auto;
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
}

.bat-queue-remove {
    flex: 0 0 auto;
}

/* ── The history ──────────────────────────────────────────────────────────── */

.bat-history-when {
    color: var(--text-secondary);
    white-space: nowrap;
}

.bat-history-holder {
    margin-left: var(--spacing-xs, 4px);
    color: var(--text-primary);
}

/* Durations are the point of story S7 ("we hold this for six hours at a time"), so
 * they are read as a COLUMN of numbers — tabular figures keep them aligned, and the
 * monospaced stack keeps 42m and 3h the same width.
 *
 * ⚠ The stack is a literal because there is no --font-mono token in main.css; see the
 * note on .bat-missed-by. Same dangler, same sweep. */
.bat-history-duration {
    font-family: 'SF Mono', 'Fira Code', monospace;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    white-space: nowrap;
}

.bat-history-ending {
    color: var(--text-secondary);
    white-space: nowrap;
}

/* ★ A FORCED release, and this rule is the audit signal becoming visible.
 * `ReleasedByUserId` differing from `HolderId` IS the record (baton-plan.md §13.1);
 * the cell says "forced by Jerome" in words, and this makes it findable when somebody
 * is scanning a long history for the one row that is not ordinary. Caution, not
 * danger: forcing a forgotten hold is normal, and it is being made visible rather
 * than condemned. */
.bat-history-ending--forced {
    color: var(--accent-caution);
}

.bat-history-note {
    color: var(--text-muted);
}



/* ── Lane E — thumbnails, monograms and faces ─────────────────────────────── */

/* A monogram is the FALLBACK and it is the NORMAL case — most people never upload a picture and
 * most systems never get one — so it has to read as a design decision rather than as a hole. The
 * background colour is set inline because it is derived per person / per system from a hash of the
 * id, which is what makes the same face the same colour on every row and every page load. White on
 * a saturated hsl is the treatment daigrammar's card grid already uses. */

/* ── The system picture: the [img] slot at the left of a row ───────────── */
.bat-thumb {
    position: relative;
    flex: 0 0 auto;
    width: 48px;
    height: 48px;
    overflow: hidden;
    border-radius: var(--border-radius-md);
    background: var(--bg-subtle);
}

.bat-thumb__monogram {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-body-lg);
    font-weight: 600;
    color: #fff;
    text-transform: uppercase;
    user-select: none;
}


.bat-thumb__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ── A person's face ──────────────────────────────────────── */
.bat-face {
    --bat-face-size: 24px;
    position: relative;
    display: inline-block;
    flex: 0 0 auto;
    width: var(--bat-face-size);
    height: var(--bat-face-size);
    overflow: hidden;
    border-radius: 50%;
    background: var(--bg-subtle);
    vertical-align: middle;
}

.bat-face__monogram {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Scaled off the face size rather than a token, so one rule serves a 24px row face and a 48px
     * holder card without a second class. */
    font-size: calc(var(--bat-face-size) * 0.42);
    font-weight: 600;
    line-height: 1;
    color: #fff;
    letter-spacing: 0.02em;
    user-select: none;
}


.bat-face__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ── "next up: (MT)(LO)(KV) +2" ─────────────────────────────── */
.bat-face-stack {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

/* Overlapped, so a queue reads as a cluster rather than a list. The ring is the card background,
 * which is what keeps two adjacent monograms legible as two faces. */
.bat-face-stack .bat-face + .bat-face {
    margin-left: -6px;
}

.bat-face-stack .bat-face {
    box-shadow: 0 0 0 2px var(--bg-elevated);
}

.bat-face-stack__more {
    margin-left: var(--spacing-xs);
    font-size: var(--font-size-body-sm);
    color: var(--text-muted);
}

/* ── The upload affordance ─────────────────────────────────── */
.bat-thumb-upload {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-md);
}

.bat-thumb-upload__preview {
    width: 72px;
    height: 72px;
}

.bat-thumb-upload__fields {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-xs);
    min-width: 0;
}

/* The native file input is a hook, not a control — the button beside it is what people operate,
 * because a native file input cannot be styled to match anything else in this app. Belt and braces
 * with the `hidden` property the module sets. */
.bat-thumb-upload__input {
    display: none;
}

.bat-thumb-upload__label {
    font-size: var(--font-size-body-sm);
    font-weight: 600;
    color: var(--text-secondary);
}

/* The instruction is a visible hint, never a placeholder — placeholders truncate at the input
 * width, and this one says a load-bearing thing: anyone here can replace the picture. */
.bat-thumb-upload__hint {
    margin: 0;
    font-size: var(--font-size-body-sm);
    color: var(--text-muted);
}

.bat-thumb-upload__status {
    margin: 0;
    font-size: var(--font-size-body-sm);
    color: var(--text-secondary);
}

.bat-thumb-upload__status[data-kind="error"] {
    color: var(--accent-danger);
}

.bat-thumb-upload__status[data-kind="success"] {
    color: var(--accent-confirm);
}

/* ── Merge integration — the row's take/pass control and the queue cluster ───
 *
 * Written at merge rather than in a lane: the action cell is Lane B's behaviour
 * inside Lane A's row, and the queue cluster is Lane E's faces inside it. Every
 * token below was grepped in css/ first — a rule referencing a token nothing
 * defines fails silently and looks intentional.
 */
.bat-take-wrap {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

/* The reason a disabled Take button is disabled. VISIBLE, never a title attribute:
 * a disabled control that does not explain itself is the "silently does nothing"
 * failure the patterns doc bans outright. */
.bat-take-why {
    color: var(--text-muted);
    font-size: var(--font-size-body-sm);
    white-space: nowrap;
}

.bat-queue {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs, 4px);
}

.bat-queue-text {
    font-size: var(--font-size-body-sm);
}

.bat-queue--empty .bat-queue-text {
    color: var(--text-muted);
}


/* ── The day-1 follow-up pass (2026-08-28) ────────────────────────────────────
 *
 * Every token below was grepped out of main.css `:root` first. A rule referencing a token nothing
 * defines fails SILENTLY — the element renders unstyled and looks intentional (patterns §23.5). */

/* ★ "Live updates paused" (day-1-followup item B).
 *
 * In `.pagination`, which is `position: fixed; bottom: 0`, so it is the one strip of a list that
 * cannot be scrolled away from — and a list that has stopped listening is exactly the thing you
 * must not have to go looking for.
 *
 * ⚠ It ships WITH the merge that removed the poll's flicker (item C), not after it. The rebuild
 * every thirty seconds was, accidentally, the only evidence anybody had that the poll was alive:
 * a window that had silently latched looked identical to a quiet one. Taking the flicker away
 * without putting this in its place would have hidden item B rather than fixed it.
 *
 * `--accent-caution` rather than an error colour: the rows on screen are still the last good
 * answer, so this is a staleness warning and not a failure. */
.bat-live {
    color: var(--accent-caution);
}

/* ★ A retired system's action cell (day-1-followup item D). Not a pill badge — patterns §12 is
 * unambiguous — just muted text where the verb would be. A system that cannot be taken, queued for
 * or forced gets no button at all rather than a disabled one, so this is what stands in its place. */
.bat-retired {
    color: var(--text-muted);
    font-size: var(--font-size-body-sm);
    font-style: italic;
}

/* A retired row is a record. Muting it is what stops the archived half of the list reading as an
 * ordinary list that happens to have no buttons. */
.table tbody tr[data-archived="true"] .bat-name {
    color: var(--text-secondary);
}
