/* /var/www/html/sysMonitor/css/sysmonitor.css
 *
 * Every rule these pages need, in one file. Loaded by includes/chrome.php; no page in
 * sysMonitor/ has a <style> block of its own.
 *
 * NO EXTERNAL STYLESHEET BUT BOOTSTRAP. These pages used to link cc-ui.css live from
 * docs2txt.com. That is off (Bob, 2026-09-11: "do not use doc2txt css or js"), so the
 * parts of that kit these pages actually used are in the FIRST section below and the
 * folder no longer depends on another host at runtime. Bootstrap 5.3 and Font Awesome 6
 * still come from their CDNs - see includes/chrome.php if those should be local too.
 *
 * THE cc- CLASS NAMES WERE KEPT ON PURPOSE. The markup says .cc-thread, .cc-bubble,
 * .cc-toolbar and so on exactly as before, so no page or script had to change and the
 * kit could be linked again later without touching anything. Same reasoning as
 * js/sysmonitor.js keeping ccPost and ccAddBubble.
 *
 * NEVER WRITE A LITERAL COLOUR HERE. Every colour resolves a Bootstrap CSS variable,
 * which is what lets one sheet serve light and dark - the toggle flips data-bs-theme on
 * <html> and these rules follow. A hex looks right in one mode and wrong in the other,
 * and it is the single easiest way to break these pages. The one exception is the dark
 * token block immediately below, which is redefining the tokens themselves.
 *
 * Derived in part from cc-ui.css in Bob's command centre.
 */

/* ====================================================================================
 * FROM THE COMMAND CENTRE KIT
 * Carried locally so this folder stands alone. If the kit is ever linked again, this
 * whole section becomes a duplicate and can go; nothing below it depends on it.
 * ==================================================================================== */

/* ---- dark mode tokens -------------------------------------------------------------
 * Bootstrap's stock dark palette leaves muted text too dim to read. .text-secondary
 * resolves to #6c757d in both modes, which is fine on white and murky on near-black,
 * and these layouts lean on it for every label and caption. These raise the muted
 * tones without touching the semantic colours the status badges depend on. */
[data-bs-theme="dark"] {
    --bs-body-color: #e9ecef;
    --bs-body-color-rgb: 233, 236, 239;

    --bs-secondary-rgb: 176, 184, 193;
    --bs-secondary-color: rgba(233, 236, 239, .84);
    --bs-secondary-color-rgb: 233, 236, 239;

    --bs-tertiary-color: rgba(233, 236, 239, .68);
    --bs-emphasis-color: #ffffff;
    --bs-emphasis-color-rgb: 255, 255, 255;
    --bs-heading-color: #f8f9fa;

    --bs-border-color: #3d444d;
    --bs-code-color: #ff9ecd;
}

/* Cards sit on the tertiary body background, so give them a touch more separation than
 * the default dark surface, or the page flattens into one dark rectangle. */
[data-bs-theme="dark"] .card { background-color: #1b1f24; }
[data-bs-theme="dark"] body  { background-color: #121519 !important; }

/* ---- text and tables -------------------------------------------------------------- */
.cc-table th {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--bs-secondary-color);
    font-weight: 600;
    border-bottom-width: 1px;
}

.cc-mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .78rem;
    line-height: 1.5;
    white-space: pre;
    overflow-wrap: normal;
    overflow-x: auto;
}

.cc-wrap { overflow-wrap: anywhere; }

/* tabular-nums is the point: without it the digits are proportional and a column of
 * times will not line up, which makes a log far harder to scan than it needs to be. */
.cc-time {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* A grouping row inside a table that also carries urgency. The !important is
 * load-bearing: Bootstrap's .table sets its own cell background through --bs-table-bg,
 * and a band without it loses its colour inside a hoverable table. */
.cc-band td {
    font-weight: 700;
    padding: 2px 8px !important;
}

.cc-band.is-past td {
    color: var(--bs-danger-text-emphasis);
    background: var(--bs-danger-bg-subtle) !important;
}

.cc-band.is-now td {
    color: var(--bs-success-text-emphasis);
    background: var(--bs-success-bg-subtle) !important;
}

.cc-band.is-soon td {
    color: var(--bs-info-text-emphasis);
    background: var(--bs-info-bg-subtle) !important;
}

details > summary { cursor: pointer; }
details > summary::marker { color: var(--bs-secondary-color); }

/* ---- toolbar ----------------------------------------------------------------------
 * A filter bar above a list. The min-width on the controls stops a select collapsing to
 * the width of its shortest option when flex-wrap puts it on a line of its own. */
.cc-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    padding: .75rem 1rem;
    background: var(--bs-warning-bg-subtle);
    border-radius: .5rem;
    margin-bottom: 1rem;
}

