/* ── Production Roster — the studio's day-by-day resourcing grid ─────────────
 *
 * Prefix is `ros-`. `rost-` was rejected because it reads as a typo of `rest-`,
 * and `bat-` (Baton) set the precedent of a short three-letter module prefix.
 *
 * ⚠ EVERY VALUE HERE IS A DESIGN TOKEN from main.css `:root`, and each one was
 * grepped out of it before being used. A rule referencing a token nothing
 * defines fails SILENTLY — the element renders, unstyled, and looks intentional.
 */

/* ── ★ THE SPACING LANGUAGE ──────────────────────────────────────────────────
 *
 * Reported from real use, about the week navigator: "the styling and spacing
 * makes them seem unconnected... the spacing should develop a language that
 * relates the elements consistently."
 *
 * It was right, and the cause was that ONE gap did every job. Prev, the date,
 * the range and next sat the same distance apart as they did from "This week",
 * so nothing said which of them operated on which. Proximity is the only cue a
 * toolbar has, and spending it evenly spends it on nothing.
 *
 * Four steps, each meaning exactly one thing. Every gap on this screen is one
 * of them; if a new rule needs a fifth, the rule is probably wrong.
 *
 *   --ros-gap-welded    0     parts of ONE control. No gap at all — a shared
 *                             border and hairline dividers instead, because
 *                             adjacency is what says "one thing".
 *   --ros-gap-tight     4px   repeated peers in a set: pills, chips, swatches.
 *   --ros-gap-related   8px   distinct controls doing the same job, e.g. the
 *                             week segment and "This week".
 *   --ros-gap-group     16px  separate clusters on one row: the week group and
 *                             the actions group.
 *   --ros-gap-section   24px  the horizontal bands: toolbar / summary /
 *                             filters / grid.
 */
.ros-root {
    --ros-gap-welded: 0;
    --ros-gap-tight: var(--spacing-xs);
    --ros-gap-related: var(--spacing-sm);
    --ros-gap-group: var(--spacing-md);
    --ros-gap-section: var(--spacing-lg);

    display: flex;
    flex-direction: column;
    gap: var(--ros-gap-section);
    padding: var(--spacing-md);
    color: var(--text-primary);
}

/* ── toolbar: week navigation + the two write actions ───────────────────── */

.ros-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ros-gap-group);      /* two clusters, so a GROUP gap */
}

.ros-week,
.ros-toolbar-actions {
    display: flex;
    align-items: center;
    gap: var(--ros-gap-related);    /* peers doing the same job */
}

/* ── ★ THE SEGMENTED WEEK CONTROL ────────────────────────────────────────────
 *
 * One border around prev / date / range / next, hairline dividers between, and
 * NO gap inside. That is the whole fix: the elements read as one control
 * because they are drawn as one, and "This week" reads as a separate action
 * because it sits outside at a related-gap.
 *
 * A single height token drives the segment and every sibling button, so the
 * toolbar sits on one baseline instead of four. */
.ros-segment {
    --ros-control-height: 34px;

    display: inline-flex;
    align-items: stretch;
    gap: var(--ros-gap-welded);
    height: var(--ros-control-height);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    background: var(--bg-muted);
    overflow: hidden;
}

/* The dividers ARE the grouping. A border-left on every child but the first
 * costs one rule and cannot fall out of step with the number of children. */
.ros-segment > * + * {
    border-left: 1px solid var(--border-default);
}

.ros-seg-btn {
    display: flex;
    align-items: center;
    padding: 0 var(--spacing-sm);
    background: transparent;
    border: none;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: var(--font-size-body-md);
    line-height: 1;
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.ros-seg-btn:hover {
    background: var(--interactive-hover);
    color: var(--text-primary);
}

.ros-seg-date {
    display: flex;
    align-items: center;
    padding: 0 var(--spacing-xs) 0 var(--spacing-sm);
}

.ros-seg-date input {
    background: transparent;
    border: none;
    color: var(--text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-ui-sm);
    padding: 0;
}

/* The human-readable range is the LABEL of the control, so it carries the
 * emphasis and the date input beside it reads as the way to change it. */
.ros-seg-range {
    display: flex;
    align-items: center;
    padding: 0 var(--spacing-md);
    color: var(--text-primary);
    font-weight: 600;
    font-size: var(--font-size-body-sm);
    white-space: nowrap;
    min-width: 132px;
}

.ros-toolbar .ros-btn,
.ros-toolbar .ros-search {
    height: 34px;                   /* the same token the segment uses */
}

.ros-btn {
    background: var(--bg-muted);
    color: var(--text-primary);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    padding: 6px 12px;
    font-size: var(--font-size-ui-md);
    font-family: inherit;
    cursor: pointer;
    transition: background var(--transition-fast);
}

.ros-btn:hover {
    background: var(--interactive-hover);
}

.ros-btn--primary {
    background: var(--accent-main);
    border-color: var(--accent-main);
    color: var(--shade-white);
}

.ros-btn--danger {
    background: transparent;
    border-color: var(--accent-danger);
    color: var(--accent-danger);
}

.ros-btn--ghost {
    background: transparent;
    border-color: transparent;
    color: var(--text-secondary);
}

.ros-btn--icon {
    padding: 6px 10px;
}

.ros-date,
.ros-search {
    background: var(--bg-muted);
    color: var(--text-primary);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    padding: 6px 10px;
    font-family: inherit;
    font-size: var(--font-size-ui-md);
}

/* ── summary bar ─────────────────────────────────────────────────────────── */

.ros-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: var(--ros-gap-related);    /* peers doing the same job */
}

