/*schedule/static/schedule/style.css*/
:root {
    --navbar-height: 56px; /* tweak if your navbar is taller/shorter */
    --grid-header-group-height: 42px; /* default, JS will overwrite */
}

/* Make the page a full-height flex column so the grid can fill remaining space */
html,
body {
    height: 100%;
}

body {
    padding-top: var(--navbar-height);
    overflow: hidden;           /* stop the page itself from scrolling */
    display: flex;
    flex-direction: column;
}

/* saner layout math everywhere */
*, *::before, *::after {
    box-sizing: border-box;
}

/* ----------------------------- */
/* GLOBAL REUSABLE BEHAVIOUR     */
/* ----------------------------- */

.valid_drop_target_border {
    border-color: green !important;
    border-width: 4px !important;
}

/* Dropdowns scroll nicely if tall */
.dropdown-menu {
    overflow: hidden;
    overflow-y: auto;
    max-height: calc(100vh - 150px);
}

/* Pointer cursor helpers */
.jump-link,
th.clickable-header,
tr.clickablerow,
li.clickable_list_item {
    cursor: pointer;
}

.error {
    color: red;
}

.employee_cell {
    max-width: 140px;
}

/* Whiteboard title table widths */
.whiteboard-table-title {
    width: 130px;
}

.whiteboard-table-end-icons {
    width: 55px;
}

.whiteboard-table-critical-icon-cell {
    width: 20px;
}

/* Whiteboard table layout */
.whiteboard-table {
    table-layout: fixed;
    width: 100%;
}

/* prevent the UL from sitting too high in table cell */
dl,
ol,
ul {
    margin-top: 0;
    margin-bottom: 0;
}

/* Navbar toggler cleanup */
.navbar-toggler:focus {
    border: 0 !important;
    box-shadow: none !important;
}

.navbar-toggler {
    border: 0 !important;
}

/* Generic row wrapper used elsewhere (no vertical scroll here) */
.tbl-row {
    overflow-x: auto;
    overflow-y: visible;
    max-height: none;
}


/* ----------------------------- */
/* TABLE BASE STYLING            */
/* ----------------------------- */

table {
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
    border: 0.5px solid #64748b;
}

th,
td {
    border: 0.5px solid #64748b;
    padding: 10pt;
    text-align: center;
    background-color: #fff;
}

.table td.platoon_label {
    background-color: lightgreen;
}

.table td.divider_label {
    background-color: lightgrey;
}

/* Remove extra white band under any schedule table */
.schedule_table {
    margin-bottom: 0;
}

/* Grid view only: hold the wide layout so mobile pinch-zoom-out works.
   Narrow tables (individual view) share .schedule_table but not this class.
   Only on small/touch screens — on desktop the grid sizes to its content,
   so stations with few crews (e.g. 370) aren't stretched to 1400px. */
@media (max-width: 991.98px) {
    .schedule_table_wide {
        min-width: 1400px;
    }
}

/* Today's row (View > Outline today, on by default): an outline only, so every cell keeps its own colour.
   Drawn with inset shadows - borders would shift the sticky columns and the collapsed grid lines. */
#schedule_table.grid-today-on tbody tr.grid-today > td { box-shadow: inset 0 2px 0 #2563eb, inset 0 -2px 0 #2563eb; }
#schedule_table.grid-today-on tbody tr.grid-today > td:first-child { box-shadow: inset 0 2px 0 #2563eb, inset 0 -2px 0 #2563eb, inset 3px 0 0 #2563eb; color: #1e3a8a; font-weight: 700; }
#schedule_table.grid-today-on tbody tr.grid-today > td:last-child { box-shadow: inset 0 2px 0 #2563eb, inset 0 -2px 0 #2563eb, inset -3px 0 0 #2563eb; }

/* Schedule Validator "Highlight on grid" (docs/SCHEDULE_VALIDATOR.md): a cell holding a person with
   too little rest. Red when the other shift is at the same station, amber when it is elsewhere,
   and the person themself is marked inside the cell since only one seat usually has the problem.
   Inset shadows again - a border would reflow the sticky table. */
#schedule_table td.employee_cell.rest-gap-cell { box-shadow: inset 0 0 0 2px #e5484d; background: #fff7f7; }
#schedule_table td.employee_cell.rest-gap-cell.rest-gap-overlap { box-shadow: inset 0 0 0 2px #b91c1c; }
#schedule_table td.employee_cell.rest-gap-cell.rest-gap-cell-cross { box-shadow: inset 0 0 0 2px #c9822b; background: #fffaf0; }
#schedule_table td.employee_cell li.rest-gap-name { background: #fdecec; border: 1px solid #e5484d; border-radius: 6px; color: #8f1d1d; font-weight: 600; padding: 1px 5px; }
#schedule_table td.employee_cell li.rest-gap-name.rest-gap-cross { background: #fdf3d8; border-color: #c9822b; color: #7a4a00; }
/* Flow-sheet crew note on a draft crew cell (grid_view/_crew_cell_note.html): a small sticky
   note above the names, so it does not read as one of the tag badges below them. */
.crew-note-chip { display: block; max-width: 100%; margin-bottom: 3px; padding: 1px 5px; border-radius: 2px;
    background: #fff3a3; color: #5c4a00; box-shadow: 1px 1px 2px rgba(0, 0, 0, .25);
    font-size: .75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crew-note-chip svg { vertical-align: -.125em; }
.crew-note-chip.crew-note-critical { background: #ffd6d9; color: #842029; font-weight: 600; }
/* An existing note in the Edit Schedule / note review modals: shown first, in red, with a reminder. */
.crew-note-editor-review { background: #ffd6d9; border-color: #dc3545; }
.crew-note-editor-hint { color: #842029; }
.rest-gap-caption { display: block; font: 700 .66rem ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Grid zoom (View menu / two-finger pinch). Browsers will not zoom a page out below
   100%, and the grid scrolls inside its own container anyway, so the grid itself
   scales. `zoom` re-lays the table out, so sticky headers and columns keep working. */
.schedule_table_wide {
    zoom: var(--grid-zoom, 1);
}
.grid-zoom-value { min-width: 3.2rem; text-align: center; font-variant-numeric: tabular-nums; }
/* While the grid handles a pinch itself, the browser must not also zoom the page. */
#grid_scroll_container { touch-action: pan-x pan-y; }


/* ----------------------------- */
/* STICKY COLUMN                 */
/* ----------------------------- */

.schedule_table > tbody > tr > td:first-child {
    position: sticky;
    left: 0;
    z-index: 30;
    background-color: #f1f5f9;
}


/* ----------------------------- */
/* SCROLLING GRID CONTAINER      */
/* ----------------------------- */

/* Main content area (the thing that holds grid_page_wrapper) */
#main {
    flex: 1 1 auto;
    min-height: 0; /* allow children to scroll */
}

/* Root layout for schedule pages:
   - lives below the navbar
   - fills the remaining viewport space
   - lets any bars take natural height
   - grid fills the rest and scrolls
*/
.schedule-page-root,
.grid-page-wrapper {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0; /* so children can actually scroll */
}

  .individual-tbl-row {
    overflow-x: visible !important;
  }

#grid_scroll_container {
    /* No fixed height – it just fills remaining space in the wrapper */
    flex: 1 1 auto;
    min-height: 0;

    overflow-y: auto;
    overflow-x: auto;
}


/* ----------------------------- */
/* STICKY GRID HEADERS (JS-assisted) */
/* ----------------------------- */

/* First header row: group row */
#tableheader tr#group-row {
    position: sticky;
    top: 0;
    background: #f1f5f9;
    z-index: 40;
}

/* Second header row: column row
   - The top offset is dynamic: updated by JS based on the actual height of the group row. */
#tableheader tr#column-row {
    position: sticky;
    top: var(--grid-header-group-height, 42px); /* fallback to 42px */
    background: #f1f5f9;
    z-index: 41;
}



/* ----------------------------- */
/* STICKY UNPUBLISHED BARS       */
/* ----------------------------- */

/* Unpublished bar: just a normal block with some spacing handled by Bootstrap */
#unpublished_bar_region {
    position: static;      /* default */
    z-index: auto;         /* let it be part of normal stacking */
    margin: 0;             /* Bootstrap mb-3 / mb-2 do the rest */
}


/* ----------------------------- */
/* HTMX INDICATOR                */
/* ----------------------------- */

/* Hidden by default – takes no space */
.htmx-indicator {
    display: none;
}
#spinner {
    z-index: 2000;
}

/* Show when the request is active
   - either an ancestor has .htmx-request
   - or the indicator itself does (hx-indicator="#id")
*/
.htmx-request .htmx-indicator,
.htmx-indicator.htmx-request {
    display: inline-flex;
    align-items: center;
}