.cc-toolbar .form-select,
.cc-toolbar .form-control {
    width: auto;
    min-width: 190px;
}

/* ---- one-row bar ----------------------------------------------------------------
 * A bar for a number beside a label. Two elements, no chart library: one value per row
 * does not justify a dependency. The inner width is the only thing a caller sets, which
 * is why it is an inline style - it is data, not design. */
.cc-bar {
    display: block;
    height: .6rem;
    background: var(--bs-secondary-bg);
    border-radius: var(--bs-border-radius);
}

.cc-bar > span {
    display: block;
    height: .6rem;
    background: var(--bs-primary);
    border-radius: var(--bs-border-radius);
}

/* ---- nav ------------------------------------------------------------------------
 * Every link stays on screen at every width: the row wraps onto a second line rather
 * than collapsing behind a toggle, and each button keeps its label on one line. */
.cc-nav .btn { white-space: nowrap; }

/* ---- message thread --------------------------------------------------------------
 * Reads as a conversation: them on the left, you on the right. Both sides take the same
 * 80%, so it reads as one column with a ragged edge rather than two columns of
 * different widths. Side is what tells them apart. */
.cc-thread {
    max-height: 380px;
    overflow-y: auto;
    padding-right: 4px;
}

.cc-thread-sm { max-height: 360px; }
.cc-thread-md { max-height: 440px; }
.cc-thread-lg { max-height: 460px; }

.cc-bubble {
    width: 80%;
    border-radius: 12px;
    padding: .5rem .7rem;
    font-size: .82rem;
    line-height: 1.45;
    border: 1px solid var(--bs-border-color);
}

.cc-bubble-you   { background: var(--bs-tertiary-bg);       border-bottom-right-radius: 3px; }
.cc-bubble-agent { background: var(--bs-primary-bg-subtle); border-bottom-left-radius: 3px; }

.cc-bubble-who {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--bs-secondary-color);
    margin-bottom: .2rem;
}

/* The "working" bubble. Three dots that actually move, so a wait of a minute reads as
 * activity rather than as the page having died. */
.cc-dots i {
    display: inline-block;
    width: 4px;
    height: 4px;
    margin-left: 2px;
    border-radius: 50%;
    background: currentColor;
    opacity: .35;
    animation: cc-blink 1.2s infinite;
}

.cc-dots i:nth-child(2) { animation-delay: .2s; }
.cc-dots i:nth-child(3) { animation-delay: .4s; }

@keyframes cc-blink {
    0%, 60%, 100% { opacity: .25; }
    30%           { opacity: 1; }
}

.cc-working .cc-bubble { opacity: .85; font-style: italic; }

/* ---- back to top ---------------------------------------------------------------
 * js/sysmonitor.js builds this button and appends it; there is no markup for it. */
#cc-top {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1030;
    width: 2.6rem;
    height: 2.6rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 50%;
    background: var(--bs-body-bg);
    color: var(--bs-secondary-color);
    box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .15);
    display: grid;
    place-items: center;
    cursor: pointer;
    opacity: 0;
    transform: translateY(.5rem);
    pointer-events: none;
    transition: opacity .15s ease, transform .15s ease, color .15s ease;
}

#cc-top.cc-top-on { opacity: 1; transform: none; pointer-events: auto; }
#cc-top:hover { color: var(--bs-primary); border-color: var(--bs-primary); }

@media (max-width: 575.98px) { #cc-top { right: .75rem; bottom: .75rem; } }
@media (prefers-reduced-motion: reduce) { #cc-top { transition: none; } }

/* ====================================================================================
 * SYSMONITOR'S OWN
 * ==================================================================================== */

/* ---- the todo grid ------------------------------------------------------------- */

#todoTable { font-size: .9rem; }

#todoTable td {
    vertical-align: middle;
    word-break: break-word;
}

#todoTable tbody tr.todo-row { cursor: pointer; }

/* A finished row stays readable rather than being greyed into illegibility. */
#todoTable tr.finishedClass td:not(.td-actions) {
    color: var(--bs-warning-text-emphasis);
}