.ros-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--border-strong);
    border-radius: var(--border-radius-md);
    padding: var(--spacing-sm) var(--spacing-md);
}

.ros-card-num {
    font-family: var(--font-family-mono);
    font-size: var(--font-size-h4);
    line-height: var(--line-height-h4);
}

.ros-card-label {
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

/* The four states, and they are the ONE colour vocabulary in this module —
 * the badge, the swatch and the card all read from these same four tokens, so
 * "over-booked" cannot be one red on a card and a different red on a badge. */
.ros-card--free   { border-left-color: var(--text-muted); }
.ros-card--under  { border-left-color: var(--accent-main); }
.ros-card--full   { border-left-color: var(--accent-confirm); }
.ros-card--over   { border-left-color: var(--accent-danger); }

/* ── filters ─────────────────────────────────────────────────────────────── */

/* Clusters (view toggle · department pills · utilization pills · free-on-day)
 * at a GROUP gap; the repeated pills inside each at a TIGHT gap. That contrast
 * is what makes four clusters read as four rather than as twelve chips. */
.ros-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ros-gap-group);
}

.ros-views {
    display: inline-flex;
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    overflow: hidden;
}

.ros-views button {
    background: transparent;
    color: var(--text-secondary);
    border: none;
    padding: 6px 14px;
    font-family: inherit;
    font-size: var(--font-size-ui-md);
    cursor: pointer;
}

.ros-views button.is-active {
    background: var(--bg-muted);
    color: var(--text-primary);
}

.ros-pills,
.ros-utils {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ros-gap-tight);      /* repeated peers in a set */
}

.ros-pill,
.ros-util {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    padding: 4px 10px;
    font-family: inherit;
    font-size: var(--font-size-ui-sm);
    cursor: pointer;
}

.ros-pill.is-active,
.ros-util.is-active {
    background: var(--bg-muted);
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.ros-pill-count {
    color: var(--text-muted);
    font-family: var(--font-family-mono);
}

.ros-swatch {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    display: inline-block;
}

.ros-swatch--all    { background: var(--text-disabled); }
.ros-swatch--free   { background: var(--text-muted); }
.ros-swatch--under  { background: var(--accent-main); }
.ros-swatch--full   { background: var(--accent-confirm); }
.ros-swatch--over   { background: var(--accent-danger); }

/* ★ The combined filter, drawn as the two swatches it unions rather than as a
 * sixth colour. A new colour would imply a fifth utilization STATE, and there
 * are four — this pill selects two of them, and the swatch should say so. Split
 * at a hard stop so it reads as two halves, not as a gradient. */
.ros-swatch--free-under {
    background: linear-gradient(
        90deg,
        var(--text-muted) 0 50%,
        var(--accent-main) 50% 100%);
}

.ros-free-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-secondary);
    font-size: var(--font-size-ui-md);
}

.ros-free-toggle select {
    background: var(--bg-muted);
    color: var(--text-primary);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-sm);
    padding: 3px 6px;
    font-family: inherit;
}

/* ── the grid ────────────────────────────────────────────────────────────── */

.ros-grid-wrap {
    overflow-x: auto;
    border: 1px solid var(--border-subtle);
    border-radius: var(--border-radius-md);
}

/* ★ FIXED LAYOUT, so opening a cell editor cannot resize the week.
 *
 * Reported from real use: "when clicking add the column gets wider, then when
 * leaving the form, it gets narrow again... it also doesn't seem necessary."
 * Correct on both counts. With `table-layout: auto` the browser re-measures
 * every column against its widest cell, so the <select> inside one open editor
 * reflowed the entire grid — and reflowed it BACK on close. The prototype did
 * the same; in a dense grid it reads as the page flinching.
 *
 * `table-layout: fixed` makes the first row's widths the whole answer, so the
 * editor has to fit the column rather than the column fitting the editor. The
 * widths below are what the read-only content already needed. */
.ros-grid {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    font-size: var(--font-size-body-sm);
}

/* Every column is declared, because `table-layout: fixed` divides any leftover
 * space between columns that are not — and one undeclared column would absorb
 * all of it. */
.ros-name-col,
.ros-name-cell {
    width: 232px;
}

