/* SubmitApp -- the whole stylesheet. Vanilla CSS, no build step (SPEC.md §11). */

/*
 * Accent is CORAL in two deliberate steps (D100):
 *
 *   --accent       text-weight coral. 4.9:1 on white, so links, buttons and
 *                  the active nav can carry it AS TEXT and still pass AA.
 *   --accent-fill  mark-weight coral for chart bars, rails and the brand
 *                  block, where 3:1 (non-text) is the bar. NOT for text.
 *
 * Both were hue-shifted toward vermilion until the palette validator passed
 * them against --fail (#b42318 stays brick): at the obvious "coral red"
 * (#d94f43) accent-vs-fail measured ΔE 11 — confusable even with full colour
 * vision, and this app uses fail red to mean something.
 *
 * The dark-mode accent (#f2a55c) sits ΔE ~13 from the dark fail salmon —
 * short of the 15 a categorical PAIR would need, accepted because the two
 * never appear as colour-only marks of one set: every fail is a worded badge
 * or flash, every accent a worded link. The meter, where colour alone DOES
 * distinguish, uses the validated one-hue ramp --meter-tint → --accent
 * instead of coral-vs-green, which fails protan CVD at ΔE 1.6.
 */
:root {
    --bg: #f6f7f9;
    --surface: #ffffff;
    --border: #dfe3e8;
    --text: #1c2024;
    --muted: #5c6670;
    --accent: #c8431f;
    --accent-fill: #e86a3e;
    --meter-tint: #ee9e70;
    --chart-grid: #e5e8ec;
    --pass: #14804a;
    --pass-bg: #e6f4ec;
    --warn: #8a5a00;
    --warn-bg: #fdf3e2;
    --fail: #b42318;
    --fail-bg: #fdeceb;
    --radius: 6px;

    /* The sidebar is charcoal in BOTH schemes (the Zoho-style dark chrome),
       so its tokens live outside the dark-mode override on purpose. Every
       pairing here is validated ≥ 4.5:1 on --sidebar-bg. */
    --sidebar-bg: #23272e;
    --sidebar-text: #c9d0d8;
    --sidebar-muted: #8b939c;
    --sidebar-active-bg: #2f353d;
    --sidebar-active-ink: #ffffff;
    --brand-bg: #c8431f;
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #14171a;
        --surface: #1c2024;
        --border: #2f353b;
        --text: #e6e9ec;
        --muted: #98a2ac;
        /* Re-picked for the dark surface, not auto-lightened: 8:1 as text. */
        --accent: #f2a55c;
        --accent-fill: #f2a55c;
        --meter-tint: #7c4a30;
        --chart-grid: #2a3036;
        --pass: #5ed39a;
        --pass-bg: #16301f;
        --warn: #e0b054;
        --warn-bg: #33260f;
        --fail: #f78b82;
        --fail-bg: #3a1a17;
    }
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

code, pre {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.9em;
}

code { background: var(--bg); padding: 0.1em 0.35em; border-radius: 3px; }

pre {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    overflow-x: auto;
}

pre code { background: none; padding: 0; }

/* --- Sidebar shell (D100) ------------------------------------------------ */

/* minmax(0, 1fr), not bare 1fr: a wide <table> or <pre> inside the content
   column would otherwise widen the track and push the page sideways. */
.shell {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    min-height: 100vh;
}

.sidebar {
    display: flex;
    flex-direction: column;
    background: var(--sidebar-bg);
    color: var(--sidebar-text);
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.95rem 1rem;
    background: var(--brand-bg);
    color: #fff;
    font-weight: 650;
    text-decoration: none;
}

.brand-mark { display: inline-flex; }

.nav { flex: 1; padding: 0.75rem 0; }

.nav-group { padding: 0.35rem 0; }
.nav-group + .nav-group { border-top: 1px solid var(--sidebar-active-bg); margin-top: 0.35rem; }

.nav-group-title {
    display: block;
    padding: 0.5rem 1rem 0.25rem;
    font-size: 0.72rem;
    font-weight: 650;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--sidebar-muted);
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.55rem 1rem;
    color: var(--sidebar-text);
    text-decoration: none;
    font-size: 0.95rem;
    /* The rail is always there, transparent until active, so activating a
       link never shifts its text sideways. */
    border-left: 3px solid transparent;
}