.todo-detail td { background: var(--bs-secondary-bg); }

/* The raw error text on an auto-filed ticket. Tinted with the danger colour at low
   alpha rather than a flat pink, so it reads in both themes. */
.todo-detail pre {
    white-space: pre-wrap;
    word-break: break-all;
    max-height: 320px;
    overflow: auto;
    background: rgba(var(--bs-danger-rgb), .08);
    border: 1px solid rgba(var(--bs-danger-rgb), .35);
    padding: 8px;
    margin: .35rem 0 0;
    font-size: .8rem;
}

.origin-icon {
    color: var(--bs-primary);
    margin-right: .35rem;
    white-space: nowrap;
}

.col-issue  { min-width: 260px; }
.td-actions { white-space: nowrap; }

#todoCount {
    color: var(--bs-secondary-color);
    font-size: .85rem;
}

/* ---- the PHP error log --------------------------------------------------------- */

#phpLogTable { font-size: .8rem; }

#phpLogTable td.msg {
    white-space: normal;
    word-break: break-word;
    min-width: 320px;
}

#phpLogTable td.src {
    font-size: .72rem;
    color: var(--bs-secondary-color);
    word-break: break-all;
    max-width: 340px;
}

.php-raw {
    font-size: .74rem;
    white-space: pre-wrap;
    word-break: break-all;
    margin: 0;
}

/* The most-repeated errors, beside the grid. One error firing 4,000 times is a
   different problem from 4,000 different errors, and this is where that shows. */
.top-err { font-size: .78rem; }

.top-err td {
    padding: 2px 6px;
    border-bottom: 1px solid var(--bs-border-color);
    vertical-align: top;
}

.top-err td.n {
    text-align: right;
    font-weight: 600;
    white-space: nowrap;
}

/* ---- the capture-scope editor -------------------------------------------------- */

.scope-wrap { margin-bottom: 1rem; }

.scope-card {
    background: var(--bs-warning-bg-subtle);
    border-radius: .5rem;
    padding: 1rem;
    margin-bottom: 1.25rem;
}

.scope-table td { vertical-align: middle; }
.scope-table input.form-control-sm { min-width: 90px; }

.scope-icon {
    width: 1.6rem;
    text-align: center;
    color: var(--bs-primary);
}

/* A scope entry that is switched off: dimmed, and its icon loses its colour so the
   row reads as inactive at a glance rather than needing the checkbox checked. */
.off { opacity: .5; }
.off .scope-icon { color: var(--bs-secondary-color); }

.path-code {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: .85rem;
}

.uncovered li {
    display: inline-block;
    margin: 0 .35rem .35rem 0;
}

.uncovered .badge {
    background: var(--bs-secondary-bg);
    color: var(--bs-body-color);
    font-weight: 500;
}

/* ---- the agent and console threads --------------------------------------------- */

/* Evidence and brief blocks: long text that must wrap and must not push the page
   sideways on a phone. */
.sm-evidence {
    max-height: 320px;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
}

.sm-pre-wrap { white-space: pre-wrap; }

/* ---- the usage page ------------------------------------------------------------ */

.sm-col-date { min-width: 5.5rem; }
.sm-col-cost { min-width: 4.5rem; }
.sm-col-n    { min-width: 3rem; }

/* ---- the error centre (events.php) ---------------------------------------------
 * A log line, a stack trace and a patch all have to be shown as the exact bytes they
 * are, so these blocks wrap rather than scroll sideways and never collapse
 * whitespace. pre-wrap, not pre: a 4,000-character stack trace on one line would
 * push the modal wider than the screen and hide the buttons.
 *
 * Every colour is a Bootstrap token, never a literal - the page follows the reader's
 * light/dark choice and a hex value here would survive the theme switch and be
 * unreadable in one of them. */
.cc-pre {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 22rem;
    overflow-y: auto;
    margin-bottom: 0;
    padding: .5rem .6rem;
    background: var(--bs-secondary-bg);
    border-radius: var(--bs-border-radius);
}

/* The before and after of a patch. Subtle backgrounds rather than red/green text:
 * the text itself is code and has to stay legible in both themes. */
.cc-pre-old {
    background: var(--bs-danger-bg-subtle);
    color: var(--bs-danger-text-emphasis);
}