.ros-day,
.ros-cell {
    width: 132px;
}

.ros-util-col,
.ros-util-cell {
    width: 168px;
}

/* A fixed column clips rather than growing, so anything that could be long has
 * to say how it behaves. A project name wraps; it is the content people read. */
.ros-cell-task,
.ros-person-name,
.ros-person-meta {
    overflow-wrap: anywhere;
}

.ros-grid th {
    text-align: left;
    padding: var(--spacing-sm);
    color: var(--text-secondary);
    font-size: var(--font-size-ui-sm);
    font-weight: 600;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border-default);
    position: sticky;
    top: 0;
    z-index: 1;
}

.ros-grid td {
    padding: 6px var(--spacing-sm);
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: top;
}

/* The name column stays put while the week scrolls sideways — without it the
 * rows are anonymous the moment somebody looks at Thursday. */
.ros-name-col,
.ros-name-cell {
    position: sticky;
    left: 0;
    background: var(--bg-primary);
    z-index: 2;
    min-width: 200px;
}

.ros-day-date {
    display: block;
    color: var(--text-muted);
    font-weight: 400;
}

.ros-day.is-today,
.ros-cell.is-today {
    background: var(--bg-surface);
}

/* ── ★ L5 — FOCUS ONE DAY ────────────────────────────────────────────────────
 *
 * "Today mode vs week mode — just highlights the day better when you want to
 * focus on a single day." Asked for as a UX change with no data behind it, and
 * built as exactly that: the other four days are still drawn, still editable
 * and still counted in every badge. Nothing is filtered.
 *
 * The whole effect is width plus contrast. `table-layout: fixed` takes its
 * widths from the header row, so declaring them on `.ros-day` is what actually
 * moves the column; `.ros-cell` matches so the two cannot disagree. */
.ros-day.is-focused,
.ros-cell.is-focused {
    width: 300px;
}

.ros-day.is-focused {
    color: var(--text-primary);
}

.ros-cell.is-focused {
    background: var(--bg-surface);
}

/* The focused column is edged rather than merely wider, so it reads as one
 * column singled out rather than as a table that has gone wrong. */
.ros-day.is-focused,
.ros-cell.is-focused {
    box-shadow: inset 1px 0 0 var(--accent-main), inset -1px 0 0 var(--accent-main);
}

/* ⚠ Dimmed, NOT hidden, and still at a readable contrast. The point of focusing
 * Wednesday is usually to place work on it, and what is on Tuesday and Thursday
 * is precisely what decides whether you can. A collapsed column would answer the
 * narrow question and hide the one the producer is actually asking. */
.ros-day.is-unfocused,
.ros-cell.is-unfocused {
    width: 96px;
    opacity: 0.55;
}

.ros-day-btn {
    display: block;
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
    border-radius: var(--border-radius-sm);
}

.ros-day-btn:hover {
    color: var(--text-primary);
}