/* Custom Bootstrap-style badge colour */
.text-bg-purple {
    color: #fff !important;
    background-color: #6f42c1 !important;
}

/* ----------------------------- */
/* TOM SELECT + FORM-FLOATING    */
/* ----------------------------- */

/* Keep floating label in "floated up" position when Tom Select is active */
.form-floating > .ts-wrapper ~ label {
    transform: scale(.85) translateY(-.5rem) translateX(.15rem) !important;
    opacity: .65 !important;
    pointer-events: none;
}
.form-floating > .ts-wrapper .ts-control {
    padding-top: 1.625rem;
    padding-bottom: .625rem;
}
/* Tom Select dropdown must sit above sticky sections in modals */
.ts-wrapper .ts-dropdown {
    z-index: 3100;
}

/* ----------------------------- */
/* CREW EDITOR (action-first pilot) */
/* ----------------------------- */

.ce-crew-row,
.ce-action {
    border: 1px solid #e2e8f0;
    border-radius: 0.8rem;
    background: #fff;
    transition: border-color .12s, box-shadow .12s;
}
.ce-crew-row:hover,
.ce-action:hover {
    border-color: var(--app-primary);
    box-shadow: 0 6px 16px -8px rgba(var(--app-primary-rgb), .30);
}
.ce-add-crew {
    border: 1.5px dashed #cbd5e1;
    border-radius: 0.8rem;
    background: #f8fafc;
}
.ce-now {
    border: 1px solid #e2e8f0;
    border-radius: 0.85rem;
    padding: 0.75rem 0.9rem;
    background: #f8fafc;
}

/* effective-date band — the "when" is the star */
.ce-when {
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 0.8rem;
}
.ce-when-label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: #b45309;
    font-weight: 700;
}
.ce-when-note {
    font-size: .8rem;
    color: #b45309;
}

/* scheduled (future) visibility flip shown on result rows / now panel */
.ce-pending {
    font-size: .72rem;
    font-weight: 600;
    color: #b45309;
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 100px;
    padding: 1px 8px;
    white-space: nowrap;
}

/* ---- hub: Now panel ---- */
.ce-now {
    border: 1px solid #e2e8f0;
    border-radius: 0.85rem;
    padding: 12px 14px;
    background: #f8fafc;
}
.ce-now-title {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: #94a3b8;
    font-weight: 700;
    margin-bottom: 9px;
}
.ce-now-row {
    display: flex;
    gap: 10px;
    align-items: baseline;
    padding: 3px 0;
}
.ce-now-row .k {
    flex: 0 0 104px;
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #64748b;
    font-weight: 700;
}
.ce-now-row .v {
    font-size: .86rem;
    display: flex;
    gap: 6px;
    align-items: baseline;
    flex-wrap: wrap;
    font-variant-numeric: tabular-nums;
}
/* Stacked value rows (Access, Dropdowns, Roles, Scopes): the value column is a
   flex row by default, so entries ran together as "280 Published viewer 283
   Published viewer". Stack them and give the label a fixed column so the detail
   on the right lines up down the card. */
.ce-now-row .v.v-stack {
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
    /* Fill the rest of the row. Without this .v sizes to content and the detail
       column gets squeezed, wrapping "Acting supervisor" onto two lines and
       "since Jan 2026" onto three. */
    flex: 1 1 auto;
    min-width: 0;
}
.ce-now-line {
    display: flex;
    gap: 12px;
    align-items: baseline;
    width: 100%;
}
.ce-now-line .st {
    flex: 0 0 116px;
    font-weight: 600;
    color: #0f172a;
    overflow-wrap: anywhere;
}
/* The detail sits on one line where it fits; it may wrap on a phone, but it is
   no longer forced to by a column that is narrower than its content. */