.cc-pre-new {
    background: var(--bs-success-bg-subtle);
    color: var(--bs-success-text-emphasis);
}

/* ---- sortable headers (events.php) ----------------------------------------------
 * The header is a link, because the sort is a new request - the ordering is done in SQL
 * so that it orders the DATA and not just the 200 rows the page happens to be showing.
 * It has to look like a control and not like a link in prose: header colour, no
 * underline until hover, and the arrow only on the column actually in use, so the row
 * does not turn into three competing indicators. Same idiom as the reference page. */
#ev-table thead a.sm-sort {
    color: var(--bs-body-color);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
}

#ev-table thead a.sm-sort:hover {
    color: var(--bs-link-hover-color);
    text-decoration: underline;
}

/* The column in use is the one a reader has to be able to find without hunting. */
#ev-table thead a.sm-sort-on {
    color: var(--bs-link-color);
    font-weight: 600;
}

#ev-table thead .sm-sort-arrow {
    font-size: .7rem;
    margin-left: .15rem;
}

/* The grid while it is fetching. Dimmed and not clickable, so a second click cannot start a
 * second request - but still readable, because the rows on screen are the last true answer
 * and blanking them would lose the reader's place. The words are in #ev-gridalert: a dim
 * alone was too quiet to read as "working", which is how somebody presses a button twice. */
#ev-table.ev-busy {
    opacity: .55;
    pointer-events: none;
}

/* The confidence column. Right-aligned tabular figures, so a column of percentages can be
 * compared down the page rather than read one at a time. */
#ev-table .ev-conf {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Its header goes right with it. A class on the th rather than :has() on the link inside -
 * this has to be right in every browser a store owner's laptop happens to run. */
#ev-table thead th.ev-conf {
    text-align: right;
}

/* The work-list number, styled like the event number for the same reason - but they are
 * DIFFERENT SEQUENCES for different tables, which is why each column is labelled with what
 * its number is rather than a bare #. */
#todoTable .todo-id {
    font-variant-numeric: tabular-nums;
    font-family: var(--bs-font-monospace);
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

/* The event number. Tabular figures so a column of them lines up, and muted because it
 * is an identifier rather than information - but selectable and full size, because the
 * whole reason it is on the page is to be read out or pasted into the filter box. */
#ev-table .ev-id {
    font-variant-numeric: tabular-nums;
    font-family: var(--bs-font-monospace);
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

/* A fault message in the grid. Long enough to recognise, short enough that 200 rows
 * stay scannable - the whole message is in the panel. */
#ev-table .ev-msg {
    word-break: break-word;
    line-height: 1.25;
}

/* The grid rows are clickable, so say so. The cursor is the only affordance a plain
 * table row has. */
#ev-table tbody tr {
    cursor: pointer;
}

/* ---- search text files (tools/searchFiles) ---------------------------------------
 * These rules were a <style> block in search.php, which is the one thing no page in
 * this folder may have, and the first rule in it was `body { margin-top: 60px }` - a
 * leftover from the host site's fixed navbar. Under this folder's own shell there is
 * no fixed navbar, so all it did was push the page 60px down the tertiary background
 * and leave that page sitting lower than every other one in the folder. It is gone,
 * not moved. Every colour below resolves a Bootstrap variable, so the page reads the
 * same in both themes.
 */

/* The folder list scrolls on its own. There are ninety-odd top-level folders in this
 * webroot and the search box has to stay on screen while you tick them. */
#folderCheckList {
    max-height: 560px;
    overflow-y: auto;
}

#folderCheckList .form-check {
    margin-bottom: .1rem;
}

#folderCheckList .form-check-label {
    font-size: .8125rem;
    cursor: pointer;
}

#folderCheckList .form-check-label:hover {
    color: var(--bs-link-hover-color);
}

/* The web root is not one of the folders under it - it is searched shallowly, one
 * level only - so it is ruled off from the list rather than sitting in it. */
#folderCheckList .sf-root {
    border-bottom: 1px solid var(--bs-border-color);
    padding-bottom: .3rem;
    margin-bottom: .3rem;
    font-weight: 600;
}

.sf-extra .form-check-label {
    font-size: .6875rem;
    color: var(--bs-secondary-color);
}

/* A vertical rule between the two search options and the two result switches: they
 * do different things and the gap alone did not say so. */
.sf-show {
    border-left: 1px solid var(--bs-border-color);
    padding-left: .75rem;
}