.ros-divider td {
    background: var(--bg-muted);
    color: var(--text-secondary);
    font-size: var(--font-size-ui-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.ros-divider--title td {
    background: var(--bg-surface);
    text-transform: none;
    letter-spacing: 0;
    padding-left: var(--spacing-lg);
}

.ros-person {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    color: inherit;
    font-family: inherit;
    cursor: pointer;
    padding: 0;
}

.ros-person-name {
    display: block;
    color: var(--text-primary);
    font-weight: 600;
}

.ros-person-meta,
.ros-person-cap {
    display: block;
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

/* The same argument vertically: a read-only booking and an open editor have to
 * occupy the same height, or the row jumps as well as the column. */
.ros-cell-row,
.ros-cell-edit {
    min-height: 34px;
}

.ros-cell-row {
    border-radius: var(--border-radius-sm);
    padding: 3px 6px;
    cursor: pointer;
}

.ros-cell-row:hover {
    background: var(--interactive-hover);
}

/* A split day's bookings stack as repeated peers of one another, so TIGHT — the
 * vocabulary's "repeated peers in a set". Anything looser and two halves of one
 * Tuesday read as two separate days. */
.ros-cell-rows {
    display: flex;
    flex-direction: column;
    gap: var(--ros-gap-tight);
}

/* Offered on every cell, but quiet on one that already has bookings: it is the
 * way to a SECOND booking, not the cell's main affordance. */
.ros-cell-add {
    color: var(--text-disabled);
    font-size: var(--font-size-body-xs);
    padding: 0 6px;
    cursor: pointer;
    border-radius: var(--border-radius-sm);
}

.ros-cell-add:hover {
    background: var(--interactive-hover);
    color: var(--text-secondary);
}

/* Shown only on a split or impossible day — on a single booking it would just
 * repeat the figure directly above it.
 *
 * ⚠ The rule sits ABOVE the total and the total sits directly under the bookings
 * it sums, so the line separates "the bookings and their total" from "+ add"
 * rather than separating the total from what it totals. */
.ros-cell-total {
    padding: 2px 6px 0;
    color: var(--text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-body-xs);
    border-top: 1px solid var(--border-subtle);
}

/* ★ A day over 24 hours. A HIGHLIGHT, deliberately not a write-time guard
 * (jmeyers, 2026-09-17): its usual cause is a producer genuinely double-booking
 * somebody across two projects without noticing, which is the thing this tool
 * exists to make visible. Refusing the write would hide it instead. */
.ros-cell-total.is-impossible {
    color: var(--text-error, #f87171);
    font-weight: 600;
}

.ros-cell-task {
    border-left: 3px solid var(--border-strong);
    padding-left: 6px;
    color: var(--text-primary);
}

.ros-cell-hours-read {
    color: var(--text-secondary);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-body-xs);
    padding-left: 9px;
}

.ros-cell-empty {
    color: var(--text-disabled);
    font-size: var(--font-size-body-xs);
}

/* Grid rather than flex: the hours box is a FIXED 52px, the remove is a fixed
 * 18px, and the project picker takes what is left — so the editor is exactly as
 * wide as the column whatever the longest project name happens to be. With flex
 * the picker's intrinsic width leaked back out and pushed the column open again.
 *
 * ⚠ The third track is declared even when there is no button to put in it (a new
 * row renders a spacer), so opening an existing booking and opening a new one do
 * not lay out differently. */
.ros-cell-edit {
    display: grid;
    grid-template-columns: 1fr 52px 18px;
    gap: var(--ros-gap-tight, 4px);
    align-items: start;
}

/* Inside the open editor only. An (x) beside every booking all week would be a
 * delete one mis-click away; opening the row first is the acknowledgement. */
.ros-cell-remove {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--text-muted);
    font-size: var(--font-size-body-sm);
    line-height: 1.4;
}

.ros-cell-remove:hover {
    color: var(--text-error, #f87171);
}

.ros-cell-edit select,
.ros-cell-edit input {
    background: var(--bg-muted);
    color: var(--text-primary);
    border: 1px solid var(--interactive-focus);
    border-radius: var(--border-radius-sm);
    padding: 3px 4px;
    font-family: inherit;
    font-size: var(--font-size-body-xs);
    /* ⚠ `min-width: 0` is what lets a grid item shrink below its intrinsic
     * content width. Without it a <select> refuses to go narrower than its
     * longest <option>, which is the other half of the column-widening. */
    min-width: 0;
    width: 100%;
}

.ros-badge {
    display: inline-block;
    border-radius: 999px;
    padding: 2px 8px;
    font-size: var(--font-size-ui-xs);
    white-space: nowrap;
}

.ros-badge--free   { background: var(--bg-muted); color: var(--text-muted); }
.ros-badge--under  { background: var(--bg-muted); color: var(--accent-main); }
.ros-badge--full   { background: var(--bg-muted); color: var(--accent-confirm); }
.ros-badge--over   { background: var(--bg-muted); color: var(--accent-danger); }

.ros-util-pct {
    display: block;
    color: var(--text-muted);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-ui-xs);
}

/* ── by-project view ─────────────────────────────────────────────────────── */

.ros-project-card {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: var(--border-radius-md);
    margin-bottom: var(--spacing-sm);
    overflow: hidden;
}

.ros-project-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--spacing-sm) var(--spacing-md);
    border-bottom: 1px solid var(--border-subtle);
}

.ros-project-name {
    border-left: 3px solid var(--accent-main);
    padding-left: var(--spacing-sm);
    font-weight: 600;
}

.ros-project-meta {
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

.ros-project-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-body-sm);
}

.ros-project-table th {
    text-align: left;
    padding: 4px var(--spacing-md);
    color: var(--text-muted);
    font-size: var(--font-size-ui-xs);
    font-weight: 600;
}

.ros-project-table td {
    padding: 4px var(--spacing-md);
    border-top: 1px solid var(--border-subtle);
}

.ros-project-hrs,
.ros-project-total {
    font-family: var(--font-family-mono);
    text-align: center;
}

.ros-project-hrs.is-blank {
    color: var(--text-disabled);
}

.ros-unassigned {
    background: var(--bg-surface);
    border: 1px dashed var(--border-default);
    border-radius: var(--border-radius-md);
    padding: var(--spacing-sm) var(--spacing-md);
}

.ros-unassigned-head {
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
    margin-bottom: var(--spacing-xs);
}

.ros-unassigned-names {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
}

.ros-unassigned-names span {
    background: var(--bg-muted);
    border-radius: var(--border-radius-sm);
    padding: 2px 8px;
    font-size: var(--font-size-body-xs);
}

/* ── modals ──────────────────────────────────────────────────────────────── */

.ros-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.ros-modal {
    background: var(--bg-elevated);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--spacing-lg);
    width: 420px;
    max-width: 92vw;
    max-height: 88vh;
    overflow-y: auto;
}

