/* ============================================================================
   SIPF stylesheet.

   Templates should not carry static inline styles — use the classes below. The only
   inline styles that remain are genuinely JS-driven (the progress bar's `width`, set per
   tick). Every color is a token from the palette, defined for a light and a dark theme
   (2026-10-09); every bordered box takes the shared radius. Sections: palette · base ·
   links · tables · buttons · text utils · spacing utils · badges/pills · layout ·
   detail blocks · progress bar · modal.
   ============================================================================ */

/* --- Palette ----------------------------------------------------------------
   Every color in this file is a token from here; a rule never carries a literal.
   Two sets: light on :root, dark where the html element says data-theme="dark"
   (set before first paint by layout.html from the viewer's choice, else the OS
   preference) and, for a page that runs no script, where the OS prefers dark.
   The dark block is written twice for that reason: a media query and an
   attribute cannot share one rule. The pale tints (alert, gap) and the text on
   them are the same in both, so a tinted cell reads the same whatever the page. */
:root {
    --sipf-page-bg: #ffffff;
    --sipf-text: #1b1b1b;
    --sipf-muted: #6c757d;
    --sipf-border: #ced4da;
    --sipf-border-strong: #343a40;     /* the barcode block, the current determination */
    --sipf-rule: #cccccc;              /* hr */
    --sipf-link: #9a3f2b;
    --sipf-link-visited: #b45a3b;
    --sipf-link-hover: #d9602a;
    --sipf-alert: #cb2814;
    --sipf-alert-on-tint: #b22314;     /* alert text on the pale red tint, both themes */
    --sipf-alert-tint: #f8d7da;
    --sipf-gap-tint: #fff3cd;
    --sipf-on-tint: #1b1b1b;           /* text on the pale alert/gap tints, whatever the theme */
    --sipf-alert-tint-striped: #efbfc4;   /* the tints on a striped row, a shade deeper */
    --sipf-gap-tint-striped: #f5e3b0;
    --sipf-ok: #2f7d2f;                /* a settled, agreed value */
    --sipf-ok-tint: rgba(62, 154, 62, 0.14);   /* a finished sheet's tables */
    --sipf-success: #1e6b1e;
    --sipf-danger: #8b0000;
    --sipf-danger-fill: #8b0000;       /* a filled danger cell, white text on it, both themes */
    --sipf-warning: #8a6407;
    --sipf-warning-fill: #8a6407;      /* the update tag, white text on it, both themes */
    --sipf-info: #0b5cd5;
    --sipf-stripe: rgba(0, 0, 0, 0.05);        /* every other row */
    --sipf-table-odd: #e6f0f0;         /* the taxa tables' odd rows */
    --sipf-table-hover: #f6e4de;
    --sipf-panel-bg: #f7f7f7;          /* cards and candidate rows */
    --sipf-panel-bg-alt: #ececec;
    --sipf-panel-border: #d4d4d4;
    --sipf-panel-accent: #2e7d32;      /* a used-record card's left edge */
    --sipf-card-label: #3f6f86;
    --sipf-input-bg: #f4f4f4;
    --sipf-tag-insert: #6c757d;
    --sipf-progress-bg: #e9ecef;
    --sipf-progress-fg: #1e6b1e;
    --sipf-on-dark: #ffffff;           /* text on a filled dark control, whatever the theme */
    --sipf-navbar-bg: #eceef0;         /* the navbar follows the theme, like the page under it */
    --sipf-navbar-fg: #1b1b1b;
    --sipf-navbar-border: #ced4da;
    --sipf-target-db: #8a6d00;         /* the Specify database name on the navbar */
    --sipf-overlay: rgba(0, 0, 0, 0.5);
    --sipf-shadow: rgba(0, 0, 0, 0.25);
    --sipf-viewer-bg: #e9e9e9;
    --sipf-navbar-height: 5rem;        /* the fixed-top navbar in layout.html */
    --sipf-radius: 4px;                /* every bordered box, lightly rounded */
    --sipf-radius-pill: 15px;          /* the round buttons and chips */
    --sipf-importer-accent: #b06d14;   /* the importer area, on the navbar and its pages */
    --sipf-ai-accent: #1d8577;         /* the AI transcription area, likewise */
    --sipf-review-font: 1.15em;        /* the review card's field side, over the body's 13px (rem is 10px here) */
    color-scheme: light;
}
/* The dark set. Keep the two copies identical. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --sipf-page-bg: #040303;
        --sipf-text: #ffffff;
        --sipf-alert: #e8503a;
        --sipf-muted: #8c949c;
        --sipf-border: #495057;
        --sipf-border-strong: #adb5bd;
        --sipf-rule: #555555;
        --sipf-link: #e2beb5;
        --sipf-link-visited: #e28871;
        --sipf-link-hover: #f9a070;
        --sipf-ok: #5cb85c;
        --sipf-ok-tint: rgba(92, 184, 92, 0.12);
        --sipf-success: #5cb85c;
        --sipf-danger: #e06060;
        --sipf-danger-fill: #8b0000;
        --sipf-warning: #d9a21b;
        --sipf-info: #5b9cff;
        --sipf-stripe: rgba(255, 255, 255, 0.16);
        --sipf-table-odd: #1f5151;
        --sipf-table-hover: #492c25;
        --sipf-panel-bg: #1a1a1a;
        --sipf-panel-bg-alt: #2a2a2a;
        --sipf-panel-border: #444444;
        --sipf-card-label: #8fb7c9;
        --sipf-input-bg: #cccccc;
        --sipf-tag-insert: #555555;
        --sipf-progress-bg: #2a2a2a;
        --sipf-progress-fg: #2e7d32;
        --sipf-overlay: rgba(0, 0, 0, 0.6);
        --sipf-shadow: rgba(0, 0, 0, 0.5);
        --sipf-viewer-bg: #222222;
        --sipf-navbar-bg: #15181b;
        --sipf-navbar-fg: rgba(255, 255, 255, 0.85);
        --sipf-navbar-border: #2c3136;
        --sipf-target-db: #e0c81c;
        --sipf-importer-accent: #e0a85a;
        --sipf-ai-accent: #3fb6a8;
        color-scheme: dark;
    }
}
:root[data-theme="dark"] {
    --sipf-page-bg: #040303;
    --sipf-text: #ffffff;
    --sipf-alert: #e8503a;
    --sipf-muted: #8c949c;
    --sipf-border: #495057;
    --sipf-border-strong: #adb5bd;
    --sipf-rule: #555555;
    --sipf-link: #e2beb5;
    --sipf-link-visited: #e28871;
    --sipf-link-hover: #f9a070;
    --sipf-ok: #5cb85c;
    --sipf-ok-tint: rgba(92, 184, 92, 0.12);
    --sipf-success: #5cb85c;
    --sipf-danger: #e06060;
    --sipf-danger-fill: #8b0000;
    --sipf-warning: #d9a21b;
    --sipf-info: #5b9cff;
    --sipf-stripe: rgba(255, 255, 255, 0.16);
    --sipf-table-odd: #1f5151;
    --sipf-table-hover: #492c25;
    --sipf-panel-bg: #1a1a1a;
    --sipf-panel-bg-alt: #2a2a2a;
    --sipf-panel-border: #444444;
    --sipf-card-label: #8fb7c9;
    --sipf-input-bg: #cccccc;
    --sipf-tag-insert: #555555;
    --sipf-progress-bg: #2a2a2a;
    --sipf-progress-fg: #2e7d32;
    --sipf-overlay: rgba(0, 0, 0, 0.6);
    --sipf-shadow: rgba(0, 0, 0, 0.5);
    --sipf-viewer-bg: #222222;
    --sipf-navbar-bg: #15181b;
    --sipf-navbar-fg: rgba(255, 255, 255, 0.85);
    --sipf-navbar-border: #2c3136;
    --sipf-target-db: #e0c81c;
    --sipf-importer-accent: #e0a85a;
    --sipf-ai-accent: #3fb6a8;
    color-scheme: dark;
}

/* --- The navbar (layout.html): its own colors, one set per theme, in place of
   Bootstrap's navbar-dark/bg-dark, which kept it dark over a light page. */