/* The results pane. It takes the body background rather than the card's, because the
 * rows are the content - on a card surface they read as a panel inside a panel. */
#q_result1 {
    min-height: 400px;
    padding: .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-body-bg);
    overflow-x: auto;
}

/* One block of hits: filenames, then contents. */
.results-section {
    margin-bottom: 1.25rem;
}

.results-section h5 {
    margin: .875rem 0 .25rem;
    font-size: 1rem;
    color: var(--bs-secondary-color);
}

.sf-hits {
    width: 100%;
    border-collapse: collapse;
    font-size: .8125rem;
}

.sf-hits th {
    border-bottom: 1px solid var(--bs-border-color);
    padding: .25rem;
    text-align: left;
}

.sf-hits td {
    padding: .1875rem .25rem;
    vertical-align: top;
}

.sf-hits .sf-col-done  { width: 40px; text-align: center; }
.sf-hits .sf-col-line  { width: 55px; }
.sf-hits .sf-col-path  { white-space: nowrap; }

/* Tick a row off as you work through a long result set. The state is the reader's
 * own, kept in localStorage by search.php, so it is a box rather than a checkbox -
 * nothing is submitted. */
.donebox {
    display: inline-block;
    width: 16px;
    height: 16px;
    border: 2px solid var(--bs-secondary-color);
    border-radius: 3px;
    cursor: pointer;
    position: relative;
    vertical-align: middle;
    user-select: none;
}

.donebox.is-done::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 0;
    width: 6px;
    height: 11px;
    border-right: 3px solid var(--bs-emphasis-color);
    border-bottom: 3px solid var(--bs-emphasis-color);
    transform: rotate(45deg);
}

/* ---- the reference folder (tools/reference) --------------------------------------
 * Also a page-level <style> block until 2026-09-11, and it carried its own
 * `.ref-wrap { max-width: 1500px; margin: 1rem auto; padding: 0 1rem }`. sm_head()
 * has already opened a full-width `container-fluid py-3`, so that wrapper was a
 * second container inside the first: a narrower page than every other one in the
 * folder, indented twice, with a top margin nothing else has. The wrapper is gone
 * and the page now sits in the same container as its neighbours.
 *
 * The literal greys it used (#495057, #6c757d, #dee2e6, #f8f9fa, #fff) were right in
 * the light theme and wrong in the dark one - a white preview pane and a near-white
 * drop zone on a near-black page. Each is a variable now.
 */

.ref-head {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bs-secondary-color);
    border-bottom: 1px solid var(--bs-border-color);
    padding-bottom: .3rem;
    margin-bottom: .4rem;
}

.ref-head i {
    color: var(--bs-tertiary-color);
    margin-right: .2rem;
}

/* Long generated names (claudeJob-2026-09-04.md) must not push the actions off the
 * row - the name cell is the one that gives way. */
.ref-table { font-size: .85rem; table-layout: fixed; }
.ref-table .ref-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ref-table .ref-size { width: 74px; }
.ref-table .ref-when { width: 110px; white-space: nowrap; }
.ref-table .ref-actions { width: 118px; }
.ref-table td { vertical-align: middle; }

/* The drop zone. Bootstrap's warning subtle pair, so it stays a soft highlight in
 * dark mode instead of the cream panel the literal #fff8e1 became. */
.ref-drop {
    background: var(--bs-warning-bg-subtle);
    border: 1px dashed var(--bs-warning-border-subtle);
    border-radius: .5rem;
    padding: 1rem;
    margin-bottom: 1rem;
}

.ref-hint {
    color: var(--bs-secondary-color);
    font-size: .85rem;
}

/* View / Download / Delete on one line - the delete control is a form, so it needs to
 * stop being a block to sit beside the two links. */
.ref-actions { white-space: nowrap; }
.ref-actions form { display: inline-block; margin: 0; }
.ref-actions > * + * { margin-left: .25rem; }

.ref-size {
    white-space: nowrap;
    color: var(--bs-secondary-color);
}

/* The cell stays a real table cell - display:flex on a <td> takes it out of the table
 * layout and the column widths go with it. The flex is on the inner div instead. */
.ref-table td.ref-name { overflow: hidden; }

.ref-name-in {
    display: flex;
    align-items: center;
    gap: .4rem;
    min-width: 0;
}