.ros-modal--wide {
    width: 620px;
}

.ros-modal h3 {
    margin: 0 0 var(--spacing-md);
    font-size: var(--font-size-h5);
}

.ros-modal label {
    display: block;
    margin-top: var(--spacing-sm);
    color: var(--text-secondary);
    font-size: var(--font-size-ui-sm);
}

.ros-modal input[type="text"],
.ros-modal input[type="number"],
.ros-modal input[type="date"],
.ros-modal input[type="search"],
.ros-modal select {
    width: 100%;
    background: var(--bg-muted);
    color: var(--text-primary);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    padding: 7px 9px;
    font-family: inherit;
    font-size: var(--font-size-body-sm);
}

.ros-checkbox {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: var(--spacing-sm);
}

.ros-modal-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--spacing-sm);
    margin-top: var(--spacing-lg);
}

.ros-modal-actions-right {
    display: flex;
    gap: var(--ros-gap-related, var(--spacing-sm));
}

/* ── quick-create: department / title / project, without leaving what you were
 * doing. It STACKS above whatever opened it, so the person form stays visible
 * behind it and the context is not lost. */
.ros-modal--narrow {
    width: 360px;
}

.ros-backdrop--stacked {
    /* One above the modal that opened it; the dimming compounds, which is what
     * says which layer is live. */
    z-index: 1001;
    background: rgba(0, 0, 0, 0.45);
}

.ros-qc-hint {
    margin: 0 0 var(--spacing-sm);
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
    line-height: 1.5;
}

.ros-qc-colour {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
}

.ros-qc-colour input[type="color"] {
    width: 40px;
    min-width: 40px;
    height: 34px;
    padding: 2px;
    background: var(--bg-muted);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius-md);
    cursor: pointer;
}

.ros-btn:disabled {
    opacity: 0.6;
    cursor: default;
}

.ros-modal-error {
    margin-top: var(--spacing-sm);
    color: var(--accent-danger);
    font-size: var(--font-size-body-xs);
}

.ros-bulk-span {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--spacing-sm);
}

.ros-bulk-tools {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    margin-top: var(--spacing-xs);
}

.ros-link {
    background: none;
    border: none;
    color: var(--accent-main);
    font-family: inherit;
    font-size: var(--font-size-ui-sm);
    cursor: pointer;
    padding: 0;
}

.ros-bulk-count {
    margin-left: auto;
    color: var(--text-muted);
    font-size: var(--font-size-ui-sm);
}

.ros-bulk-list {
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid var(--border-subtle);
    border-radius: var(--border-radius-md);
    margin-top: var(--spacing-xs);
}

.ros-bulk-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px var(--spacing-sm);
    margin: 0;
    font-size: var(--font-size-body-sm);
}

/* ★ THE CONFLICT REPORT — §10 D2's recommendation made visible. It is the one
 * block in this module that has to read as a warning rather than as furniture,
 * because the button beside it destroys somebody else's week. */
.ros-conflicts {
    margin-top: var(--spacing-md);
    border: 1px solid var(--accent-caution);
    border-radius: var(--border-radius-md);
    padding: var(--spacing-sm) var(--spacing-md);
    background: var(--bg-muted);
}

.ros-conflicts-head {
    color: var(--accent-caution);
    font-weight: 600;
    font-size: var(--font-size-body-sm);
}

.ros-conflicts ul {
    margin: var(--spacing-xs) 0 0;
    padding-left: var(--spacing-md);
    max-height: 160px;
    overflow-y: auto;
    font-size: var(--font-size-body-xs);
    color: var(--text-secondary);
}

.ros-conflicts-more {
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
}

/* ── shared ──────────────────────────────────────────────────────────────── */

.ros-empty {
    padding: var(--spacing-xl);
    text-align: center;
    color: var(--text-muted);
    font-size: var(--font-size-body-sm);
}

.ros-note {
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
    line-height: 1.5;
}

/* ── Presence (§7, lane C) ───────────────────────────────────────────────────
 *
 * Two marks, answering two different questions:
 *
 *   .ros-presence        the header zone — "is anybody else in the roster at all?"
 *   .ros-peer-editing    a booking marker — "is somebody in THIS booking?"
 *
 * ★ The peer's colour arrives as a custom property set by the surgical paint
 * (rosterPresence.paintPresence), never as an inline background, so a marker can
 * be restyled here without the JS knowing anything about how it looks. The colour
 * itself is derived from the peer's clientId, so it is stable within a session and
 * the same on every screen. */

.ros-presence-host {
    display: flex;
    align-items: center;
}

/* ⚠ An EMPTY host still consumes one of `.ros-toolbar-actions`'s flex gaps, so a roster where
 * presence never started — no Group, a node test, an unreachable hub — would carry a permanent
 * phantom space before the search box that nothing explains. It costs one toolbar reflow when
 * presence does come up, which is a one-time shift at mount rather than a standing defect. */