.nav-link svg { flex: 0 0 auto; color: var(--sidebar-muted); }

.nav-link:hover { color: var(--sidebar-active-ink); background: var(--sidebar-active-bg); }
.nav-link:hover svg { color: var(--sidebar-active-ink); }

.nav-link.active {
    color: var(--sidebar-active-ink);
    background: var(--sidebar-active-bg);
    border-left-color: var(--accent-fill);
    font-weight: 550;
}

.nav-link.active svg { color: var(--accent-fill); }

.sidebar-foot {
    padding: 0.85rem 1rem;
    border-top: 1px solid var(--sidebar-active-bg);
}

.signout { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.who { color: var(--sidebar-muted); font-size: 0.9em; word-break: break-all; }
.signout .btn-link { color: var(--sidebar-muted); }
.signout .btn-link:hover { color: var(--sidebar-active-ink); }

/* Narrow screens: the sidebar collapses to an icon strip, no JS. */
@media (max-width: 820px) {
    .shell { grid-template-columns: 56px minmax(0, 1fr); }
    .brand { justify-content: center; padding: 0.95rem 0.5rem; }
    .brand-name, .nav-link span, .nav-group-title, .who { display: none; }
    .nav-link { justify-content: center; padding: 0.55rem 0; }
    .sidebar-foot { padding: 0.85rem 0.5rem; text-align: center; }
}

/* --- Layout -------------------------------------------------------------- */

main { max-width: 1100px; margin: 0 auto; padding: 1.75rem 1.5rem 4rem; }
main.centered { max-width: 900px; display: flex; flex-direction: column; justify-content: center; min-height: 100vh; }

main a { color: var(--accent); }

h1 { font-size: 1.5rem; margin: 0 0 1rem; }
h2 { font-size: 1.05rem; margin: 0 0 0.75rem; }

.muted { color: var(--muted); }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.25rem;
    margin-bottom: 1.25rem;
}

.card-narrow { max-width: 380px; margin: 0 auto 1.25rem; }

/* --- Forms --------------------------------------------------------------- */

label { display: block; margin: 0.9rem 0 0.3rem; font-weight: 550; font-size: 0.9em; }

input[type="text"], input[type="password"] {
    width: 100%;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--text);
    font-size: 1rem;
}

input:focus-visible, button:focus-visible, a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.btn {
    display: inline-block;
    padding: 0.5rem 0.95rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    font-size: 0.95rem;
    text-decoration: none;
    cursor: pointer;
}

.btn:hover { border-color: var(--accent); color: var(--accent); }

.btn-primary {
    width: 100%;
    margin-top: 1.25rem;
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    font-weight: 550;
}

.btn-primary:hover { filter: brightness(1.08); color: #fff; }

.btn-link {
    background: none;
    border: 0;
    padding: 0;
    color: var(--muted);
    cursor: pointer;
    font-size: 0.9em;
    text-decoration: underline;
}

.btn-link:hover { color: var(--accent); }

/* --- Flashes ------------------------------------------------------------- */

.flash {
    padding: 0.6rem 0.85rem;
    border-radius: var(--radius);
    border: 1px solid transparent;
    margin: 0 0 1rem;
}

.flash-success { background: var(--pass-bg); border-color: var(--pass); color: var(--pass); }
.flash-error   { background: var(--fail-bg); border-color: var(--fail); color: var(--fail); }
.flash a { color: inherit; }

/* --- Tables -------------------------------------------------------------- */

.table { width: 100%; border-collapse: collapse; }

.table th, .table td {
    text-align: left;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}

.table tbody tr:last-child th, .table tbody tr:last-child td { border-bottom: 0; }
.table th[scope="row"] { color: var(--muted); font-weight: 500; width: 34%; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Preflight ----------------------------------------------------------- */

.summary { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; }

.badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 650;
    letter-spacing: 0.02em;
}

.badge.pass { background: var(--pass-bg); color: var(--pass); }
.badge.warn { background: var(--warn-bg); color: var(--warn); }
.badge.fail { background: var(--fail-bg); color: var(--fail); }

.table-checks .cell-status { width: 62px; }
.table-checks .cell-name { width: 33%; font-weight: 550; }
.table-checks .cell-value { color: var(--muted); }

.hint {
    margin-top: 0.35rem;
    padding-left: 0.6rem;
    border-left: 2px solid var(--border);
    color: var(--text);
    font-size: 0.9em;
}

.row-fail .hint { border-left-color: var(--fail); }
.row-warn .hint { border-left-color: var(--warn); }

.trace { max-height: 20rem; overflow: auto; font-size: 0.8em; }

/* --- Dashboard (D100) ---------------------------------------------------- */

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.stat {
    display: flex;
    gap: 0.9rem;
    align-items: flex-start;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.1rem;
}

.stat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 8px;
    flex: 0 0 auto;
}