.ref-thumb {
    width: 34px;
    height: 34px;
    object-fit: cover;
    border-radius: .2rem;
    border: 1px solid var(--bs-border-color);
    background: var(--bs-body-bg);
    flex: 0 0 auto;
    cursor: pointer;
}

.ref-name-in > a {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.ref-open { cursor: pointer; }

/* ── Bare icons, same as the menus toolbars ──
 * The element is still a <button>/<a>; only the btn chrome is gone. A bare icon has
 * to earn back what the border gave it, so it keeps a hover and a focus ring -
 * without one nothing says it is clickable.
 *
 * Shared, despite sitting in this section: agents.php uses it for the Run now column.
 * If a third page wants it, move it to its own section rather than copying it. */
.cig-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    background: none;
    border-radius: 4px;
    color: var(--bs-secondary-color);
    font-size: .95rem;
    line-height: 1;
    cursor: pointer;
    text-decoration: none;
    vertical-align: middle;
}

.cig-ico:hover {
    color: var(--bs-link-hover-color);
    background: var(--bs-tertiary-bg);
}

.cig-ico:focus-visible {
    outline: 2px solid var(--bs-primary-border-subtle);
    outline-offset: 1px;
    color: var(--bs-link-hover-color);
}

/* Disabled has to look disabled. A bare icon has no border to grey out, so without
 * this a Run now button with nothing to run looks exactly like one that will work, and
 * the only feedback is that pressing it does nothing. */
.cig-ico:disabled,
.cig-ico.disabled {
    opacity: .35;
    cursor: not-allowed;
    background: none;
}

.cig-ico:disabled:hover,
.cig-ico.disabled:hover {
    color: var(--bs-secondary-color);
    background: none;
}

.cig-ico-danger { color: var(--bs-danger-text-emphasis); }

.cig-ico-danger:hover {
    color: #fff;
    background: var(--bs-danger);
}

/* Rows with no preview keep the column aligned rather than shifting the other two
 * icons left. */
.cig-ico-gap {
    display: inline-block;
    width: 26px;
    vertical-align: middle;
}

/* ── Sortable headers ── */
.ref-table th[data-sort] {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.ref-table th[data-sort]:hover { color: var(--bs-link-hover-color); }

/* The arrow is on the sorted column only, so the header row does not turn into three
 * competing indicators. */
.ref-table th[data-sort]::after {
    content: '';
    font-size: .7rem;
    margin-left: .3rem;
    color: var(--bs-tertiary-color);
}

.ref-table th[aria-sort="ascending"]::after  { content: '\25B2'; color: var(--bs-link-color); }
.ref-table th[aria-sort="descending"]::after { content: '\25BC'; color: var(--bs-link-color); }

/* The preview body is one box whichever type fills it, so the modal does not resize
 * as you step between files. */
#refPreviewBody {
    min-height: 60vh;
    max-height: 78vh;
    overflow: auto;
    background: var(--bs-tertiary-bg);
    display: flex;
    align-items: center;
    justify-content: center;
}

#refPreviewBody img {
    max-width: 100%;
    max-height: 76vh;
    object-fit: contain;
}

#refPreviewBody iframe {
    width: 100%;
    height: 76vh;
    border: 0;
    background: var(--bs-body-bg);
}

#refPreviewBody pre {
    width: 100%;
    height: 76vh;
    margin: 0;
    padding: 1rem;
    overflow: auto;
    background: var(--bs-body-bg);
    font-size: .8rem;
    white-space: pre-wrap;
    word-break: break-word;
    text-align: left;
}

/* ---- printing ------------------------------------------------------------------
 * Controls are noise on paper; the content is the point. LAST IN THE FILE, because it
 * overrides the nav, toolbar, toggle and results rules above. There were two print
 * blocks here until 2026-09-11 and the first only repeated a selector from the second.
 *
 * The search page's own print block came in from its <style> at the same time. It is
 * landscape on purpose: a result row is a full path plus a line of source, and in
 * portrait every one of them wraps. */