.ros-presence-host:empty {
    display: none;
}

.ros-presence {
    display: flex;
    align-items: center;
    gap: var(--ros-gap-tight);      /* repeated peers in a set */
}

.ros-avatar {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-ui-xs);
    font-weight: 600;
    color: #fff;
    /* The ring separates overlapping chips from the toolbar behind them, and it is
     * the PAGE's ground rather than a fixed white so it holds in both themes. */
    box-shadow: 0 0 0 2px var(--bg-primary);
    user-select: none;
}

/* "You" reads as a peer of the others, not as a different kind of thing — but it
 * is hollow, because a filled chip for yourself competes with the people the zone
 * exists to tell you about. */
.ros-avatar--self {
    background: transparent !important;
    color: var(--text-secondary);
    box-shadow: inset 0 0 0 1px var(--border-strong), 0 0 0 2px var(--bg-primary);
}

.ros-avatar--more {
    background: var(--bg-muted) !important;
    color: var(--text-secondary);
}

.ros-presence-label {
    font-size: var(--font-size-body-xs);
    color: var(--text-disabled);
    white-space: nowrap;
}

/* ★ THE BOOKING MARKER: a tint plus an INSET outline, both in the peer's own colour.
 *
 * ⚠ NOT A LEFT BAR, and the screenshot gate is what caught it. `.ros-cell-task`
 * already carries a left border in the PROJECT's colour, which is load-bearing — it
 * is how a producer reads which project a booking is on at a glance. A second
 * coloured bar immediately beside it puts two different meanings in the same visual
 * idiom, one cell apart, and the reader has to learn which is which. The tint says
 * "occupied" without competing for that idiom at all.
 *
 * ⚠ `outline` with a NEGATIVE offset, not `border`: an outline is painted outside
 * the box model, so it costs no layout, and pulling it inward keeps it inside the
 * cell rather than bleeding over the column divider. A border would shift the row by
 * a pixel and make the whole week twitch every time somebody opened a cell.
 *
 * ⚠ Deliberately quiet. This fires while a colleague is mid-edit, which on a busy
 * week is often — and a marker loud enough to be read as an error is one people
 * learn to ignore. It has to be noticeable when looked at, not attention-grabbing. */
.ros-cell-row.ros-peer-editing,
.ros-cell-add.ros-peer-editing,
.ros-cell-empty.ros-peer-editing,
.ros-cell-edit.ros-peer-editing {
    background: color-mix(in srgb, var(--ros-peer-colour, var(--accent-main)) 14%, transparent);
    outline: 1px solid color-mix(in srgb, var(--ros-peer-colour, var(--accent-main)) 55%, transparent);
    outline-offset: -1px;
    border-radius: var(--border-radius-sm);
    cursor: pointer;
}

/* The one place it gets louder: YOU are in the booking a peer is also in. That is the
 * collision the whole feature exists for, so it earns a solid outline at full colour. */
.ros-cell-edit.ros-peer-editing {
    outline: 1px solid var(--ros-peer-colour, var(--accent-main));
}

/* A hover on a marked row must not wash the tint out — the marker outranks the
 * hover, because "somebody is in here" matters more than "your pointer is here". */
.ros-cell-row.ros-peer-editing:hover {
    background: color-mix(in srgb, var(--ros-peer-colour, var(--accent-main)) 22%, transparent);
}

/* ══════════════════════════════════════════════════════════════════════════
 * ★★ THE 2026-09-22 STAKEHOLDER BATCH — location, and Booked / Held / PTO.
 *
 * ⚠ EVERY VALUE BELOW IS A TOKEN FROM main.css `:root`, grepped out of it
 *   before use, per this file's opening rule.
 *
 * ⚠⚠ AND THE PALETTE IS A DARK ONE. The request said "pastel", and the
 *    stakeholder's prototype is a LIGHT page whose #EBEDEF fills are exactly
 *    right there and would glare here. The dark-theme equivalent of a pastel
 *    is a LOW-ALPHA TINT of the hue over the surface — the same hue, a tenth
 *    of the presence. That is what these are.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ── where somebody is ──────────────────────────────────────────────────────
 *
 * Deliberately quiet. It sits beside a name that people scan down a column of
 * 93, so it has to be legible without ever competing with the name itself.
 * Rendered only when set — see `locationTag`. */
.ros-loc-tag {
    display: inline-block;
    margin-left: var(--ros-gap-tight);
    padding: 0 5px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--border-radius-sm);
    color: var(--text-muted);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    vertical-align: middle;
}

/* Its own band, because "where" and "how loaded" are two axes a producer
 * combines rather than one list of seven things. `--ros-gap-tight` is the
 * "repeated peers in a set" step, same as the pills above it. */
.ros-locs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ros-gap-tight);
    align-items: center;
}

.ros-loc {
    padding: 3px 10px;
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
    cursor: pointer;
}