.ce-now-line .ce-chg-sub {
    flex: 1 1 auto;
    min-width: 0;
}
.ce-now-line .st-sub { color: #64748b; }
.ce-now-row .v .sep,
.ce-chg-what .sep { color: #cbd5e1; }
/* A pill that genuinely leads the value column reads as indented, because its
   own 8px of padding pushes it right of every plain-text value above it. Opt in
   with .lead — :first-child cannot be used, since a bare text node ("Grid ")
   is not an element, so a pill after it still matched and was dragged back over
   the preceding word. No template needs it today; the class is kept so the
   de-indent is available without reintroducing that bug. */
.ce-now-row .v > .ce-pill.lead { margin-left: -8px; }
.ce-now-since {
    font-size: .76rem;
    color: #64748b;
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px dashed #e2e8f0;
}

/* ---- hub: section + year headers ---- */
.ce-sec-label {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: #94a3b8;
    font-weight: 700;
    margin: 18px 0 10px;
}
.ce-year {
    font-size: .7rem;
    font-weight: 700;
    color: #94a3b8;
    letter-spacing: .04em;
    margin: 12px 0 7px;
}

/* ---- hub: change rows ---- */
.ce-chg {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 0.8rem;
    margin-bottom: 7px;
    background: #fff;
    transition: border-color .15s, box-shadow .15s;
}
.ce-chg:hover {
    border-color: #cbd5e1;
    box-shadow: 0 4px 14px -6px rgba(15, 23, 42, .12);
}
.ce-chg.past { background: #f8fafc; border-color: #eef2f6; }
.ce-chg-date {
    font-size: .78rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    width: 72px;
    flex: 0 0 auto;
}
.ce-chg.past .ce-chg-date { color: #64748b; font-weight: 600; }
.ce-chg-what { font-size: .88rem; flex: 1; min-width: 0; }
.ce-chg-sub { font-size: .78rem; color: #64748b; }
.ce-chg-acts { display: flex; gap: 6px; flex: 0 0 auto; }
/* Schedule-access rows: station name reads as the row's subject, the select sits
   right-aligned. Wider than .ce-chg-date because station labels are words
   ("region-2-support-pool"), not dates. */
.ce-access-station {
    font-size: .88rem;
    font-weight: 600;
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* ---- hub: pills ---- */
.ce-pill {
    font-size: .68rem;
    font-weight: 700;
    padding: 1px 8px;
    border-radius: 100px;
    white-space: nowrap;
}
.ce-pill.hide { background: #f1f5f9; color: #475569; }
.ce-pill.show { background: #ecfdf5; color: #047857; }
.ce-pill.cfg  { background: #fffbeb; color: #b45309; border: 1px solid #fde68a; }

/* ---- hub: action icon chips ---- */
.ce-action-ic {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: .6rem;
    display: grid;
    place-items: center;
    background: var(--app-primary-soft, #edf3fa);
    color: var(--app-primary, #4175c8);
}

/* ---- hub: history + add-grid ---- */
.ce-history summary {
    cursor: pointer;
    font-size: .82rem;
    color: var(--app-primary);
    font-weight: 600;
    list-style: none;
    padding: 6px 0;
}
.ce-history summary::-webkit-details-marker { display: none; }
.ce-history summary::before { content: "▸ "; font-size: .7rem; }
.ce-history[open] summary::before { content: "▾ "; }
.ce-add-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}
@media (max-width: 520px) { .ce-add-grid { grid-template-columns: 1fr; } }

/* ---- create form: sharp shift cards + fields ---- */
.ce-shift-field { display: flex; flex-direction: column; }
.ce-shift-field label {
    font-size: .66rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #616a72;
    font-weight: 700;
    margin-bottom: 3px;
}
.ce-shift-card {
    display: flex;
    gap: 8px;
    align-items: flex-end;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: .8rem;
    padding: 8px 10px;
    margin-bottom: 8px;
}
.ce-shift-card .ce-shift-name { width: 130px; }
.ce-shift-card .ce-shift-label { width: 104px; }
.ce-shift-card input[type="time"] { width: 132px; }

/* roomier modal for the busy create form so time inputs aren't clipped */
.modal-dialog.modal-ce-wide { max-width: 640px; }
.ce-shift-remove {
    border: 0;
    background: transparent;
    color: #adb5bd;
    font-size: 1.3rem;
    line-height: 1;
    padding: 0 2px 4px;
    cursor: pointer;
    margin-left: auto;
}
.ce-shift-remove:hover { color: #dc3545; }
@media (max-width: 480px) { .ce-shift-card { flex-wrap: wrap; } }

/* timeline-split preview */
.ce-timeline {
    display: flex;
    border: 1px solid #e2e8f0;
    border-radius: 0.8rem;
    overflow: hidden;
}
.ce-seg {
    flex: 1;
    padding: 0.6rem 0.8rem;
    font-size: .85rem;
    font-variant-numeric: tabular-nums;
}
.ce-seg.before {
    background: #f8fafc;
    color: #64748b;
}
.ce-seg.after {
    background: #edf3fa;
}
.ce-seg-cap {
    font-size: .66rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 700;
    opacity: .8;
    margin-bottom: .15rem;
}
.ce-seg.after .ce-seg-cap {
    color: var(--app-primary);
    opacity: 1;
}
@media (max-width: 440px) {
    .ce-timeline {
        flex-direction: column;
    }
}

/* =========================================================
   APP THEME — indigo/slate, ported from the Tailwind prototype
   Loads after bootstrap.min.css, so plain selectors override.
   Semantic colors (bg-warning, bg-success, badge colors in the
   grid and TagType.bootstrap_color_class) are left untouched —
   only app chrome is themed here.
   ========================================================= */

:root {
    --app-primary: #4175c8;
    --app-primary-hover: #3562a8;
    --app-primary-soft: #edf3fa;
    --app-primary-rgb: 65, 117, 200;
    --app-ink: #0f172a;
    --app-muted: #64748b;
    --app-faint: #94a3b8;
    --app-border: #e2e8f0;
    --app-muted-bg: #f8fafc;
    --app-slate-soft: #f1f5f9;
    --app-slate-ink: #475569;
    --app-bg: #eef2f7;

    /* retune Bootstrap's own tokens */
    --bs-body-color: var(--app-ink);
    --bs-border-color: var(--app-border);
    --bs-link-color: var(--app-primary);
    --bs-link-hover-color: var(--app-primary-hover);
    --bs-link-color-rgb: var(--app-primary-rgb);
    --bs-link-hover-color-rgb: 53, 98, 168;
    --bs-focus-ring-color: rgba(var(--app-primary-rgb), .25);
}

/* ---- page ground: soft slate with faint indigo/cyan washes ---- */
body {
    color: var(--app-ink);
    background:
        radial-gradient(60rem 30rem at 80% -10%, #e0e7ff55, transparent),
        radial-gradient(50rem 30rem at -10% 10%, #cffafe44, transparent),
        var(--app-bg);
}

/* ---- navbar: clean white with hairline bottom border ----
   NOTE: no backdrop-filter here — the offcanvas panels are children of
   the navbar, and backdrop-filter creates a containing block that
   breaks their position:fixed. */
/* Tinted command bar — same indigo/cyan wash as the page ground, but denser, with a primary accent edge */
.navbar.bg-light {
    background:
        linear-gradient(90deg, #e0e7ff99, #cffafe66 55%, #e0e7ff77),
        #f8fafc !important;
    border-bottom: 2px solid rgba(var(--app-primary-rgb), .55);
    box-shadow: 0 1px 10px rgba(15, 23, 42, .08);
}
.navbar .navbar-toggler {
    color: var(--app-slate-ink);
    border-radius: .55rem;
    padding: .35rem .5rem;
}
.navbar .navbar-toggler:hover {
    background: #ffffffcc;
    box-shadow: inset 0 0 0 1px var(--app-border);
}
.navbar .navbar-brand, .navbar #month_year_header, .navbar h4, .navbar .navbar-text {
    font-weight: 650;
    letter-spacing: -.01em;
    color: var(--app-ink);
}
.navbar .nav-link.dropdown-toggle {
    font-weight: 600;
    color: var(--app-slate-ink);
    border-radius: .55rem;
    padding: .3rem .7rem !important;
}
.navbar .nav-link.dropdown-toggle:hover,
.navbar .nav-link.dropdown-toggle.show {
    background: #ffffffcc;
    color: var(--app-ink);
    box-shadow: inset 0 0 0 1px var(--app-border);
}

/* ---- buttons ---- */
.btn {
    --bs-btn-border-radius: .65rem;
    font-weight: 600;
}
.btn-sm { --bs-btn-border-radius: .55rem; }
.btn-primary {
    --bs-btn-bg: var(--app-primary);
    --bs-btn-border-color: var(--app-primary);
    --bs-btn-hover-bg: var(--app-primary-hover);
    --bs-btn-hover-border-color: var(--app-primary-hover);
    --bs-btn-active-bg: var(--app-primary-hover);
    --bs-btn-active-border-color: var(--app-primary-hover);
    --bs-btn-disabled-bg: var(--app-primary);
    --bs-btn-disabled-border-color: var(--app-primary);
    --bs-btn-focus-shadow-rgb: var(--app-primary-rgb);
    box-shadow: 0 1px 2px rgba(var(--app-primary-rgb), .35);
}
/* secondary = quiet soft-slate, like the prototype's ghost/outline buttons */
.btn-secondary {
    --bs-btn-bg: var(--app-slate-soft);
    --bs-btn-border-color: var(--app-border);
    --bs-btn-color: var(--app-slate-ink);
    --bs-btn-hover-bg: #e2e8f0;
    --bs-btn-hover-border-color: #cbd5e1;
    --bs-btn-hover-color: var(--app-ink);
    --bs-btn-active-bg: #e2e8f0;
    --bs-btn-active-border-color: #cbd5e1;
    --bs-btn-active-color: var(--app-ink);
    --bs-btn-disabled-bg: var(--app-slate-soft);
    --bs-btn-disabled-border-color: var(--app-border);
    --bs-btn-disabled-color: var(--app-faint);
    --bs-btn-focus-shadow-rgb: 148, 163, 184;
}
.btn-outline-primary {
    --bs-btn-color: var(--app-primary);
    --bs-btn-border-color: #c9d9ef;
    --bs-btn-hover-bg: var(--app-primary-soft);
    --bs-btn-hover-border-color: var(--app-primary);
    --bs-btn-hover-color: var(--app-primary-hover);
    --bs-btn-active-bg: var(--app-primary-soft);
    --bs-btn-active-border-color: var(--app-primary);
    --bs-btn-active-color: var(--app-primary-hover);
    --bs-btn-focus-shadow-rgb: var(--app-primary-rgb);
}
.btn-outline-secondary {
    --bs-btn-color: var(--app-slate-ink);
    --bs-btn-border-color: var(--app-border);
    --bs-btn-hover-bg: var(--app-slate-soft);
    --bs-btn-hover-border-color: #cbd5e1;
    --bs-btn-hover-color: var(--app-ink);
    --bs-btn-active-bg: var(--app-slate-soft);
    --bs-btn-active-border-color: #cbd5e1;
    --bs-btn-active-color: var(--app-ink);
    --bs-btn-focus-shadow-rgb: 148, 163, 184;
}

/* ---- forms: rounded fields, indigo focus ring ---- */
.form-control,
.form-select {
    border-radius: .65rem;
    border-color: var(--app-border);
}
.form-control:focus,
.form-select:focus {
    border-color: #a9c4e8;
    box-shadow: 0 0 0 .25rem rgba(var(--app-primary-rgb), .15);
}
.form-check-input:checked {
    background-color: var(--app-primary);
    border-color: var(--app-primary);
}
.form-check-input:focus {
    border-color: #a9c4e8;
    box-shadow: 0 0 0 .25rem rgba(var(--app-primary-rgb), .15);
}
.form-floating > .form-control,
.form-floating > .form-select {
    border-radius: .65rem;
}

/* ---- modals: the prototype card ---- */
.modal-content {
    border-radius: 1rem;
    border: 1px solid var(--app-border);
    box-shadow: 0 20px 45px -15px rgba(15, 23, 42, .25), 0 2px 6px rgba(15, 23, 42, .05);
}
.modal-header {
    border-bottom-color: var(--app-border);
    padding: 1rem 1.375rem .875rem;
}
.modal-title {
    font-size: 1.06rem;
    font-weight: 650;
    letter-spacing: -.01em;
}
.modal-footer {
    border-top-color: var(--app-border);
    background: linear-gradient(#fff, #fcfdfe);
    border-bottom-left-radius: 1rem;
    border-bottom-right-radius: 1rem;
}
.modal-backdrop {
    --bs-backdrop-bg: #0f172a;
    --bs-backdrop-opacity: .45;
}
/* Safari flicker fix: the grid uses position:sticky wall-to-wall, and Safari
   repaints those sticky layers while a translucent backdrop fades in over them.
   Make the backdrop appear instantly and fairly opaque so the repaint is masked. */
.modal-backdrop.fade { transition: none !important; }
.modal-backdrop { --bs-backdrop-opacity: .75 !important; }
/* Open with a short opacity fade only — no translate slide. Kept at 0.25s: a
   slower fade leaves the panel semi-transparent longer, letting the Safari
   grid-repaint show through the half-faded dialog. */
.modal.fade .modal-dialog { transform: none !important; }
.modal.fade { transition: opacity 0.25s ease-out !important; }
/* Kill the static-backdrop "bounce" (a scale(1.02) animation Bootstrap fires on
   open) which moved the centered dialog up ~8px then back — the up/down jitter.
   The static backdrop still can't be click-dismissed; only the shake goes. */
.modal-static .modal-dialog { animation: none !important; transform: none !important; }

/* ---- dropdown menus ---- */
.dropdown-menu {
    --bs-dropdown-border-radius: .8rem;
    --bs-dropdown-border-color: var(--app-border);
    --bs-dropdown-link-hover-bg: var(--app-slate-soft);
    --bs-dropdown-link-active-bg: var(--app-primary);
    box-shadow: 0 12px 30px -12px rgba(15, 23, 42, .25);
    padding: .4rem;
}
.dropdown-item { border-radius: .5rem; }

/* ---- offcanvas + toasts ---- */
.offcanvas {
    border-color: var(--app-border);
    box-shadow: 0 20px 45px -15px rgba(15, 23, 42, .25);
}
.offcanvas-header {
    border-bottom: 1px solid var(--app-border);
}
.offcanvas-title {
    font-weight: 650;
    letter-spacing: -.01em;
}
.offcanvas hr {
    border-color: var(--app-border);
    opacity: 1;
    margin: .55rem 0;
}
.offcanvas .nav-link.jump-link {
    font-size: .92rem;
    font-weight: 500;
    color: var(--app-ink);
    text-decoration: none;
}
.offcanvas .nav-link.jump-link:hover {
    color: var(--app-primary-hover);
}
.toast {
    border-radius: .8rem;
    border: 1px solid var(--app-border);
    box-shadow: 0 12px 30px -12px rgba(15, 23, 42, .3);
}
.toast-header {
    border-top-left-radius: .8rem;
    border-top-right-radius: .8rem;
    border-bottom-color: var(--app-border);
}

/* ---- badges: pill shape, calmer weight ---- */
.badge {
    border-radius: 9999px;
    font-weight: 650;
    padding: .3em .7em;
}

/* ---- alerts ---- */
.alert { border-radius: .8rem; }

/* ---- offcanvas nav links: rounded hover rows ---- */
.offcanvas .nav-link.jump-link {
    border-radius: .5rem;
    padding: .35rem .6rem;
}
.offcanvas .nav-link.jump-link:hover {
    background: var(--app-slate-soft);
}

/* ---- offcanvas: section labels, month pager, station chips, icon chips ---- */
.oc-sec {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--app-faint);
    font-weight: 700;
    margin: 14px 6px 4px;
    list-style: none;
}
.oc-pager {
    display: flex;
    gap: 8px;
    margin: 2px 4px 6px;
}
.oc-pg {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 7px 0;
    border: 1px solid var(--app-border);
    border-radius: .65rem;
    background: #fff;
    font-size: .85rem;
    font-weight: 600;
    color: var(--app-ink);
    cursor: pointer;
    white-space: nowrap;
}
.oc-pg:hover {
    border-color: #cbd5e1;
    background: var(--app-muted-bg);
}
.oc-pg-mid {
    flex: 1.5;
    color: var(--app-primary-hover);
}
.oc-chips {
    display: flex;
    gap: 6px;
    margin: 2px 4px 4px;
    flex-wrap: wrap;
}
.oc-chip {
    font-size: .8rem;
    font-weight: 650;
    padding: 4px 13px;
    border-radius: 999px;
    cursor: pointer;
    border: 1px solid var(--app-border);
    background: #fff;
    color: var(--app-slate-ink);
}
.oc-chip:hover {
    border-color: #cbd5e1;
}
.oc-chip.oc-chip-on {
    background: var(--app-primary);
    border-color: var(--app-primary);
    color: #fff;
    box-shadow: 0 1px 2px rgba(var(--app-primary-rgb), .4);
}
.oc-ic {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: .5rem;
    display: grid;
    place-items: center;
    background: var(--app-primary-soft);
    color: var(--app-primary);
}
.oc-ic svg {
    width: 14px;
    height: 14px;
}
.oc-sub {
    font-size: .78rem;
    color: var(--app-faint);
    font-weight: 600;
}
.oc-ic-slate {
    background: var(--app-slate-soft);
    color: var(--app-slate-ink);
}
.oc-ic-danger {
    background: #fef2f2;
    color: #dc2626;
}
.oc-beta {
    font-size: .6rem;
    font-weight: 700;
    letter-spacing: .05em;
    color: #b45309;
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 999px;
    padding: 1px 7px;
}
.oc-foot {
    border-top: 1px solid var(--app-border);
    margin: 10px -16px -16px;
    padding: 10px 16px 14px;
    background: linear-gradient(#fff, #fcfdfe);
}
.oc-foot .nav-link.jump-link {
    border-radius: .5rem;
    padding: .35rem .6rem;
}
.oc-foot .nav-link.jump-link:hover {
    background: var(--app-slate-soft);
}

/* ---- MSOS jump bar: sticky section pills + station chips ---- */
.msos-jumpbar {
    position: sticky;
    top: 0;
    z-index: 600;
    margin: 0 -0.25rem .35rem;
    padding: .5rem .25rem;
    background: rgba(238, 242, 247, .88);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--app-border);
}
.msos-jumpbar-label {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 700;
    color: var(--app-faint);
    margin-right: .15rem;
}
.msos-jumpbar-in {
    display: flex;
    align-items: center;
    gap: .45rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
}
.msos-jumpbar-in::-webkit-scrollbar { display: none; }
.msos-jump-pill, .msos-jump-chip, .msos-jumpbar-label, .msos-jumpbar-div { flex: 0 0 auto; }
.msos-jump-pill {
    border: 1px solid var(--app-border);
    border-radius: 999px;
    padding: .32rem .85rem;
    font-size: .8rem;
    font-weight: 650;
    background: #fff;
    color: var(--app-slate-ink);
}
.msos-jump-pill:hover { background: var(--app-slate-soft); }
.msos-jump-pill.active {
    background: var(--app-ink);
    border-color: var(--app-ink);
    color: #fff;
}
.msos-jump-chip {
    border: 1px solid var(--app-border);
    border-radius: 999px;
    padding: .28rem .6rem;
    font-size: .74rem;
    font-weight: 600;
    background: var(--app-muted-bg);
    color: var(--app-muted);
}
.msos-jump-chip:hover { background: #fff; color: var(--app-ink); }
.msos-jump-chip.active {
    background: var(--app-ink);
    border-color: var(--app-ink);
    color: #fff;
}
.msos-jumpbar-div { width: 1px; height: 20px; background: var(--app-border); margin: 0 .3rem; }
.msos-jump-pill:focus, .msos-jump-chip:focus { outline: none; }
.msos-jump-pill:focus-visible, .msos-jump-chip:focus-visible {
    outline: 2px solid rgba(var(--app-primary-rgb), .5);
    outline-offset: 1px;
}
.msos-sec-title[id], .msos-crew-table[id] {
    scroll-margin-top: 58px;
}

/* ---- Crew chooser: hidden crews collapsed until toggled ---- */
#ce_crew_list .ce-crew-row-hidden { display: none !important; }
#ce_crew_list.ce-show-hidden .ce-crew-row-hidden { display: flex !important; }

/* ---- Grid right-click context menu ---- */
.ctx-menu {
    position: fixed;
    z-index: 3000;
    min-width: 190px;
    background: #fff;
    border: 1px solid var(--app-border);
    border-radius: .6rem;
    box-shadow: 0 8px 24px rgba(15, 23, 42, .18);
    padding: .3rem;
    font-size: .85rem;
}
.ctx-item {
    display: flex;
    align-items: center;
    gap: .4rem;
    width: 100%;
    border: 0;
    background: transparent;
    text-align: left;
    padding: .4rem .55rem;
    border-radius: .4rem;
    color: var(--app-ink);
    position: relative;
}
.ctx-item:hover { background: var(--app-slate-soft); }
.ctx-sep { height: 1px; background: var(--app-border); margin: .3rem .2rem; }
.ctx-empty { padding: .4rem .55rem; color: var(--app-faint); font-size: .8rem; }
.ctx-has-sub::after { content: ""; margin-left: auto; }
.ctx-sub {
    display: none;
    position: absolute;
    left: 100%;
    top: 0;
    min-width: 170px;
    background: #fff;
    border: 1px solid var(--app-border);
    border-radius: .6rem;
    box-shadow: 0 8px 24px rgba(15, 23, 42, .18);
    padding: .3rem;
}
.ctx-has-sub:hover .ctx-sub { display: block; }
.ctx-tag { display: flex; width: 100%; border: 0; background: transparent; padding: .35rem .5rem; border-radius: .4rem; }
.ctx-tag:hover { background: var(--app-slate-soft); }

/* ---- Availability: holiday-recall marker, front-loaded so long names can't hide it ---- */
.av-hr {
    font-weight: 700;
    color: #b45309;
}

/* ---- People search: station filter pills ---- */
.pe-station-bar {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}
.pe-station-bar::-webkit-scrollbar { display: none; }
.pe-station-label {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 700;
    color: var(--app-faint);
    flex: 0 0 auto;
}
.pe-station-pill {
    border: 1px solid var(--app-border);
    border-radius: 999px;
    padding: .24rem .6rem;
    font-size: .74rem;
    font-weight: 600;
    background: var(--app-muted-bg);
    color: var(--app-muted);
    flex: 0 0 auto;
}
.pe-station-pill:hover { background: #fff; color: var(--app-ink); }
.pe-station-pill.active {
    background: var(--app-ink);
    border-color: var(--app-ink);
    color: #fff;
}
.pe-station-pill:focus { outline: none; }
.pe-station-pill:focus-visible { outline: 2px solid rgba(var(--app-primary-rgb), .5); outline-offset: 1px; }

/* ---- MSOS jump bar: phone station select ---- */
.msos-jump-select {
    border: 1px solid var(--app-border);
    border-radius: 999px;
    padding: .3rem 1.6rem .3rem .7rem;
    font-size: .78rem;
    font-weight: 600;
    color: var(--app-slate-ink);
    background-color: #fff;
    flex: 0 0 auto;
    max-width: 8.5rem;
}

/* ---- MSOS times cell: start over end, two lines, at every width ---- */
.msos-times { font-variant-numeric: tabular-nums; white-space: nowrap; text-align: center; }
.msos-times .msos-time { display: block; }
.msos-times .msos-time-sep { display: none; }

/* ---- MSOS "what changed" notice (after a quiet refresh) ---- */
.msos-changes { position: fixed; left: 50%; bottom: 1rem; transform: translateX(-50%); z-index: 1040; width: min(34rem, calc(100vw - 1.5rem)); background: #1f2937; color: #fff; border-radius: .9rem; box-shadow: 0 8px 24px rgba(15, 23, 42, .3); padding: .15rem .25rem; display: grid; grid-template-columns: 1fr auto; align-items: center; }
.msos-changes button { border: 0; background: none; color: inherit; text-align: left; }
.msos-changes-summary { padding: .55rem .75rem; font-size: .9rem; font-weight: 600; }
.msos-changes-summary::after { content: " \25be"; opacity: .7; }
/* A new change pulses three times, then sits still in its colour. Nothing blinks for long. */
@keyframes msos-pulse { 0%, 100% { filter: none; } 50% { filter: brightness(.86) saturate(1.6); } }
.msos-crew-table tr.msos-pulse > td, #whiteboard tr.msos-pulse > td { animation: msos-pulse .9s ease-in-out 3; }
@media (prefers-reduced-motion: reduce) { .msos-crew-table tr.msos-pulse > td, #whiteboard tr.msos-pulse > td { animation: none; } }
.msos-changes-close { font-size: 1.4rem; line-height: 1; padding: .2rem .7rem; opacity: .8; }
.msos-changes-list { grid-column: 1 / -1; margin: 0; max-height: 40vh; overflow-y: auto; border-top: 1px solid rgba(255, 255, 255, .15); }
.msos-changes-list button { width: 100%; padding: .45rem .75rem; font-size: .85rem; }
.msos-changes-list small { opacity: .6; }
.msos-crew-table tr.msos-changed > td, #whiteboard tr.msos-changed > td { background-color: #fff4d6 !important; }
.msos-crew-table tr.msos-changed > td:first-child { box-shadow: inset 4px 0 0 #f59e0b; }
.msos-crew-table tr.msos-short > td { background-color: #fde2e1 !important; }
.msos-crew-table tr.msos-short > td:first-child { box-shadow: inset 4px 0 0 #dc2626; }
.msos-crew-table tr.msos-whole > td { background-color: #dcf5e3 !important; }
.msos-crew-table tr.msos-whole > td:first-child { box-shadow: inset 4px 0 0 #16a34a; }
.msos-jump-pill[data-msos-changes]::after { content: attr(data-msos-changes); display: inline-block; margin-left: .4rem; min-width: 1.25rem; padding: 0 .3rem; border-radius: 999px; background: #f59e0b; color: #1f2937; font-size: .72rem; font-weight: 700; line-height: 1.25rem; text-align: center; }
.msos-changes-list button[data-msos-mood="short"] { box-shadow: inset 4px 0 0 #f87171; }
.msos-changes-list button[data-msos-mood="whole"] { box-shadow: inset 4px 0 0 #4ade80; }

/* ---- MSOS flow sheets: section bands + station cards ---- */
.msos-sec-title {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--app-slate-ink);
    font-weight: 700;
    margin: 1.3rem 0 .6rem .15rem;
    display: flex;
    align-items: center;
    gap: .6rem;
}
.msos-sec-title::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--app-border);
}
.msos-card {
    background: #fff;
    border: 1px solid var(--app-border);
    border-radius: .85rem;
    margin-bottom: .9rem;
    overflow: hidden;
}
.msos-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .55rem .95rem;
    border-bottom: 1px solid var(--app-border);
    background: var(--app-muted-bg);
}
.msos-card-station {
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--app-ink);
}
.msos-card-meta {
    font-size: .78rem;
    color: var(--app-muted);
    white-space: nowrap;
}
.msos-table { margin-bottom: 0; border: 0; }
.msos-table > :not(caption) > * > * {
    border: 0;
    border-bottom: 1px solid #d7dee8;
    padding: .6rem .95rem;
}
.msos-table tr:last-child > * { border-bottom: 0; }
.msos-table .fst-italic {
    font-size: .85rem;
    color: var(--app-muted);
}
.msos-table tr.clickablerow:hover {
    background: var(--app-slate-soft);
    cursor: pointer;
}

/* Flow-sheet crew tables: a real grid at every width - crew, times, people.
   It reads like the sheet it replaced: ruled cells, striped rows, times stacked. */
.msos-crew-table { border-collapse: collapse; }
.msos-crew-table > :not(caption) > * > td { border: 1px solid #c9d2de; vertical-align: middle; }
.msos-crew-table > :not(caption) > * > td:first-child { border-left: 0; }
.msos-crew-table > :not(caption) > * > td:last-child { border-right: 0; }
.msos-crew-table tr:first-child > td { border-top: 0; }
.msos-crew-table tr:last-child > td { border-bottom: 0; }
.msos-crew-table tbody tr:nth-child(odd) > td, .msos-crew-table > tr:nth-child(odd) > td { background-color: #f3f5f8; }
.msos-crew-table td ul { margin: 0; }
.msos-crew-table > :not(caption) > * > td:nth-child(1) { width: 150px; text-align: center; }
.msos-crew-table > :not(caption) > * > td:nth-child(2) { width: 90px; }
.msos-crew-table > :not(caption) > * > td:nth-child(3) { width: auto; }
@media (max-width: 768px) {
    .msos-table.msos-crew-table > :not(caption) > * > td { padding: .5rem .45rem; }
    .msos-crew-table > :not(caption) > * > td:nth-child(1) { width: 5.6rem; }
    .msos-crew-table > :not(caption) > * > td:nth-child(2) { width: 3.9rem; }
    .msos-crew-table > :not(caption) > * > td:nth-child(3) { padding-left: .6rem; }
    .msos-crew-table td:nth-child(3) li { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem; margin: 0 0 .15rem; }
}

/* ---- individual schedule: card table + calendar cells ---- */
.ind-emp {
    background: #fff;
    border: 1px solid var(--app-border);
    border-radius: .65rem;
    padding: .32rem .3rem .32rem .65rem;
    gap: .45rem;
    box-shadow: 0 1px 2px rgba(15, 23, 42, .05);
}
.ind-emp-ic { color: var(--app-faint); display: flex; }
.ind-emp select:not(.tomselected), .ind-emp .ts-wrapper.form-select {
    border: 0;
    background-color: transparent;
    font-weight: 600;
    color: var(--app-ink);
    max-width: 260px;
    min-width: 180px;
    padding: 0 1.5rem 0 0;
    box-shadow: none;
}
.ind-emp .ts-control {
    border: 0;
    background: transparent;
    box-shadow: none;
    padding: .15rem .2rem;
    font-weight: 600;
    color: var(--app-ink);
}
.ind-emp select:focus, .ind-emp .ts-wrapper.focus .ts-control { outline: none; box-shadow: none; }
#individual_sticky_controls .btn-group {
    border-radius: .65rem;
    overflow: hidden;
}
#individual_sticky_controls .btn-group .btn {
    padding: .42rem .9rem;
    font-weight: 600;
}
.ind-list-card {
    width: fit-content;
    min-width: min(320px, 94vw);
    max-width: 94vw;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .07);
    overflow: visible;
}
.ind-card-head {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .55rem .7rem;
    background: rgba(255, 255, 255, .92);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border-bottom: 1px solid var(--app-border);
    border-radius: .85rem .85rem 0 0;
}
.ind-card-head .ind-emp {
    border: 0;
    box-shadow: none;
    padding-left: .15rem;
}
.ind-card-head .btn-group .btn {
    padding: .3rem .7rem;
    font-weight: 600;
}
#schedule_table tbody tr:last-child > td:first-child { border-bottom-left-radius: .85rem; }
#schedule_table tbody tr:last-child > td:last-child { border-bottom-right-radius: .85rem; }
.ind-cal-controls {
    position: sticky;
    top: 0;
    z-index: 500;
    background: rgba(238, 242, 247, .82);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
#schedule_table td { vertical-align: top; }
.ind-day {
    font-weight: 700;
    font-size: 1.02rem;
    font-variant-numeric: tabular-nums;
    color: var(--app-ink);
    width: 2.9rem;
    text-align: right !important;
}
.ind-dow {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--app-muted);
    font-weight: 700;
    width: 2.6rem;
    padding-top: 1.02rem !important;
}
#schedule_table tr.ind-weekend .ind-day,
#schedule_table tr.ind-weekend .ind-dow { color: var(--app-faint); }
#schedule_table tr.ind-today > td:first-child { box-shadow: inset 3px 0 0 var(--app-primary); }
#schedule_table tr.ind-today .ind-day,
#schedule_table tr.ind-today .ind-dow { color: var(--app-primary); }
.ind-body { min-width: 170px; }
.ind-body li.fw-bold { color: var(--app-ink); }
.ind-flag {
    display: inline-block;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .02em;
    padding: .16rem .6rem;
    border-radius: 999px;
}
.ind-flag-holiday { background: #fef3c7; color: #92400e; }
.ind-flag-leave { background: #ede9fe; color: #5b21b6; }
.ind-cal-cell {
    background: #fff;
    border-color: var(--app-border) !important;
    border-radius: .65rem !important;
}
.ind-cal-blank {
    background: transparent;
    border-style: dashed !important;
}
.ind-cal-cell .fst-italic {
    font-size: .85rem;
    color: var(--app-muted);
}
.ind-cal-cell hr, .msos-table hr {
    margin: .45rem 0;
    border-color: var(--app-border);
    opacity: 1;
}
#individual_sticky_controls .btn-outline-secondary {
    background: #fff;
    border-color: var(--app-border);
    color: var(--app-slate-ink);
}
#individual_sticky_controls .btn-outline-secondary:hover {
    background: var(--app-slate-soft);
}

/* ---- whiteboard: category cards on the gradient ground ---- */
.wb-cat-title {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--app-faint);
    font-weight: 700;
    margin: 0 0 .4rem .15rem;
}
#whiteboard [id^="whiteboard_category__"] {
    background: #fff;
    border: 1px solid var(--app-border);
    border-radius: .85rem;
    padding: .8rem .95rem .5rem;
    margin-bottom: .8rem;
}
#whiteboard [id^="whiteboard_category__"].d-none {
    display: none !important;
}
/* ============================================================================
   Edit Station Permissions — station roster with inline level editing (.spx)
   ========================================================================== */
.spx { --spx-line: var(--app-border); }

.spx-lede { font-size: .78rem; color: var(--app-muted); margin: .1rem .1rem .7rem; line-height: 1.35; }

/* Search box with leading icon */
.spx-search { position: relative; margin: .2rem 0 .6rem; }
.spx-search svg { position: absolute; left: .7rem; top: 50%; transform: translateY(-50%); color: var(--app-faint); pointer-events: none; }
.spx-search input { padding-left: 2.05rem; }

/* Level filter chips */
.spx-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .6rem; }
.spx-chip { border: 1px solid var(--spx-line); background: #fff; color: var(--app-muted); border-radius: 999px;
    padding: .22rem .66rem; font-size: .76rem; font-weight: 600; cursor: pointer; line-height: 1.2; transition: border-color .12s, background .12s, color .12s; }
.spx-chip:hover { border-color: #cbd5e1; }
.spx-chip.on { background: var(--app-ink); border-color: var(--app-ink); color: #fff; }
.spx-chip .c { opacity: .6; margin-left: .3rem; font-variant-numeric: tabular-nums; }
.spx-chip.on .c { opacity: .8; }

.spx-count { font-size: .75rem; color: var(--app-muted); margin: .1rem 0 .45rem .1rem; }

/* Roster list */
.spx-ulist { display: flex; flex-direction: column; gap: .3rem; max-height: 52vh; overflow-y: auto; padding-right: .15rem; }
.spx-urow { display: flex; align-items: center; gap: .6rem; width: 100%; border: 1px solid var(--spx-line);
    background: #fff; border-radius: .75rem; padding: .45rem .6rem; }
.spx-urow.self { opacity: .6; }

.spx-av { width: 32px; height: 32px; border-radius: 50%; flex: 0 0 auto; display: grid; place-items: center;
    font-size: .76rem; font-weight: 700; color: #fff; background: var(--app-faint); }

.spx-uinfo { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.spx-uname { font-weight: 600; font-size: .88rem; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spx-you { color: var(--app-faint); font-weight: 500; }
.spx-umail { font-size: .74rem; color: var(--app-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Right-hand role cell: inline select, or a read-only pill for locked/self */
.spx-role { flex: 0 0 auto; display: flex; align-items: center; gap: .45rem; }
.spx-lvl-select { width: auto; font-weight: 600; min-width: 8.5rem; }
.spx-lock { font-size: .68rem; color: var(--app-faint); font-style: italic; white-space: nowrap; }
.spx-pill { font-size: .68rem; font-weight: 700; padding: .18rem .5rem; border-radius: 999px; white-space: nowrap; background: var(--app-slate-soft); color: var(--app-slate-ink); }

/* Level colors (avatars + pills) keyed off data-level */
.spx-av[data-level="supervisor"]        { background: #7c3aed; }
.spx-av[data-level="acting_supervisor"] { background: #4338ca; }
.spx-av[data-level="draft_editor"]      { background: #16a34a; }
.spx-av[data-level="draft_viewer"]      { background: #0891b2; }
.spx-av[data-level="published_viewer"]  { background: #64748b; }
.spx-av[data-level="none"]              { background: #94a3b8; }
.spx-pill[data-level="supervisor"]        { background: #ede9fe; color: #6d28d9; }
.spx-pill[data-level="acting_supervisor"] { background: #e0e7ff; color: #4338ca; }
.spx-pill[data-level="draft_editor"]      { background: #dcfce7; color: #15803d; }
.spx-pill[data-level="draft_viewer"]      { background: #cffafe; color: #0e7490; }
.spx-pill[data-level="published_viewer"]  { background: var(--app-slate-soft); color: var(--app-slate-ink); }
.spx-pill[data-level="none"]              { background: #fff; color: var(--app-faint); border: 1px dashed #cbd5e1; }

.spx-empty { padding: 1.4rem 1rem; text-align: center; color: var(--app-muted); font-size: .85rem; }

/* Clear x on the app's other searchable dropdowns: the stock one only fades in on */
/* hover (never on touch). Always show it on a filled control; hide it on an empty one. */
.ts-wrapper.plugin-clear_button.has-items .clear-button {
    opacity: 1;
    font-size: 1.5rem;
    line-height: 1;
    font-weight: 400;
    color: #6c757d;
    padding: 0 .35rem;
    right: 2rem;
}
.ts-wrapper.plugin-clear_button.has-items .clear-button:hover { color: #dc3545; }
.ts-wrapper.plugin-clear_button:has(.item[data-value=""]) .clear-button { display: none; }
.ts-wrapper.plugin-clear_button.has-items .ts-control { padding-right: 3.6rem; }

/* ----------------------------- */
/* CHIP FIELDS (Update Crew modal) */
/* ----------------------------- */
/* A filled value is a blue chip with its own x; an empty one is a dashed "+ Add". */
.cu-field { border: 1px solid #dee2e6; border-radius: .5rem; padding: .4rem .7rem .55rem; display: flex; flex-direction: column; gap: .3rem; }
.cu-label { font-size: .75rem; color: #6c757d; }
.ts-wrapper.chip-select { border: 0; padding: 0; background: none; min-height: 0; }
.ts-wrapper.chip-select .ts-control { border: 0; padding: 0; background: none; box-shadow: none; min-height: 0; cursor: pointer; }
.ts-wrapper.chip-select .ts-control > input { display: none !important; }
.ts-wrapper.chip-select.disabled { opacity: .5; }
.chip-item { display: inline-flex; align-items: center; max-width: 100%; background: #e8eefb; color: #1f3f86; border-radius: 999px; font-size: .95rem; }
.chip-item .chip-text { padding: .4rem .2rem .4rem .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip-item .chip-x { flex: 0 0 auto; width: 2.2rem; height: 2.1rem; display: grid; place-items: center; cursor: pointer; }
.chip-item .chip-x svg { width: 1.15rem; height: 1.15rem; fill: #5f7fc4; }
.chip-item .chip-x:hover svg, .chip-item .chip-x:focus-visible svg { fill: #dc3545; }
.chip-item .chip-x:focus-visible { outline: 2px solid #0d6efd; outline-offset: -4px; border-radius: 999px; }
.chip-add { display: inline-block; color: #0d6efd; font-size: .95rem; padding: .4rem .85rem .4rem .65rem; border: 1px dashed #ced4da; border-radius: 999px; }
.chip-note { font-size: .8rem; color: #6c757d; }
.chip-note-error { color: #b02a37; }
.chip-note button { border: 0; background: none; padding: 0; color: #0d6efd; text-decoration: underline; }
/* Start / End: a pill, not a full-width box */
.cu-time input[type="time"] { align-self: flex-start; width: auto; border: 0; border-radius: 999px; background: #f1f3f5; padding: .3rem .8rem; font-variant-numeric: tabular-nums; }
/* Toggle chips: a checkbox and its label, drawn as one pill */
.cu-toggles { display: flex; flex-wrap: wrap; gap: .45rem; }
.cu-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.cu-toggle label { display: inline-block; cursor: pointer; font-size: .9rem; padding: .35rem .85rem; border-radius: 999px; border: 1px solid #dee2e6; color: #6c757d; user-select: none; }
.cu-toggle input:checked + label { background: #e8eefb; color: #1f3f86; border-color: transparent; }
.cu-toggle input:checked + label::before { content: "\2713\00a0"; }
.cu-toggle input:focus-visible + label { outline: 2px solid #0d6efd; outline-offset: 2px; }
/* Seat list rows: name, and a badge for someone based at another station */
.seat-option { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .15rem .5rem; }
.seat-option-name { min-width: 0; }
.home-badge { font-size: .7rem; padding: .1rem .5rem; border-radius: 999px; background: #eef0f3; color: #5c6570; }
.seat-option .highlight { padding: 0; margin: 0; border-radius: 2px; }
.home-badge .highlight { background: none; }
.seat-hint { padding: .5rem .75rem; font-size: .8rem; color: #6c757d; }
.seat-more { border-top: 1px solid #e9ecef; }
/* Start and End share a row */
.cu-time { display: inline-flex; width: calc(50% - .2rem); vertical-align: top; }

/* ---- Regular lines confirm: one card per line, who comes off -> who goes on ---- */
.ol-swap { border: 1px solid #e2e8f0; border-radius: .8rem; padding: .6rem .75rem .7rem; background: #fff; }
.ol-swap-line { margin-bottom: .45rem; }
.ol-swap-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: stretch; gap: .45rem; }
.ol-who { display: flex; flex-direction: column; justify-content: center; border-radius: .6rem; padding: .4rem .6rem; font-weight: 600; line-height: 1.25; min-width: 0; overflow-wrap: anywhere; }
.ol-who small { font-weight: 500; font-size: .7rem; letter-spacing: .04em; text-transform: uppercase; opacity: .8; }
.ol-off { background: #fde8e7; color: #8f1d1d; }
.ol-on { background: #dcf5e3; color: #14532d; }
.ol-nobody { border: 1px dashed #cbd5e1; color: #64748b; font-weight: 500; }
.ol-arrow { align-self: center; font-size: 1.4rem; color: #64748b; }

/* ---- Crew editor, Regular lines: the rotation options and the result box ---- */
.rl-opt { display: flex; align-items: center; gap: 10px; width: 100%; border: 1px solid #e2e8f0; border-radius: .8rem; padding: 9px 12px; margin-bottom: 7px; background: #fff; cursor: pointer; }
.rl-opt:has(input:checked) { border-color: var(--app-primary, #4175c8); background: var(--app-primary-soft, #edf3fa); }
.rl-opt-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.rl-opt-text b { font-weight: 600; font-size: .9rem; }
.rl-opt-text small { color: #64748b; overflow-wrap: anywhere; }
.rl-result { border-radius: .8rem; padding: .6rem .75rem; font-size: .86rem; }
.rl-result b { display: block; font-size: 1rem; }
.rl-result.add { background: #dcf5e3; color: #14532d; }
.rl-result.lose { background: #fde8e7; color: #8f1d1d; }
.rl-result.none { border: 1px dashed #cbd5e1; color: #64748b; }
.rl-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.rl-pills .ce-pill { background: rgba(0, 0, 0, .08); }

/* ---- Operational Readiness dashboard ----
   These live here, not in the page's {% block style %}: navigating in from the
   menu is an out-of-band swap of #main alone, so a <style> in the response head
   never reaches the DOM. Without .readiness-scroll the content overflowed #main
   inside an overflow:hidden body and the page could not be scrolled at all. */
.readiness-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }
/* One height whether it is showing a percentage or only its colour, so turning
   the numbers off does not re-flow the whole board. */
.readiness-cell { display: flex; align-items: center; justify-content: center;
  min-width: 74px; min-height: 44px; padding: .5rem .25rem; line-height: 1.1; }
.readiness-cell:focus-visible { outline: 2px solid #11181c; outline-offset: 1px; }
.readiness-cell--empty { background: #f4f6f8; border: 1px dashed #dfe3e8; }
.readiness-grid th, .readiness-grid td { white-space: nowrap; }
.readiness-legend { height: 12px; width: 220px; border-radius: 6px;
  background: linear-gradient(90deg, #e5484d 0%, #f2c94c 50%, #27ae60 100%); }

/* Phone: the two headline numbers share the width rather than crowding the
   title, and a week's worth of cells gets closer to fitting. */
@media (max-width: 575.98px) {
  .readiness-kpis { width: 100%; }
  .readiness-kpis > .card { flex: 1 1 0; }
  .readiness-cell { min-width: 44px; min-height: 38px; padding: .4rem .15rem; font-size: .8rem; }
  .readiness-legend { width: 120px; }
}

/* ---- Readiness dashboard builder ---- */
/* Beside the editor this column is 220px wide; stacked above it on a phone the
   same shorthand would have pinned it to 220px TALL, leaving a dead gap under
   the last dashboard. Width only, and only once there is room for two columns. */
.rd-dash-col { flex: 1 1 auto; min-width: 0; }
@media (min-width: 768px) { .rd-dash-col { flex: 0 0 220px; } }

.rd-label { font-size: .72rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: #64748b; display: block; margin-bottom: .3rem; }
.rd-label b { color: #11181c; font-size: .85rem; letter-spacing: 0; }
.rd-field { margin-bottom: .9rem; }

/* Phone: the list becomes one line - a picker and a + . */
.rd-picker { display: flex; gap: .5rem; margin-bottom: 1rem; }
.rd-picker .form-select { flex: 1 1 auto; min-width: 0; }
.rd-picker .btn { flex: 0 0 auto; width: 42px; padding-inline: 0; font-weight: 700; }

/* "Saved" sits inside the field's right end, so the field is full width and
   nothing jumps when the word comes and goes. */
.rd-name-row { position: relative; }
.rd-name-row .form-control { padding-right: 3.6rem; }
.rd-saved { position: absolute; right: .75rem; top: 50%; transform: translateY(-50%);
  font-size: .78rem; font-weight: 600; color: #15803d; pointer-events: none; }

/* The two settings share a row and wrap only when they must. */
.rd-settings { display: flex; flex-wrap: wrap; gap: .6rem .9rem; margin-bottom: .9rem; }
.rd-settings .rd-field { margin: 0; }

.rd-crews-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .35rem; }
.rd-crews-head .rd-label { margin: 0; }
.rd-showall { display: flex; align-items: center; gap: .4rem; font-size: .8rem; color: #64748b; cursor: pointer; margin: 0; }

.rd-crew-list { max-height: 360px; overflow-y: auto; overflow-x: hidden;
  border: 1px solid #e0e6ea; border-radius: 8px; }
.rd-crew-station { display: flex; align-items: baseline; gap: .5rem; padding: .3rem .6rem;
  font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #475569;
  background: #f6f8f9; border-bottom: 1px solid #e0e6ea; position: sticky; top: 0; z-index: 1; }
.rd-folded { margin-left: auto; font-weight: 500; text-transform: none; letter-spacing: 0; color: #94a3b8; }
.rd-crew-list.rd-show-all .rd-folded { display: none; }

/* One line per crew: who it is, what it is, when it runs. Wraps only if it must. */
.rd-crew-row { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem;
  padding: .45rem .6rem; border-bottom: 1px solid #eef1f4; cursor: pointer; margin: 0; }
.rd-crew-row:last-child { border-bottom: 0; }
.rd-crew-name { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; overflow-wrap: anywhere; }
@media (min-width: 768px) { .rd-crew-name { min-width: 118px; } }
.rd-crew-alt { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8rem; color: #6c757d; }
.rd-crew-shift { margin-left: auto; font-size: .8rem; color: #6c757d; white-space: nowrap; }
.rd-why { background: #fdf3d8; color: #7a4a00; border: 1px solid #f0d9a0; font-weight: 600; }
/* Crews that would not count stay folded until asked for - unless they are on
   the board, which must always be visible so they can be taken off. */
.rd-crew-list:not(.rd-show-all) .rd-noise:not(.rd-checked) { display: none; }
.rd-noise .rd-crew-name, .rd-noise .rd-crew-alt { color: #94a3b8; }

.rd-danger { margin-top: 1.25rem; padding-top: .75rem; border-top: 1px solid #eef1f4; }


/* ---- Readiness: plan vs actual ----
   Same reason as the .readiness-* block above: menu navigation is an
   out-of-band swap of #main, so a <style> in the page head never lands.
   Without these the page could not scroll AND the summary bar collapsed
   to its three numbers run together - "2276016" instead of a bar. */
.pva-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.pva-grid th, .pva-grid td { white-space: nowrap; }
.pva-bar { display: flex; height: 34px; border-radius: 8px; overflow: hidden; background: #f1f3f6; }
.pva-bar span { display: grid; place-items: center; font-size: 12px; font-weight: 700; }
.pva-seg--held { background: #cbd5e1; color: #475569; }
.pva-seg--recovered { background: #16a34a; color: #fff; }
.pva-seg--lost { background: #dc2626; color: #fff; }
.pva-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }
.pva-dot--held { background: #cbd5e1; }
.pva-dot--recovered { background: #16a34a; }
.pva-dot--lost { background: #dc2626; }
.pva-mini { position: relative; width: 54px; height: 20px; border-radius: 4px; background: #f1f3f6; overflow: hidden; }
.pva-mini i { position: absolute; top: 0; bottom: 0; left: 0; display: block; background: #cbd5e1; }
.pva-mini i.pva-move--up { background: #16a34a; }
.pva-mini i.pva-move--down { background: #dc2626; }
.pva-empty { width: 54px; height: 20px; border-radius: 4px; background: #f4f6f8; border: 1px dashed #dfe3e8; }
.pva-delta { min-width: 30px; text-align: left; font-weight: 700; font-variant-numeric: tabular-nums; }
.pva-delta--up { color: #16a34a; }
.pva-delta--down { color: #dc2626; }
.pva-delta--flat { color: #8a9099; font-weight: 500; }
.pva-none { border: 1px dashed #dfe3e8; }
.pva-when { min-width: 66px; font-variant-numeric: tabular-nums; }
.pva-unit { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* The flow under the bar: the count at the end of every day from the plan on,
   the plan as a dashed rule, the week's Monday as a thin one, a dot where it
   stands now. No axes: the caption under it carries the numbers. The line is
   drawn in its own coordinates and stretched to the card, so its stroke must
   not scale with it (vector-effect on the polyline), and the end dot sits at
   the right edge, so nothing may clip. */
.pva-spark { display: block; overflow: visible; }
.pva-spark svg { overflow: visible; }
.pva-spark__line { fill: none; stroke: #475569; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pva-spark__plan { stroke: #94a3b8; stroke-width: 1; stroke-dasharray: 4 3; }
.pva-spark__monday { stroke: #cbd5e1; stroke-width: 1; }
.pva-spark__end { fill: #475569; }
.pva-flow { color: #475569; font-variant-numeric: tabular-nums; }

/* Who came and went: rows, not a table (a table wrapped every row over eight
   lines on a phone). The kind as a chip in the bar's colours, the name, the
   hop with a station chip when the crew is not at the station the header
   names, the shift, and the seat's occupants over the versions in mono. */
.pva-day { margin: 12px 0 4px; letter-spacing: .04em; }
.pva-day:first-child { margin-top: 0; }
.pva-person { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-bottom: 4px;
  padding: 6px 10px; border: 1px solid #e2e8f0; border-radius: 10px; background: #fff; }
.pva-kind { font-size: .7rem; font-weight: 700; padding: 1px 8px; border-radius: 999px; }
.pva-kind--removed { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
.pva-kind--moved { background: #e2e8f0; color: #334155; border: 1px solid #cbd5e1; }
.pva-kind--added { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; }
.pva-name { font-weight: 600; font-size: .9rem; }
.pva-where { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums; }
.pva-chip { font-size: .7rem; font-weight: 700; padding: 1px 6px; border-radius: 999px;
  background: #f1f5f9; color: #475569; border: 1px solid #e2e8f0; }
.pva-seq { margin-left: auto; font-size: .78rem; overflow-wrap: anywhere;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
/* What the row did to the car, after the crew's label: red when it took a
   staffed car down, green when it made one, grey when the car was down
   either way. It sits inside the mono hop, so it takes the body face back. */
.pva-effect { font-family: var(--bs-body-font-family); font-size: .7rem; font-weight: 700;
  padding: 1px 6px; border-radius: 999px; vertical-align: 1px; white-space: nowrap; }
.pva-effect--down { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
.pva-effect--staffed { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; }
.pva-effect--short { background: #f1f5f9; color: #64748b; border: 1px solid #e2e8f0; }

/* Phone: the bar's three segments cannot hold a label each at 390px, so the
   numbers sit in the legend underneath and the bar is pure proportion. */
@media (max-width: 575.98px) {
  .pva-bar { height: 16px; }
  .pva-bar span { font-size: 0; }
  .pva-seq { margin-left: 0; flex-basis: 100%; }
}

/* Readiness: the View menu's section labels. */
.rd-opt-label { font-size: .75rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: #6c757d; margin-bottom: .35rem; }

/* ---- Schedule Validator: the findings list in the modal ----
   Rows, not a table: on a phone a three-column table wrapped every finding
   over eight lines. Gap on the left in mono, who and the two shifts beside it,
   the other station as a chip on the right. */
.sv-rows { display: flex; flex-direction: column; gap: 6px; }
.sv-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border: 1px solid #e2e8f0; border-radius: 10px; background: #fff; }
.sv-row--cross { border-color: #f0d9a0; background: #fffaf0; }
.sv-row--overlap { border-color: #f5c2c7; background: #fff5f5; }
.sv-gap { flex: 0 0 64px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700; font-variant-numeric: tabular-nums; color: #b42318; font-size: .9rem; line-height: 1.15; }
.sv-row--cross .sv-gap { color: #9a5b00; }
.sv-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.sv-who { font-weight: 600; font-size: .9rem; }
.sv-ctx { font-size: .78rem; color: #475569; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.sv-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.sv-chip { font-size: .7rem; font-weight: 700; padding: 1px 8px; border-radius: 999px;
  background: #fdf3d8; color: #7a4a00; border: 1px solid #f0d9a0; }

/* ---- Permissions Log: the change list in the modal ----
   One row per change. On a phone: who and where on the first line, the level
   change on the second, when/by whom/why beneath. From tablet width up the
   same four pieces sit on one line. The chips are the People search pills,
   not .oc-chip: that class is wired to the offcanvas station filter and would
   toggle it from inside the modal. */
.pl-chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.pl-chip { border: 1px solid var(--app-border); border-radius: 999px; padding: .24rem .6rem;
  font-size: .74rem; font-weight: 600; background: var(--app-muted-bg); color: var(--app-muted); }
.pl-chip:hover { background: #fff; color: var(--app-ink); }
.pl-chip.active { background: var(--app-ink); border-color: var(--app-ink); color: #fff; }
.pl-chip:focus { outline: none; }
.pl-chip:focus-visible { outline: 2px solid rgba(var(--app-primary-rgb), .5); outline-offset: 1px; }
.pl-row { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "person station" "change change" "meta meta";
  column-gap: .6rem; row-gap: .1rem; padding: .5rem .2rem; border-bottom: 1px solid var(--app-border);
  text-align: left; line-height: 1.3; overflow-wrap: anywhere; }
.pl-rows + .pl-rows .pl-row:first-child { border-top: 0; }
.pl-person { grid-area: person; font-weight: 600; }
.pl-station { grid-area: station; font-weight: 600; font-variant-numeric: tabular-nums; }
.pl-change { grid-area: change; font-size: .9rem; }
.pl-meta { grid-area: meta; font-size: .78rem; color: var(--app-muted); font-variant-numeric: tabular-nums; }
@media (min-width: 768px) {
  .pl-row { grid-template-columns: minmax(9rem, 1fr) 3.5rem minmax(15.5rem, 1.5fr) minmax(14rem, 1.6fr);
    grid-template-areas: "person station change meta"; align-items: baseline; }
  .pl-change { font-size: inherit; }
}