@media print {
    @page {
        size: landscape;
        margin: .35in;
    }

    .cc-toolbar,
    .cc-nav,
    .td-actions,
    #cc-theme-toggle,
    #cc-top,
    .sf-sidebar,
    .sf-query,
    .sf-controls,
    .card-header {
        display: none !important;
    }

    /* The card is a screen affordance. On paper the border is just a line around the
     * whole page. */
    .card {
        border: 0 !important;
        box-shadow: none !important;
    }

    /* The results pane fills the sheet: no min-height holding a short result set open
     * for four hundred pixels, no border, and small enough type to fit a path. */
    #q_result1 {
        min-height: 0 !important;
        border: 0 !important;
        padding: 0 !important;
        font-size: 11px !important;
    }

    .sf-hits { font-size: 11px !important; }
    .sf-hits th,
    .sf-hits td { padding: 2px 5px !important; }

    /* Big enough to tick with a pen. */
    .donebox {
        width: 22px !important;
        height: 22px !important;
    }
}

/* ---- sticky page header ---------------------------------------------------------
 * The title + menu + theme button row sm_head() prints on every page stays at the top
 * while the page scrolls (Bob, 2026-09-13: make it "sticky"). Its background is the body's
 * (bg-body-tertiary) so rows scroll under it rather than through it; the negative inline
 * margin and matching padding stretch that background across the container's gutter.
 * Flows normally in print. */
.sm-headbar {
    position: sticky;
    top: 0;
    z-index: 1020;
    background: var(--bs-tertiary-bg);
    margin-inline: calc(var(--bs-gutter-x, 1.5rem) * -.5);
    padding: .5rem calc(var(--bs-gutter-x, 1.5rem) * .5);
    border-bottom: 1px solid var(--bs-border-color-translucent);
}
@media print {
    .sm-headbar { position: static; border-bottom: 0; }
}

/* ---- source viewer (source.php) --------------------------------------------------
 * Moved in from /errorSource.php on 2026-09-13. Theme colours only: that page's literal
 * light greys and yellows left dark mode as light text on a light background. */
.sm-src-head {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    padding: .6rem 1rem;
    background: var(--bs-warning-bg-subtle);
    color: var(--bs-body-color);
    border-radius: .5rem;
    margin-bottom: .75rem;
}
.sm-src-path { font-family: var(--bs-font-monospace); font-size: .9rem; word-break: break-all; }
.sm-src-code {
    border: 1px solid var(--bs-border-color);
    border-radius: .4rem;
    overflow: auto;
    max-height: 78vh;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
}
.sm-src-code table { border-collapse: collapse; width: 100%; font-family: var(--bs-font-monospace); font-size: .82rem; }
.sm-src-code td { padding: 0 .5rem; white-space: pre; vertical-align: top; }
.sm-src-code td.ln {
    text-align: right;
    color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
    user-select: none;
    width: 1%;
    position: sticky;
    left: 0;
    border-right: 1px solid var(--bs-border-color);
}
.sm-src-code tr.hit td, .sm-src-code tr:target td { background: var(--bs-warning-bg-subtle); color: var(--bs-warning-text-emphasis); }
.sm-src-code tr.hit td.ln { background: var(--bs-warning-border-subtle); font-weight: 700; }

/* ---- small layout helpers ---------------------------------------------------------
 * Replace the inline style="width:..." attributes pages used to carry (2026-09-13), so
 * every look in the folder is set here. */
.sm-w-xs { width: 2.5rem; }
.sm-w-sm { width: 4.5rem; }
.sm-w-md { width: 6.5rem; }
.sm-w-lg { width: 9.5rem; }
.sm-w-xl { width: 12rem; }
.sm-maxw-14 { max-width: 14rem; }
.sm-minw-14 { min-width: 14rem; }
.sm-prewrap { white-space: pre-wrap; }

/* ---- agents.php: what the reviewing agent did (2026-09-15) ----------------------
 * Two long lists (every event and todo of every review) scroll inside their card,
 * with the column heads kept in view. */
.sm-agent-log { max-height: 520px; overflow-y: auto; }
.sm-agent-log thead th { position: sticky; top: 0; z-index: 1; background: var(--bs-body-bg); }

/* events.php: the row is the only way to open an event since the open button went (2026-09-15), so say so. */
#ev-table tbody tr[data-ev] { cursor: pointer; }

/* events.php: each State box is a label around its tick box, so the whole card toggles it (2026-09-15). */
#ev-filters .ev-state { cursor: pointer; }

/* agents.php: the Title and Its job boxes size to their text (size=), but never wider than the card. */
.sm-fit { max-width: 100%; }

/* Agent notes card on agents.php (2026-09-16): keep the note's own line breaks. */
.sm-note-body {
    white-space: pre-wrap;
}