.ros-loc:hover { background: var(--interactive-hover); }

.ros-loc.is-active {
    border-color: var(--accent-main);
    color: var(--text-primary);
    background: var(--bg-muted);
}

/* ── the fifth utilization state ────────────────────────────────────────────
 *
 * ★ Neutral, NOT red. Being off is not a fault, and colouring it as one would
 *   put an alarm on every holiday in the studio. It reads as "absent" —
 *   which is exactly what it is. */
.ros-card--off   { border-left-color: var(--text-disabled); }
.ros-swatch--off { background: var(--text-disabled); }
.ros-badge--off  { background: var(--bg-muted); color: var(--text-disabled); }

/* ── the two extra figures under a badge ────────────────────────────────────
 *
 * Both are SECONDARY by construction: the badge is the verdict, and these are
 * the reasons it is what it is. If either ever reads as loud as the badge, the
 * row has two headlines and no answer. */
.ros-util-held,
.ros-util-pto {
    display: block;
    font-family: var(--font-family-mono);
    font-size: 10px;
    line-height: 1.5;
}

/* Amber: the same hue the held CELL fill uses, so the figure and the thing it
 * describes are recognisably one fact seen twice. */
.ros-util-held { color: var(--accent-caution); }
.ros-util-pto  { color: var(--text-disabled); }

/* ── ★★ THE CELL, AND THE TWO CHANNELS ─────────────────────────────────────
 *
 *     left border  →  the PROJECT   (identity)
 *     background   →  the KIND      (status)
 *
 * They were on a collision course: `.ros-cell-task` has always spent the
 * cell's only colour on the project swatch. Tinting the whole row by kind
 * would have taken that away — and the project is WHAT somebody is on, which
 * is the more important of the two facts. Splitting the channels lets a cell
 * say both at once, and it is fragment-specific for nothing, because every
 * booking is already its own element.
 *
 * ⚠ `.ros-kind--booked` has NO RULE AT ALL, on purpose. It is ~95% of the
 *   grid and it looks exactly as it always did. Re-teaching the normal case to
 *   make room for two exceptions is a bad trade, and an unstyled default also
 *   means a row whose kind fails to arrive degrades to the common case rather
 *   than to something that looks broken. */

/* Held — amber tint PLUS a hatch. ★ The hatch is the load-bearing half: it
 * reads as "provisional" without a legend, it survives colour-blindness, and
 * it still shows in the greyscale of a printed screenshot. Colour alone would
 * carry none of that. */
.ros-cell-row.ros-kind--held {
    background:
        repeating-linear-gradient(
            135deg,
            transparent 0 5px,
            rgba(245, 158, 11, .07) 5px 10px),
        rgba(245, 158, 11, .06);
}

.ros-cell-row.ros-kind--held:hover {
    background:
        repeating-linear-gradient(
            135deg,
            transparent 0 5px,
            rgba(245, 158, 11, .11) 5px 10px),
        var(--interactive-hover);
}

/* Time off — "grey the cell out" (jmeyers), which on a dark theme means
 * DESATURATE rather than lighten. It also carries no project border, because
 * it names no project. */
.ros-cell-row.ros-kind--pto {
    background: rgba(255, 255, 255, .03);
}

.ros-cell-row.ros-kind--pto .ros-cell-task {
    border-left-color: transparent;
    color: var(--text-muted);
    font-style: italic;
}

.ros-cell-row.ros-kind--pto .ros-cell-hours-read { color: var(--text-disabled); }

/* The short kind word beside the hours. Absent on Booked — see above. */
.ros-cell-kind {
    margin-left: 5px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    opacity: .85;
}

.ros-kind--held .ros-cell-kind { color: var(--accent-caution); }
.ros-kind--pto  .ros-cell-kind { color: var(--text-disabled); }

/* ── the kind picker in an open editor ──────────────────────────────────────
 *
 * ⚠ ON ITS OWN LINE, and that is forced rather than chosen. `.ros-cell-edit`
 *   is `1fr 52px 18px` inside a 171px column with a real native <select> in
 *   the first track; a fourth control there would squeeze the project picker
 *   below the width of its own longest option. The editor is taller for it,
 *   which is a cost to judge from the SCREENSHOT rather than from a rule. */
.ros-cell-edit-wrap {
    display: flex;
    flex-direction: column;
    gap: var(--ros-gap-tight);
}

.ros-cell-kinds {
    display: flex;
    gap: 0;                      /* welded: three parts of ONE control */
    border: 1px solid var(--border-subtle);
    border-radius: var(--border-radius-sm);
    overflow: hidden;
}

.ros-cell-kind-opt {
    flex: 1;
    min-width: 0;                /* so three of them fit a 171px column */
    padding: 2px 0;
    border: 0;
    border-right: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    font-size: 9px;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    cursor: pointer;
}