/* Icon tiles reuse the reserved status backgrounds at tint strength; the
   icons are decorative (aria-hidden), so these pairs only need to please. */
.stat-icon-spend     { background: var(--fail-bg); color: var(--accent); }
.stat-icon-suppliers { background: var(--pass-bg); color: var(--pass); }
.stat-icon-push      { background: var(--warn-bg); color: var(--warn); }

.stat-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.stat-label { font-size: 0.85rem; color: var(--muted); }
.stat-value { font-size: 1.45rem; font-weight: 650; line-height: 1.2; }
.stat-foot { font-size: 0.8rem; color: var(--muted); }

.panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1.25rem;
    align-items: start;
}

.panel-grid .card { margin-bottom: 0; }

/*
 * The spend chart. All geometry is SVG attributes computed server-side
 * (partials/spend-chart.php explains: the CSP blocks style="" attributes);
 * everything COLOUR lives here so the dark-mode token swap reaches it.
 */
.chart { display: block; width: 100%; height: auto; }
.chart-bar { fill: var(--accent-fill); }
line.chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-tick { fill: var(--muted); font-size: 11px; text-anchor: end; font-variant-numeric: tabular-nums; }
.chart-month { fill: var(--muted); font-size: 11px; text-anchor: middle; }

/*
 * Batch progress meter: one hue, two lightness steps (tint = reviewed,
 * solid = pushed, drawn over it from the same origin). Deliberately NOT
 * coral-vs-green: that pair measured ΔE 1.6 under protan simulation — see
 * the token comment at the top. The numbers ride in <title>/aria-label.
 */
.meter { display: block; width: 120px; max-width: 100%; height: 8px; }
.meter-track { fill: var(--border); }
.meter-reviewed { fill: var(--meter-tint); }
.meter-pushed { fill: var(--accent); }

/* --- Batch receipt table (D101) ------------------------------------------ */

.table-scroll { overflow-x: auto; }

.receipt-table td { vertical-align: middle; }
.receipt-table .cell-check { width: 28px; }
.rrow:hover td { background: var(--bg); }

/* Right-aligned, never wrapping: four icons and their forms stay one row. */
.row-actions { text-align: right; white-space: nowrap; width: 1%; }
.row-actions .inline-form { display: inline-block; }

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    background: none;
    border: 0;
    border-radius: var(--radius);
    color: var(--muted);
    cursor: pointer;
    vertical-align: middle;
}

.icon-btn:hover { color: var(--accent); background: var(--bg); }
.icon-btn[disabled] { opacity: 0.35; cursor: not-allowed; }
.icon-btn[disabled]:hover { color: var(--muted); background: none; }
/* Destructive stays quiet until hovered, like .btn-danger. */
.icon-danger:hover { color: var(--fail); background: var(--fail-bg); }

/*
 * The expanded detail row holds the full pre-D101 receipt card, unchanged.
 * The recessed background makes the card read as belonging to the row above.
 */
.receipt-detail > td { padding: 0.75rem; background: var(--bg); }
.receipt-detail .receipt { margin-bottom: 0; }

.bulk-bar {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

/* Screen-reader-only table header for the actions column. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* --- Milestone 2: batches, review table -------------------------------- */

.flash-warning { background: var(--warn-bg); border-color: var(--warn); color: var(--warn); }

.btn-inline { width: auto; margin-top: 0; }
.inline-form { display: inline-block; margin: 0; }

input[type="file"], input[type="date"], select {
    width: 100%;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--text);
    font-size: 0.95rem;
}

/* Fields the extractor could not fill, so the eye goes straight to them. */
input.missing { border-color: var(--warn); background: var(--warn-bg); }