.site-nav { background: var(--sipf-navbar-bg); border-bottom: 1px solid var(--sipf-navbar-border); }
.site-nav .navbar-brand, .site-nav .nav-link, .site-nav .navbar-toggler { color: var(--sipf-navbar-fg); }
.site-nav .nav-link:hover, .site-nav .navbar-brand:hover { color: var(--sipf-navbar-fg); text-decoration: underline; }
.site-nav .navbar-toggler { border-color: var(--sipf-navbar-border); }

/* --- Theme switch (the moon/sun in the navbar, layout.html) --------------- */
.theme-switch { background: none; border: 1px solid transparent; border-radius: var(--sipf-radius); color: var(--sipf-navbar-fg); padding: 2px 8px; margin-left: 8px; cursor: pointer; font-size: 1.1em; line-height: 1; }
.theme-switch:hover { border-color: currentColor; }

/* --- Areas (layout.html): the importer and AI transcription, each a labeled nav group.
   The page's area (the body class) lights its group and gives its headings the accent. */
.nav-area { display: flex; align-items: center; gap: 4px; padding: 2px 10px; border-left: 3px solid transparent; }
.nav-area-label { font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.06em; color: var(--sipf-navbar-fg); opacity: 0.6; margin-right: 4px; }
.nav-area-importer { border-left-color: var(--sipf-importer-accent); }
.nav-area-ai { border-left-color: var(--sipf-ai-accent); }
.area-importer .nav-area-importer .nav-area-label { color: var(--sipf-importer-accent); opacity: 1; }
.area-ai .nav-area-ai .nav-area-label { color: var(--sipf-ai-accent); opacity: 1; }
.nav-action { color: var(--sipf-navbar-fg); border: 1px solid currentColor; border-radius: var(--sipf-radius-pill); padding: 1px 10px; margin-left: 4px; font-size: 0.9em; white-space: nowrap; }
.nav-action:hover { color: var(--sipf-importer-accent); text-decoration: none; }
.area-ai .sipf h1 { border-left: 5px solid var(--sipf-ai-accent); padding-left: 10px; }
.area-importer .sipf h1 { border-left: 5px solid var(--sipf-importer-accent); padding-left: 10px; }
/* The home page: one card per area. */
.area-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 20px; margin-top: 16px; }
.area-card { border: 1px solid var(--sipf-panel-border); border-top: 5px solid var(--sipf-importer-accent); border-radius: var(--sipf-radius); padding: 16px 20px; background: var(--sipf-panel-bg); }
.area-card.area-card-ai { border-top-color: var(--sipf-ai-accent); }
.area-card h2 { font-size: 1.4em; margin-top: 0; }
.area-card .area-counts { list-style: none; padding: 0; margin: 8px 0 14px; }
.area-card .area-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* --- AI runs (vision_runs.html): the start form, one card per run (after the LiDAR
   pipeline's runs page: a state word and a colored left edge per state). */
.run-start { margin: 16px 0 24px; }
.run-start h2 { font-size: 1.2em; }
.run-form { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.run-form label { display: flex; flex-direction: column; font-size: 0.9em; margin: 0; }
.run-form input[type=number] { width: 7em; }
.run-card { border: 1px solid var(--sipf-panel-border); border-left: 5px solid var(--sipf-muted); border-radius: var(--sipf-radius); padding: 10px 14px; margin-bottom: 12px; background: var(--sipf-panel-bg); }
.run-card.run-requested { border-left-color: var(--sipf-warning); }
.run-card.run-reading { border-left-color: var(--sipf-info); }
.run-card.run-ended { border-left-color: var(--sipf-ai-accent); }
.run-card.run-failed { border-left-color: var(--sipf-alert); }
.run-card-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.run-title { font-weight: bold; }
.run-state { font-size: 0.85em; border: 1px solid currentColor; border-radius: var(--sipf-radius-pill); padding: 0 8px; white-space: nowrap; }
.run-meta, .run-counts { font-size: 0.9em; color: var(--sipf-muted); margin-top: 4px; }
.run-counts { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.run-review { margin-left: auto; }
.run-stage { display: grid; grid-template-columns: 8.5em 1fr 11em; gap: 10px; align-items: center; margin-top: 6px; font-size: 0.9em; }
.run-stage-label { color: var(--sipf-muted); }
.run-stage-count { color: var(--sipf-muted); }
.sipf-progress.run-progress { display: flex; height: 10px; margin-top: 0; }   /* the shared bar, slimmer */
.run-bar-read { background: var(--sipf-info); }
.run-progress .run-bar-reading { line-height: 10px; font-size: 0; }   /* the shared striped bar, moving: still being read */
.run-bar { height: 100%; }
.run-bar-sent { background: var(--sipf-ai-accent); }
.run-bar-finished { background: var(--sipf-ok); }
.run-bar-skipped { background: var(--sipf-muted); }
.run-tests { margin-top: 24px; }
.run-list-title { font-size: 1.2em; margin-top: 20px; }
/* Bootstrap's own pieces that carry a color: the tables and the dropdown follow the page. */
.text-muted { color: var(--sipf-muted) !important; }   /* Bootstrap's is !important too */
.table { color: var(--sipf-text); }
.table-striped > tbody > tr:nth-of-type(odd) { background: var(--sipf-stripe); }
.dropdown-menu { background: var(--sipf-page-bg); border-color: var(--sipf-border); }
.dropdown-item { color: var(--sipf-text); }
.dropdown-item:hover, .dropdown-item:focus { background: var(--sipf-stripe); color: var(--sipf-text); }
.card { background: var(--sipf-panel-bg); border-color: var(--sipf-panel-border); border-radius: var(--sipf-radius); color: var(--sipf-text); }
.form-control { background: var(--sipf-page-bg); color: var(--sipf-text); border-color: var(--sipf-border); border-radius: var(--sipf-radius); }
.form-control:focus { background: var(--sipf-page-bg); color: var(--sipf-text); }
input, select, textarea { border-radius: var(--sipf-radius); }
.badge { border-radius: var(--sipf-radius); }

/* --- Base & layout -------------------------------------------------------- */
html {
    height: 100% !important;
    min-width: 680px !important;
    font-size: 62.5% !important;
}

body {
    min-width: 680px !important;
    font-size: 1.3rem;
    margin-bottom: 5rem; /* leave room for footer */
    padding: var(--sipf-navbar-height) 0;     /* fixed navbar */
    background: var(--sipf-page-bg);
    color: var(--sipf-text);
    cursor: default;
}

.sipf { padding: 3rem 1.5rem; }
.clickable-row { cursor: pointer; }
.hidden { display: none; }
.default-animation { transition: all 0.2s 0s ease-in-out; }

/* --- Links ---------------------------------------------------------------- */
a:link { color: var(--sipf-link); text-decoration: none; }
a:visited { color: var(--sipf-link-visited); text-decoration: none; }
a:link:hover,
a:visited:hover { color: var(--sipf-link-hover); text-decoration: none; }

hr {
    display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid var(--sipf-rule);
    margin: 1em 0;
    padding: 0;
}

/* --- Tables --------------------------------------------------------------- */
.table-taxa,
.table-taxa > thead > tr > th,
.table-taxa > tbody > tr > td { text-align: left; }

.table-taxa > tbody > tr:nth-child(odd) > td,
.table-taxa > tbody > tr:nth-child(odd) > th { background-color: var(--sipf-table-odd); }

.table-taxa > tbody > tr:hover { cursor: pointer; }
.table-taxa > tbody > tr:hover > td { color: var(--sipf-link); background: var(--sipf-table-hover); }

/* --- Buttons & icon controls ---------------------------------------------- */
.sipf-button {
    border: 1px solid var(--sipf-text);
    background: var(--sipf-page-bg);
    color: var(--sipf-text);
    padding: 1px 8px 3px;
    margin: 3px;
    border-radius: var(--sipf-radius-pill);
    float: right;
}
.sipf-button:hover { background-color: var(--sipf-text); cursor: pointer; color: var(--sipf-page-bg); }
.sipf-button .inline { margin-left: 15px; }
.sipf-button--success { background-color: var(--sipf-progress-fg); color: var(--sipf-on-dark); border: 0; }
.sipf-button--disabled { background-color: var(--sipf-muted); color: var(--sipf-on-dark); cursor: not-allowed; }

.sipf-link { text-decoration: underline; font-weight: bold; }

/* A transparent, borderless button used as an icon affordance (e.g. the dataset delete ×). */
.icon-button { background: none; border: 0; padding: 0; cursor: pointer; }

/* The delete glyph: it lives in a <button>, which doesn't inherit the theme's a:link color,
   so set the pinkish color explicitly (brighten on hover). */
.dataset-delete { display: inline; color: var(--sipf-link); }
button:hover > .dataset-delete { color: var(--sipf-link-hover); }

/* --- Text utilities ------------------------------------------------------- */
/* NB: these are `.sipf-*` prefixed on purpose — Bootstrap 4 ships `.text-danger`,
   `.text-success`, etc. as `!important` utilities that would otherwise override ours. */
.sipf-muted { color: var(--sipf-muted); }
.sipf-success { color: var(--sipf-success); }
.sipf-danger { color: var(--sipf-danger); }
.sipf-warning { color: var(--sipf-warning); }
.sipf-info { color: var(--sipf-info); }
.text-correction { color: var(--sipf-alert); }      /* an uploaded value that was corrected */
.text-lg { font-size: 1.2em; }
.text-sm { font-size: 0.85em; }
.text-right { text-align: right; }
.text-center { text-align: center; }
.text-bold { font-weight: bold; }
.fst-italic { font-style: italic; }
.d-inline { display: inline; }
.w-60 { width: 60%; }
.p-20 { padding: 20px; }

/* --- Spacing utilities (named by px to preserve existing layout) ---------- */
.sipf-mt-2 { margin-top: 2px; }
.sipf-mt-4 { margin-top: 4px; }
.mt-10 { margin-top: 10px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }
.mt-20 { margin-top: 20px; }
.mt-24 { margin-top: 24px; }
.mt-30 { margin-top: 30px; }
.mt-40 { margin-top: 40px; }
.mt-50 { margin-top: 50px; }
.mb-8 { margin-bottom: 8px; }
.mb-10 { margin-bottom: 10px; }
.ml-6 { margin-left: 6px; }
.ml-8 { margin-left: 8px; }
.mx-10 { margin: 0 10px; }
.pt-20 { padding-top: 20px; }

/* --- Badges (dataset update/insert type) ---------------------------------- */
.tag { padding: 2px 8px; border-radius: var(--sipf-radius); font-size: 0.8em; color: var(--sipf-on-dark); }
.tag--update { background-color: var(--sipf-warning-fill); }
.tag--insert { background-color: var(--sipf-tag-insert); }

/* --- Match-status table cells (matched / unmatched / skipped) ------------- */
/* `.sipf-*` prefixed to avoid Bootstrap 4's `.bg-*` utilities. Scoped through the same
   `.table-taxa > tbody > tr > td` chain as the row-striping rule above so they carry equal
   specificity and win by source order (they're declared later) — no `!important` needed. */
.table-taxa > tbody > tr > td.sipf-bg-success { background-color: var(--sipf-progress-fg); color: var(--sipf-on-dark); }
.table-taxa > tbody > tr > td.sipf-bg-danger { background-color: var(--sipf-danger-fill); color: var(--sipf-on-dark); }
.table-taxa > tbody > tr > td.sipf-bg-muted { background-color: var(--sipf-tag-insert); color: var(--sipf-on-dark); }

/* --- Layout helpers ------------------------------------------------------- */
.review-pane { overflow-y: auto; height: 600px; }
/* A report page that reads as a document: full width up to a point, centered beyond it. */
.page-bounded { max-width: 1600px; margin-left: auto; margin-right: auto; }
/* Pre-flight update preview: totals table, then the per-record list behind a toggle. */
.preview-counts { width: auto; }
.preview-counts td { text-align: right; min-width: 5em; }
.preview-records summary { cursor: pointer; font-weight: bold; margin-bottom: 8px; }
.change-list { margin: 0; padding-left: 1.2em; }
/* Records list beside the clicked record's before/after, at any window width (the Bootstrap
   xl columns stacked the detail under the list below 1200 CSS px). The list takes the width
   its content needs, up to half; the detail takes the rest and stays in view while the page
   scrolls the list, so neither needs a scrollbar of its own. */
.preview-split { display: grid; grid-template-columns: fit-content(50%) minmax(0, 1fr); gap: 16px; align-items: start; }
.preview-split .table { width: auto; }
.preview-detail { position: sticky; top: var(--sipf-navbar-height); max-height: calc(100vh - var(--sipf-navbar-height)); overflow-y: auto; }
.panel { margin-top: 12px; padding: 10px; border: 1px solid var(--sipf-panel-border); border-radius: var(--sipf-radius); }
.panel-light { margin-top: 20px; padding: 10px; border: 1px solid var(--sipf-panel-border); border-radius: var(--sipf-radius); }
.text-input { margin: 3px; background-color: var(--sipf-input-bg); color: var(--sipf-on-tint); border-radius: var(--sipf-radius); }
.sipf-candidates-even { background-color: var(--sipf-panel-bg); }
.sipf-candidates-odd { background-color: var(--sipf-panel-bg-alt); }

/* "Used by" record cards (partials/_used_records.html). */
.field-card {
    height: 100%;
    padding: 6px 10px;
    background: var(--sipf-panel-bg);
    border: 1px solid var(--sipf-panel-border);
    border-left: 3px solid var(--sipf-panel-accent);
    border-radius: var(--sipf-radius);
}
.field-card-label { color: var(--sipf-card-label); font-size: 0.78em; text-transform: uppercase; letter-spacing: 0.03em; }

/* Horizontally-scrollable table wrapper + nowrap table (dataset preview). */
.table-scroll-wrap { overflow-x: auto; max-height: 75vh; border: 1px solid var(--sipf-panel-border); border-radius: var(--sipf-radius); }
.table-nowrap { white-space: nowrap; margin-bottom: 0; }

/* --- Detail blocks (taxon / jurisdiction / agent detail panes) ------------ */
.detail-header { font-size: larger; font-weight: bold; }
.detail-label { font-style: italic; }
.detail-data { font-style: normal; font-weight: bold; }
.detail-data-corrected { font-style: normal; font-weight: bold; color: var(--sipf-alert); }
.correction-scope { margin-top: 6px; }
.correction-scope label { font-weight: bold; margin-right: 8px; }
.login-note { margin-top: 16px; font-style: italic; }
.login-messages { color: var(--sipf-alert); font-weight: bold; }

/* Sheet review (vision_review.html / vision_sheet_card.html) */
.review-progress { display: flex; align-items: center; gap: 12px; font-style: italic; margin-bottom: 8px; }
.review-progress .review-page { float: none; margin: 0; font-style: normal; }
.sheet-card { display: flex; gap: 16px; align-items: flex-start; }
.sheet-viewer-pane { flex: 1 1 55%; position: sticky; top: 70px; }
.sheet-viewer { overflow: hidden; height: 80vh; border: 1px solid var(--sipf-border); border-radius: var(--sipf-radius); background: var(--sipf-viewer-bg); cursor: grab; }
.sheet-viewer img { transform-origin: 0 0; max-width: 100%; user-select: none; }
.viewer-controls { margin-top: 4px; display: flex; gap: 6px; align-items: center; }
.viewer-hint { font-style: italic; color: var(--sipf-muted); }
.sheet-fields { flex: 1 1 45%; }
.barcode-block { border: 1.5px solid var(--sipf-border-strong); border-radius: var(--sipf-radius); padding: 10px; margin-bottom: 12px; }
.barcode-line { display: flex; align-items: center; gap: 12px; margin-bottom: 4px; }
.barcode-line .detail-label { flex: 0 0 auto; }
.barcode-input { font-size: 1.5em; font-weight: bold; flex: 1 1 0; min-width: 0; }
.barcode-confirm { flex: 0 0 auto; font-weight: bold; white-space: nowrap; }
/* Finish was pressed with the barcode unconfirmed: the block says so until the box is ticked. */
.barcode-block.needs-confirm { border-color: var(--sipf-alert); box-shadow: 0 0 0 2px var(--sipf-alert-tint); }
.barcode-block.needs-confirm .barcode-confirm { color: var(--sipf-alert); }
.barcode-confirm-needed { margin-top: 4px; color: var(--sipf-alert); font-weight: bold; }
/* The source of the barcode and its standing in the catalog share the line under it. */
.barcode-block .catalog-note { display: inline; }
.sheet-fields .section-title { font-weight: bold; margin-top: 14px; border-bottom: 1px solid var(--sipf-border); }
.field-table { width: 100%; }
.field-table th { font-style: italic; font-weight: normal; width: 30%; vertical-align: top; }
.field-table td.ai-read, .field-table td.catalog-read { width: 30%; color: var(--sipf-muted); vertical-align: top; }
/* With the catalog column present, three text columns share the row with the input. */
.field-table.with-catalog th, .field-table.with-catalog td.ai-read,
.field-table.with-catalog td.catalog-read { width: 22%; }
/* AI read vs catalog, per vision.catalog.compare: a real disagreement tints the
   whole row red and puts both readings in red; a value only one side has tints
   it amber. The same two classes mark the collectors and determinations lines. */
.catalog-differs > th, .catalog-differs > td, .catalog-note.catalog-differs { background: var(--sipf-alert-tint); }
.catalog-differs > td.ai-read, .catalog-differs > td.catalog-read, .catalog-note.catalog-differs { color: var(--sipf-alert-on-tint); font-weight: bold; }
.catalog-gap > th, .catalog-gap > td, .catalog-note.catalog-gap { background: var(--sipf-gap-tint); }
/* A row edited in parts (latitude's degrees/minutes/seconds/hemisphere, the elevation
   range and unit): the parts share the input cell side by side. */
.field-table .field-parts { display: flex; gap: 4px; align-items: center; }
.field-table .field-parts input, .field-table .field-parts select { width: auto; flex: 1 1 0; min-width: 0; }
.field-table input[type=checkbox], .field-table input[type=radio] { width: auto; }
/* AI read beside the catalog for the list-valued fields (collectors, determinations). */
.comparison-table { margin-top: 6px; }
.comparison-table td { vertical-align: top; }
.det-line { margin-bottom: 2px; }
/* The legend's color samples in the barcode block's catalog note. */
.catalog-key { padding: 0 4px; font-style: normal; }
.catalog-key.catalog-differs { background: var(--sipf-alert-tint); color: var(--sipf-alert-on-tint); }
.catalog-key.catalog-gap { background: var(--sipf-gap-tint); }
/* Column headings on the field tables: upright and bold, unlike the italic row labels. */
.field-table .column-heads th { font-style: normal; font-weight: bold; font-size: 0.85em; border-bottom: 1px solid var(--sipf-border); }
.catalog-note { display: block; color: var(--sipf-muted); font-style: italic; }
.field-table input, .field-table select, .field-table textarea { width: 100%; }
.row-corrected input, .row-corrected textarea { color: var(--sipf-alert); font-weight: bold; }
/* The production review card (one reader): larger type, one value column whose boxes
   start with the AI's reading, the AI's reading shown under a box once it is changed,
   and the free-text fields in boxes of two lines that open taller while in use. */
.review-card .sheet-fields { font-size: var(--sipf-review-font); }
.review-card .field-table { border-collapse: separate; border-spacing: 0 3px; }
.review-card .field-table th, .review-card .field-table.with-catalog th { width: 9.5em; font-style: normal; font-weight: 600; padding: 6px 10px 0 0; }
.review-card .field-table.with-catalog td.catalog-read { width: 30%; padding: 6px 0 0 10px; }
.review-card .field-table .column-heads th { width: auto; font-size: 0.8em; }
.review-card .field-table input, .review-card .field-table select, .review-card .field-table textarea { font-size: inherit; padding: 4px 6px; }
.review-card .sheet-text {
    display: block; resize: none; line-height: 1.35; overflow: hidden;
    height: calc(2 * 1.35em + 10px); transition: height .2s ease-out;
}
.review-card .sheet-text:focus { height: calc(7 * 1.35em + 10px); overflow: auto; box-shadow: 0 2px 8px var(--sipf-shadow); }
@media (prefers-reduced-motion: reduce) {
    .review-card .sheet-text { transition: none; }
}
.review-card .ai-original { display: none; font-size: 0.8em; color: var(--sipf-muted); font-style: italic; margin-top: 2px; }
.review-card .row-corrected .ai-original { display: block; }
.review-card .field-table td { vertical-align: top; }
/* Short fields share a line (card.LINES), each as wide as it needs, with a small caption
   above; numbers in a line or in a row's parts never stretch across the column. */
.review-card .field-line { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.review-card .line-member { display: flex; flex-direction: column; }
.review-card .line-member > div { display: flex; align-items: center; gap: 4px; }
.review-card .line-caption { font-size: 0.75em; line-height: 1.2; color: var(--sipf-muted); }
/* A date's precision at the end of its line, level with the boxes. */
.review-card .date-precision { align-self: flex-end; margin-bottom: 6px; font-size: 0.85em; font-style: italic; color: var(--sipf-muted); }
/* A line row's label and note drop by the caption's height, to sit level with the inputs. */
.review-card .field-table tr.line-row > th { padding-top: calc(0.9em + 6px); }
.review-card .field-table tr.line-row > td.note-cell, .review-card .field-table tr.line-row > td.catalog-read { padding-top: 0.9em; }
/* A field's box with its tree badge or English beside it, not under it: a line under
   every box cost the card a row's height each (Tomislav, 2026-10-16). */
.review-card .field-body { display: flex; align-items: center; gap: 8px; }
.review-card .field-body > input:not([type=checkbox]):not([type=radio]), .review-card .field-body > select,
.review-card .field-body > textarea { flex: 1 1 0; min-width: 0; }
.review-card .field-body > .tree-badge { flex: 0 0 auto; margin-left: 0; }
/* A checkbox alone in its cell: as tall as the note box beside it, so it centers on the label. */
.review-card .field-body:has(> input[type=checkbox]) { min-height: calc(1.15em + 10px); }
.review-card .field-body > input[type=checkbox] { margin: 0; width: 1.1em; height: 1.1em; }
.review-card .field-body > .translation.has-translation { flex: 1 1 0; margin-top: 0; align-self: flex-start; }
.review-card .field-table .field-line input, .review-card .field-table .field-parts input,
.review-card .field-table .field-parts select { width: 7em; flex: 0 0 auto; }
.review-card .field-table input.field-start_month, .review-card .field-table input.field-end_month,
.review-card .field-table input.field-start_day, .review-card .field-table input.field-end_day { width: 4em; }
.review-card .field-table input.field-start_year, .review-card .field-table input.field-end_year { width: 5.5em; }
.review-card .field-table input.field-decimal_latitude, .review-card .field-table input.field-decimal_longitude { width: 9em; }
/* The month's name hangs to the left of its box, outside the member, so the caption
   above stays over the box. */
.review-card .line-member:has(.month-name) { margin-left: 2.6em; }
.review-card .line-member > div:has(.month-name) { position: relative; }
.review-card .month-name { position: absolute; right: calc(100% + 4px); white-space: nowrap; color: var(--sipf-muted); }
/* A row's note: one line in place, opening over the row while it is typed in. */
.review-card .field-table .note-cell { width: 16%; padding-left: 10px; position: relative; }
.review-card .row-note { width: 100%; resize: none; overflow: hidden; white-space: nowrap; height: calc(1.35em + 10px); line-height: 1.35; font-size: 0.85em; }
/* Feedback to the AI, set apart from the values by the AI area's color. */
.review-card .row-note { border: 1px dashed var(--sipf-ai-accent); }
.review-card .row-note::placeholder { color: var(--sipf-ai-accent); opacity: 0.8; font-style: italic; }
.review-card .row-note:not(:placeholder-shown) { border-style: solid; }
.review-card .row-note:focus {
    position: absolute; right: 0; top: 0; z-index: 5; width: min(28em, 50vw); height: calc(5 * 1.35em + 10px);
    white-space: normal; overflow: auto; box-shadow: 0 2px 8px var(--sipf-shadow);
    animation: note-box-open .2s ease-out;
}
/* The box jumps from in-cell to absolute on focus, which no transition can follow, so it
   unfolds instead: revealed from its one-line corner out to the full size. */
@keyframes note-box-open {
    from { clip-path: inset(0 0 calc(100% - 1.9em) 60% round var(--sipf-radius)); }
    to { clip-path: inset(0 0 0 0 round var(--sipf-radius)); }
}
@media (prefers-reduced-motion: reduce) {
    .review-card .row-note:focus { animation: none; }
}
/* A free text's English (vision/translate.py), under its box; empty, it takes no room. */
.review-card .translation { display: none; margin-top: 2px; font-size: 0.85em; color: var(--sipf-muted); }
.review-card .translation.has-translation { display: block; }
.review-card .translation.has-translation:not(.translation-failed)::before { content: 'English: '; font-weight: 600; font-style: normal; }
.review-card .translation:not(.translation-failed) { font-style: italic; }
.review-card .translation.translation-failed { color: var(--sipf-alert); }
/* The Specify names menu under a lookup input (vision_review.js). */
.typeahead-menu {
    position: absolute; z-index: 20; list-style: none; margin: 2px 0 0; padding: 4px 0;
    max-height: 16em; overflow-y: auto; font-size: var(--sipf-review-font);
    background: var(--sipf-input-bg); color: var(--sipf-text);
    border: 1px solid var(--sipf-ai-accent); border-radius: var(--sipf-radius); box-shadow: 0 4px 12px var(--sipf-shadow);
}
.typeahead-head { padding: 2px 10px 4px; font-size: 0.7em; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--sipf-ai-accent); }
.typeahead-item { padding: 3px 10px; cursor: pointer; white-space: nowrap; }
.typeahead-item strong { font-weight: 700; }
.typeahead-item:hover, .typeahead-item.active { background: var(--sipf-table-hover); }
/* Rows with nothing in them anywhere fold under their section as chips, each showing its row. */
.review-card tr.empty-row { display: none; }
.review-card tr.empty-row.shown { display: table-row; background: var(--sipf-stripe); }
.empty-fold { display: flex; flex-wrap: wrap; gap: 4px 6px; align-items: center; margin: 2px 0 8px; font-size: 0.85em; }
.empty-field { display: inline-block; padding: 0 7px; border: 1px solid var(--sipf-muted); border-radius: var(--sipf-radius-pill); color: inherit; text-decoration: none; white-space: nowrap; }
.empty-field:hover { border-color: var(--sipf-ok); text-decoration: none; }
.empty-field.active { border-color: var(--sipf-ok); color: var(--sipf-ok); font-weight: bold; }
/* Remove a row from a list (a collector): a quiet x that turns red on hover. */
.row-remove { flex: 0 0 auto; width: 1.6em; height: 1.6em; padding: 0; line-height: 1; border: 1px solid var(--sipf-border); border-radius: 50%; background: none; color: var(--sipf-muted); cursor: pointer; }
.row-remove:hover, .row-remove:focus { border-color: var(--sipf-alert); color: var(--sipf-alert); }
/* The "+ collector" button sits under the names, where the next one goes. */
.review-card .add-collector-row .sipf-button { float: none; display: inline-block; margin: 0; font-size: 0.85em; }
/* Collectors: first and last name level with each other, the badge beside the last name. */
.review-card #collectors_table th, .review-card #collectors_table td { vertical-align: top; }
.review-card #collectors_table th { padding-top: 10px; }
.review-card .skip-reason { display: flex; align-items: center; gap: 6px; flex: 1; margin: 0; }
.concern-badge { color: var(--sipf-alert); font-size: 0.85em; border: 1px solid var(--sipf-alert); border-radius: var(--sipf-radius); padding: 0 4px; margin-left: 4px; }
.concern-badge.concern-review { background: var(--sipf-alert); color: var(--sipf-on-dark); }
/* A division's standing in Specify's geography tree, and a county the model supplied itself. */
.tree-badge, .inferred-badge { font-size: 0.8em; border-radius: var(--sipf-radius); padding: 0 4px; margin-left: 4px; white-space: nowrap; border: 1px solid var(--sipf-muted); color: var(--sipf-muted); }
.tree-badge:empty { display: none; }
.tree-badge.tree-in-tree { border-color: var(--sipf-ok); color: var(--sipf-ok); }
.tree-badge.tree-not-in-tree { border-color: var(--sipf-alert); color: var(--sipf-alert); font-weight: bold; }
.tree-badge.tree-ambiguous { background: var(--sipf-gap-tint); color: var(--sipf-on-tint); }
.tree-badge.tree-to-add { background: var(--sipf-gap-tint); color: var(--sipf-on-tint); border-color: transparent; }   /* work to do, not an error */
.inferred-badge { font-style: italic; }
.determination-block { margin-bottom: 10px; border-left: 3px solid var(--sipf-border); }
.review-card .determination-block th { padding-left: 12px; }
/* The current determination stands out from the earlier ones: a colored bar and a bold
   "Current"; the earlier ones say "Earlier" in gray. vision_review.js swaps them when the
   radio moves. */
.review-card .determination-block .det-role { color: var(--sipf-muted); font-style: italic; font-weight: normal; }
.review-card .determination-block.det-current .det-role { color: var(--sipf-ai-accent); font-style: normal; font-weight: 700; }
.review-card .determination-block .row-remove { margin-left: auto; }
.det-role-pick { display: inline-flex; align-items: center; gap: 6px; margin: 0; cursor: pointer; }
.determination-block.det-current { border-left: 4px solid var(--sipf-ai-accent); }
/* A determination's name and its determiner each on one line, the boxes sharing the width. */
.review-card .field-table .det-line { flex-wrap: nowrap; gap: 6px 8px; }
.review-card .field-table .det-line .line-member { flex: 1 1 0; min-width: 0; }
.review-card .field-table .det-line input { width: 100%; flex: 1 1 auto; min-width: 0; }
.review-card .field-table .det-line > .tree-badge { flex: 0 0 auto; align-self: flex-end; margin: 0 0 6px; }
.sheet-extras { margin-top: 10px; }
.sheet-extras summary { cursor: pointer; font-style: italic; }
/* The finished and skipped lists above the card: the way back to a sheet, so they read as links. */
.sheet-extras.sheet-list { margin-top: 0; margin-bottom: 6px; }
.sheet-extras.sheet-list summary { font-style: normal; color: var(--sipf-link); }
.ocr-text { white-space: pre-wrap; font-size: 12px; max-height: 300px; overflow: auto; color: var(--sipf-text); }
.review-actions { margin-top: 16px; display: flex; gap: 8px; align-items: center; }
.review-actions #skip_note { flex: 1; }   /* inside its label (.skip-reason) */
/* Bare grouping element for the read-only lock on non-pending cards; min-inline-size
   stops the fieldset's min-content default from breaking the flex layout. */
.sheet-fieldset { border: 0; margin: 0; padding: 0; min-inline-size: auto; }
.sheet-fieldset:disabled input, .sheet-fieldset:disabled select { opacity: 0.6; }
.skipped-list { margin: 4px 0 0 0; padding-left: 20px; }
.detail-data-ignored { font-style: normal; font-weight: bold; color: var(--sipf-alert); text-decoration: line-through; }
.corrected { color: var(--sipf-alert); }
.detail-note { font-style: italic; font-weight: bold; color: var(--sipf-alert); }
.target_db { text-align: right; font-style: normal; font-weight: bolder; color: var(--sipf-target-db); }

/* --- Progress bar (shared by import / upload / delete) -------------------- */
/* Self-contained — does NOT use Bootstrap's .progress classes, which render inconsistently
   across the app's Bootstrap version. The bar's inline `width` is set per tick by JS. */
.sipf-progress {
    height: 28px;
    margin-top: 24px;
    width: 100%;
    background: var(--sipf-progress-bg);
    border-radius: var(--sipf-radius);
    overflow: hidden;
}
.sipf-progress-bar {
    width: 0%;
    height: 100%;
    background-color: var(--sipf-progress-fg);
    color: var(--sipf-on-dark);
    text-align: center;
    line-height: 28px;
    font-size: 13px;
    white-space: nowrap;
    transition: width .3s ease;
    background-image: linear-gradient(45deg,
        rgba(255, 255, 255, .2) 25%, transparent 25%, transparent 50%,
        rgba(255, 255, 255, .2) 50%, rgba(255, 255, 255, .2) 75%, transparent 75%, transparent);
    background-size: 28px 28px;
    animation: sipf-stripes 1s linear infinite;
}
.sipf-progress-bar.done { background-image: none; animation: none; }
@keyframes sipf-stripes { from { background-position: 0 0; } to { background-position: 28px 0; } }
.progress-message { color: var(--sipf-muted); font-family: monospace; }

/* --- Modal dialog --------------------------------------------------------- */
.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--sipf-overlay);
    z-index: 1000;
    align-items: center;
    justify-content: center;
}
.modal-overlay.is-open { display: flex; }
.modal-box {
    background: var(--sipf-panel-bg);
    color: var(--sipf-text);
    border: 1px solid var(--sipf-panel-border);
    border-radius: var(--sipf-radius);
    padding: 24px;
    max-width: 420px;
    width: 90%;
}
.modal-message { margin-bottom: 20px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; }
.modal-confirm:hover { background-color: var(--sipf-danger-fill); color: var(--sipf-on-dark); }