.ros-cell-kind-opt:last-child { border-right: 0; }
.ros-cell-kind-opt:hover      { background: var(--interactive-hover); color: var(--text-secondary); }

.ros-cell-kind-opt.is-active {
    background: var(--bg-muted);
    color: var(--text-primary);
}

.ros-cell-kind-opt[data-kind="Held"].is-active { color: var(--accent-caution); }
.ros-cell-kind-opt[data-kind="Pto"].is-active  { color: var(--text-secondary); }

/* A projectless editor keeps its THREE TRACKS rather than collapsing to two.
 * The disabled picker still occupies its column, so switching kind does not
 * make the row jump sideways under the producer's cursor mid-edit. */
.ros-cell-edit.is-projectless .ros-cell-project {
    opacity: .4;
    cursor: not-allowed;
}

/* ── radio groups (person form, bulk span) ──────────────────────────────────
 *
 * ★ Radios rather than a <select> (jmeyers): four mutually exclusive options
 *   that fit on one line. A dropdown would hide three of them behind a click
 *   to save no space, and seeing what the options ARE is most of this field's
 *   value on a roster where nobody has set one yet. */
.ros-radios {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ros-gap-related);
    margin-bottom: var(--ros-gap-related);
}

.ros-radio {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-secondary);
    font-size: var(--font-size-body-sm, 13px);
    cursor: pointer;
}

.ros-radio input { cursor: pointer; }

/* ── a person's name as a control in the by-project view ────────────────────
 *
 * It used to be a bare <span> there, so the two views disagreed about whether
 * a name was clickable at all. Same control, same affordance, both places. */
.ros-person--inline {
    padding: 0;
    border: 0;
    background: transparent;
    text-align: left;
    cursor: pointer;
}

.ros-person--inline:hover .ros-person-name { text-decoration: underline; }

/* ── the person detail dialog ───────────────────────────────────────────────
 *
 * Read-only. A name is something you click to LOOK at; editing is one button
 * further in, so a stray keystroke cannot change somebody's capacity — and
 * with it every utilization figure in their row. */
.ros-detail-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ros-gap-tight);
    margin-bottom: var(--ros-gap-section);
}

.ros-detail-tag {
    padding: 2px 8px;
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    color: var(--text-secondary);
    font-size: var(--font-size-body-xs);
}

.ros-detail-heading {
    margin-bottom: var(--ros-gap-related);
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.ros-detail-avail {
    margin-bottom: var(--ros-gap-section);
    padding: var(--ros-gap-related);
    border-left: 3px solid var(--accent-main);
    background: var(--bg-muted);
    border-radius: var(--border-radius-sm);
}

.ros-detail-line {
    color: var(--text-primary);
    font-size: var(--font-size-body-sm, 13px);
    line-height: 1.7;
}

.ros-detail-line.is-free  strong { color: var(--accent-confirm); }
.ros-detail-line.is-busy         { color: var(--text-secondary); }

/* ⚠ The horizon caveat, and it is never decoration. "Still committed on the
 * last day checked" is the difference between a date and a guess, and a
 * free-up date presented without it is a wrong answer wearing a precise
 * one's clothes. */
.ros-detail-caveat {
    color: var(--text-muted);
    font-size: var(--font-size-body-xs);
    font-style: italic;
}

.ros-detail-days {
    display: flex;
    flex-direction: column;
    gap: var(--ros-gap-related);
    max-height: 320px;
    overflow-y: auto;
}

.ros-detail-day {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: var(--ros-gap-related);
    align-items: start;
}

.ros-detail-date {
    color: var(--text-muted);
    font-family: var(--font-family-mono);
    font-size: var(--font-size-body-xs);
    padding-top: 3px;
}

.ros-detail-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ros-gap-tight);
}

/* The same two channels as the grid's cells, so a chip here and a cell there
 * are recognisably the same fact in two places. */
.ros-detail-chip {
    padding: 3px 8px;
    border-left: 3px solid var(--border-strong);
    border-radius: var(--border-radius-sm);
    background: var(--surface-secondary, rgba(255, 255, 255, .06));
    font-size: var(--font-size-body-xs);
}

.ros-detail-chip.ros-kind--held {
    border-left-color: var(--accent-caution);
    background:
        repeating-linear-gradient(
            135deg,
            transparent 0 5px,
            rgba(245, 158, 11, .07) 5px 10px),
        rgba(245, 158, 11, .06);
}

.ros-detail-chip.ros-kind--pto {
    border-left-color: var(--text-disabled);
    background: rgba(255, 255, 255, .03);
    font-style: italic;
}

.ros-detail-chip-what { display: block; color: var(--text-primary); }

.ros-detail-chip-hrs {
    display: block;
    color: var(--text-muted);
    font-family: var(--font-family-mono);
    font-size: 10px;
}

.ros-detail-empty {
    padding: var(--ros-gap-group) 0;
    color: var(--text-muted);
    font-size: var(--font-size-body-sm, 13px);
}