.progress {
    height: 8px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
    margin: 0.5rem 0;
}

.progress-bar {
    height: 100%;
    width: 0;
    background: var(--accent);
    transition: width 0.2s ease;
}

.receipt-head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.receipt-name { word-break: break-all; }

/*
 * A pushed receipt is marked on the card itself, not only by its badge.
 *
 * A batch is a long vertical stack of near-identical cards, and the question
 * asked while scrolling it is "which of these are already filed?". A badge
 * answers that only once you have stopped and read it; an edge does it in
 * peripheral vision. The border replaces the transparent one below rather than
 * adding to it, so the card does not shift by 3px when the state changes.
 *
 * Colour is not the only signal — the header badge carries the word "pushed" —
 * because these two greens are close to indistinguishable under the common forms
 * of colour blindness.
 */
.receipt { border-left: 3px solid transparent; }
.receipt.is-pushed { border-left-color: var(--pass); }
.receipt.is-push-failed { border-left-color: var(--fail); }

/* Auto-fit grid: collapses to one column on a phone with no media query. */
.grid-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0 0.75rem;
    align-items: start;
}

/*
 * The edit fields sit inside a <fieldset> so a receipt already filed in ERPNext
 * can disable every control in one attribute (D90).
 *
 * That wrapper is otherwise the SINGLE grid item of .grid-form, which collapses
 * the whole form into one ~180px column — a narrow box against the left edge.
 *
 * `display: contents` was the first fix and is the wrong tool here. A <fieldset>
 * is precisely the element it cannot be relied on for: the UA gives it a special
 * layout box, engines have historically ignored `display` on it, and removing it
 * from the box tree has known accessibility-tree side effects — on the very
 * element carrying the `disabled` semantics that the whole guard depends on.
 *
 * So the wrapper stays a real box and is instead made transparent to the layout:
 * it spans every column of the outer grid, and repeats the same track definition
 * inside itself, so .field children lay out exactly as they did when they were
 * direct children of the form and `field-wide`'s `1 / -1` still resolves. The
 * four resets are the fieldset UA defaults; `min-inline-size` in particular
 * defaults to `min-content`, which is what makes an unstyled fieldset refuse to
 * shrink and is worth zeroing even when a grid span already stretches it.
 */
.grid-form > .field-group {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0 0.75rem;
    align-items: start;
    border: 0;
    margin: 0;
    padding: 0;
    min-inline-size: 0;
}

.field { min-width: 0; }
.field-tiny  { grid-column: span 1; }
.field-small { grid-column: span 1; }
.field-wide  { grid-column: 1 / -1; }

.field-actions {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.save-state { font-size: 0.9em; }
.save-ok   { color: var(--pass); }
.save-warn { color: var(--warn); }

.receipt-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 0.9rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--border);
}

.upload-hint { margin-top: 0.6rem; }

/* --- Milestone 3: CSV export -------------------------------------------- */

.template-tabs { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.9rem; }
.btn-current { border-color: var(--accent); color: var(--accent); font-weight: 600; }

/* The header row is long; wrap rather than clip it, since a truncated header is
   the thing you most want to read when checking column mapping. */
.csv-preview {
    max-height: 22rem;
    overflow: auto;
    font-size: 0.78em;
    white-space: pre-wrap;
    word-break: break-word;
}

.skipped { margin: 0; padding-left: 1.3rem; }
.skipped li { margin: 0.25rem 0; }

.steps { margin: 0 0 1rem; padding-left: 1.4rem; }
.steps li { margin: 0.3rem 0; }

/* --- Milestone 4: payload preview --------------------------------------- */

.payload {
    max-height: 30rem;
    overflow: auto;
    font-size: 0.8em;
    line-height: 1.45;
}

/*
 * Destructive action.
 *
 * Understated on purpose: it sits at the foot of every unpushed receipt, so a
 * loud red button on each row would make the whole batch page look alarming and
 * train the eye to ignore it. It reads as ordinary until hovered, and the
 * confirm dialog does the actual stopping.
 */
.receipt-destructive {
    margin-top: 0.5rem;
    padding-top: 0.75rem;
    border-top: 1px dashed var(--border);
}

.btn-danger { color: var(--fail); }

.btn-danger:hover {
    background: var(--fail-bg);
    border-color: var(--fail);
    color: var(--fail);
}
