:root {
    --ov-bg: #F3F5F4;
    --ov-surface: #FFFFFF;
    --ov-ink: #212B27;
    --ov-ink-muted: #66766F;
    --ov-line: #E1E7E4;
    --ov-teal: #2F6F62;
    --ov-teal-deep: #1F4E44;
    --ov-teal-wash: #E7F1EE;
    --ov-danger: #A6453B;
    --ov-danger-wash: #FBEDEB;
    /* The setup side of the shop: a slate that sits beside the teal
       without competing with it, and reads as "system" rather than as
       a warning. */
    --ov-admin: #4A5A72;
    --ov-admin-deep: #334054;
    --ov-admin-wash: #ECEFF4;
}

* { box-sizing: border-box; }
body {
    margin: 0;
    font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Arial, sans-serif;
    background: var(--ov-bg);
    color: var(--ov-ink);
}

/* --- App shell: header --- */
.app-header {
    background: var(--ov-surface);
    border-bottom: 1px solid var(--ov-line);
    padding: 14px 24px;
}
.app-header-inner {
    display: flex;
    align-items: center;
    gap: 12px;
}
.brand-mark { height: 34px; width: auto; flex-shrink: 0; }
.app-header-inner h1 {
    font-family: Georgia, 'Times New Roman', serif;
    margin: 0;
    font-size: 21px;
    font-weight: normal;
    letter-spacing: 0.2px;
    color: var(--ov-ink);
}
.app-header-inner h2 {
    margin: 2px 0 0;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--ov-ink-muted);
    text-align: left;
}

/* --- Login page --- */
.login-body { background: var(--ov-bg); min-height: 100vh; }
.login-wrapper {
    display: flex;
    justify-content: center;
    padding-top: 60px;
}
.login-box {
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-radius: 12px;
    width: 420px;
    box-shadow: 0 10px 24px rgba(31, 78, 68, 0.08);
    overflow: hidden;
}
.login-logo {
    display: block;
    height: 96px;
    width: auto;
    margin: 20px auto 4px;
}
.login-box-title {
    background: var(--ov-teal-wash);
    color: var(--ov-teal-deep);
    padding: 10px 16px;
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.form-row { display: flex; align-items: center; gap: 10px; padding: 12px 20px; }
.form-row label { width: 90px; font-weight: 600; color: var(--ov-ink); }
.form-row input { flex: 1; }
/* Two boxes sharing one labelled row (Vision VA: Distance / Near). Each half
   carries its own small caption, so the row's own label stays the heading. */
.form-row .split-field { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; }
.form-row .split-field .split-label {
    width: auto;
    flex: none;
    font-weight: 500;
    font-size: 12.5px;
    color: var(--ov-ink-muted);
}
.form-row .split-field input { flex: 1; min-width: 0; }
/* A label too long for the 90px column, so it doesn't wrap to two lines. */
.form-row label.wide { width: 130px; }
.form-buttons { text-align: center; padding: 15px 0 25px; }
.btn {
    display: inline-block;
    padding: 8px 18px;
    border: 1px solid var(--ov-line);
    border-radius: 6px;
    font-weight: 600;
    font-size: 13.5px;
    cursor: pointer;
    background: var(--ov-surface);
    color: var(--ov-ink);
    text-decoration: none;
}
.btn:hover { border-color: var(--ov-teal); color: var(--ov-teal-deep); }
.btn-green { background: var(--ov-teal); border-color: var(--ov-teal); color: white; }
.btn-green:hover { background: var(--ov-teal-deep); border-color: var(--ov-teal-deep); color: white; }
.form-error { color: var(--ov-danger); text-align: center; margin: 10px 20px 0; font-size: 13px; }

/* --- App shell: layout --- */
.app-layout { display: flex; background: var(--ov-bg); min-height: calc(100vh - 130px); }
.sidebar {
    width: 220px;
    flex-shrink: 0;
    background: var(--ov-surface);
    border-right: 1px solid var(--ov-line);
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 16px 10px;
}
.menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    color: var(--ov-ink);
    text-decoration: none;
    font-weight: 600;
    font-size: 13.5px;
    border-radius: 8px;
    border-left: 3px solid transparent;
}
.menu-item .menu-icon { font-size: 16px; width: 18px; text-align: center; flex-shrink: 0; }
.menu-item:hover { background: var(--ov-teal-wash); color: var(--ov-teal-deep); }
.menu-item.active { background: var(--ov-teal-wash); color: var(--ov-teal-deep); border-left-color: var(--ov-teal); }
/* Admin is the setup behind the shop, not one of the day's jobs, so it
   carries its own slate rather than the menu's teal -- the same way Exit
   carries the danger red. Slate and not amber or red: nothing here is a
   warning, it is simply a different kind of screen. */
.menu-admin { color: var(--ov-admin); }
.menu-admin .menu-icon { filter: grayscale(0.35); }
.menu-admin:hover { background: var(--ov-admin-wash); color: var(--ov-admin-deep); }
.menu-admin.active {
    background: var(--ov-admin-wash);
    color: var(--ov-admin-deep);
    border-left-color: var(--ov-admin);
}
.menu-exit {
    margin-top: 10px;
    padding-top: 16px;
    border-top: 1px solid var(--ov-line);
    border-radius: 0;
    color: var(--ov-danger);
}
.menu-exit:hover { background: var(--ov-danger-wash); color: var(--ov-danger); }
.main-panel { flex: 1; min-width: 0; padding: 30px; background: var(--ov-bg); overflow-x: auto; }
.main-panel h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--ov-ink-muted); margin: 0 0 14px; font-weight: 700; }
.placeholder-note {
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    padding: 18px 22px;
    border-radius: 10px;
    max-width: 520px;
    color: var(--ov-ink-muted);
}

/* --- Module tile grid (Accounts / Other Jobs / Reports / Inventory hubs) --- */
.job-tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 16px;
    max-width: 900px;
    margin-bottom: 32px;
}
.job-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 22px 12px;
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-radius: 12px;
    color: var(--ov-ink);
    text-decoration: none;
    font-weight: 600;
    font-size: 13.5px;
    text-align: center;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.job-tile-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: var(--ov-teal-wash);
    font-size: 19px;
}
.job-tile:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(31, 78, 68, 0.14); border-color: var(--ov-teal); }
.job-tile.disabled { color: var(--ov-ink-muted); cursor: not-allowed; opacity: 0.6; }
/* A tile whose job moved to the Admin screen. It reads as a signpost and
   not as a fault: the reader knew where this was, so leaving a gap where
   it stood would send them hunting. Its label borrows .job-tile-soon and
   the slate the Admin menu item carries, so "In Admin" and the item that
   opens it are visibly the same thing. */
.job-tile-moved { cursor: default; }
.job-tile-moved .job-tile-soon { color: var(--ov-admin); }
.job-tile.disabled .job-tile-icon { background: #EEF0EF; }
.job-tile.disabled:hover { transform: none; box-shadow: none; border-color: var(--ov-line); }

.app-footer {
    display: flex;
    justify-content: space-between;
    padding: 10px 24px;
    background: var(--ov-surface);
    border-top: 1px solid var(--ov-line);
    font-size: 12.5px;
    color: var(--ov-ink-muted);
}

/* --- Employee Management permit grid --- */
.permit-grid { width: 100%; border-collapse: collapse; background: var(--ov-surface); }
.permit-grid th, .permit-grid td { border: 1px solid var(--ov-line); padding: 8px 10px; font-size: 13px; text-align: left; }
.permit-grid th { background: var(--ov-teal-wash); color: var(--ov-teal-deep); }
.permit-grid td:nth-child(n+4):nth-child(-n+8) { text-align: center; color: var(--ov-teal-deep); font-weight: 700; }
.inactive-row td { opacity: 0.5; }

/* --- Global form controls (the .invoice-box print pages are read-only,
   no inputs live there, so this applies everywhere else without needing
   an exclusion) --- */
input, select, textarea {
    font-family: inherit;
    font-size: 13.5px;
    padding: 7px 10px;
    border: 1px solid var(--ov-line);
    border-radius: 6px;
    background: var(--ov-surface);
    color: var(--ov-ink);
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--ov-teal);
    box-shadow: 0 0 0 3px var(--ov-teal-wash);
}
label { color: var(--ov-ink); }

/* --- Sales module: shared page shell --- */
.sales-page { max-width: 900px; margin: 20px auto; padding: 0 20px; font-family: 'Segoe UI', Arial, sans-serif; color: var(--ov-ink); }
/* Master-file screens list far more columns than a sale does (an item has
   eleven). They keep the same shell and only widen it, so the table can
   breathe instead of wrapping every heading. */
.sales-page-wide { max-width: 1250px; }
.sales-page h1 { font-size: 21px; font-weight: 700; }
.sales-page a { color: var(--ov-teal-deep); }
.sales-page table, .main-panel table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-radius: 8px;
    overflow: hidden;
}
.sales-page table th, .sales-page table td, .main-panel table th, .main-panel table td {
    border: 1px solid var(--ov-line);
    padding: 8px 10px;
    text-align: left;
}
.sales-page table th, .main-panel table th { background: var(--ov-teal-wash); color: var(--ov-teal-deep); font-weight: 700; }
/* Amounts sit on the right so the rupees and cents line up down a column;
   tabular figures give every digit the same width, which is what makes
   1,300,000.00 and 900.00 end in the same place. Written as table td.num so
   it outranks the text-align: left just above on every screen, not only
   inside .sales-page and .main-panel. */
table td.num, table th.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Reports are headed like a printed report: the title centered, and the
   column headings centered over their columns. Only the first row, and only
   when it is all headings -- a summary table's first row is a label beside
   its figure, and the Total row at the foot keeps its figure on the right. */
.report-page > h2, .report-page > .no-print > h1 { text-align: center; }
.report-page table tr:first-child:not(:has(td)) > th { text-align: center; }
.sales-card { background: var(--ov-surface); border: 1px solid var(--ov-line); border-radius: 10px; padding: 18px 20px; margin-bottom: 20px; }
.sales-card h2 { margin-top: 0; }
.sales-msg-success { color: #1F6E4A; background: #E7F5EC; border: 1px solid #C6E7D4; padding: 8px 12px; border-radius: 6px; }
.sales-msg-error { color: var(--ov-danger); background: var(--ov-danger-wash); border: 1px solid #F0D3CE; padding: 8px 12px; border-radius: 6px; }
.wizard-steps { list-style: none; display: flex; gap: 8px; padding: 0; margin: 0 0 20px; }
.wizard-steps li { padding: 6px 14px; background: var(--ov-bg); border: 1px solid var(--ov-line); border-radius: 20px; font-size: 12.5px; font-weight: 700; color: var(--ov-ink-muted); }
.wizard-steps li.active { background: var(--ov-teal); border-color: var(--ov-teal); color: #fff; }
.wizard-steps li.done { background: var(--ov-teal-wash); border-color: var(--ov-teal-wash); color: var(--ov-teal-deep); }

/* --- Type-ahead search --- */
.search-box { position: relative; max-width: 420px; }
.search-box input[type="text"] { width: 100%; box-sizing: border-box; }
.search-results {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 20;
    background: var(--ov-surface); border: 1px solid var(--ov-line); border-top: none;
    border-radius: 0 0 8px 8px;
    max-height: 220px; overflow-y: auto;
    box-shadow: 0 8px 16px rgba(31, 78, 68, 0.1);
}
.search-result-item { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid var(--ov-line); font-size: 13px; }
.search-result-item:hover { background: var(--ov-teal-wash); }
.search-result-item small { display: block; color: var(--ov-ink-muted); }
.selected-box {
    margin-top: 8px; padding: 8px 10px; background: var(--ov-teal-wash);
    border: 1px solid #CFE4DF; border-radius: 6px; font-size: 13px; color: var(--ov-teal-deep);
}

/* --- Invoice / print --- */
.invoice-box { background: #fff; padding: 30px; max-width: 800px; margin: 20px auto; border: 1px solid #ccc; }
.invoice-header-row { display: flex; justify-content: space-between; font-size: 13px; font-weight: bold; margin-bottom: 8px; }
/* The number the document is known by, at the same 16px the print sheets
   give it. Needed here as well as in print_b5.css because the service note
   is the one document of this family that loads no print sheet at all. */
.invoice-header-row > div.doc-no { font-size: 16px; }
.invoice-letterhead { text-align: center; padding-bottom: 4px; }
.invoice-letterhead .doc-logo { display: block; height: 34px; width: auto; margin: 0 auto 6px; }
.invoice-letterhead h1 { margin: 0; font-family: Georgia, serif; font-size: 22px; }
.invoice-letterhead p { margin: 2px 0; font-size: 12px; color: #444; }
.invoice-title { text-align: center; text-decoration: underline; font-size: 15px; margin: 10px 0 20px; }
.invoice-meta { display: flex; justify-content: space-between; margin-bottom: 20px; font-size: 13px; }
.invoice-box table { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
.invoice-box table th, .invoice-box table td { border: 1px solid #999; padding: 6px 10px; font-size: 13px; }
.invoice-box table th { background: #eee; }
.invoice-totals { width: 100%; margin-left: auto; font-size: 13px; }
.invoice-totals tr td:first-child { font-weight: normal; }
.invoice-totals .grand td { font-size: 14px; font-weight: bold; }
.invoice-signature { margin-top: 50px; text-align: left; font-size: 13px; }
.invoice-remark-lines { margin-top: 20px; }
.invoice-remark-lines div { border-bottom: 1px dashed #666; height: 22px; font-size: 13px; padding-top: 2px; }
.invoice-footer { text-align: center; margin-top: 20px; font-size: 12px; color: #444; }
/* --- Scan-to-add box (Step 2 of a sale) --- */
.scan-form { margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--ov-line); }
.scan-form input { width: 320px; max-width: 100%; font-family: monospace; font-size: 15px; }
.scan-hint { margin: 6px 0 0; font-size: 12.5px; color: var(--ov-ink-muted); }
/* Repricing a line in place, in the Items table. Kept on one line so the
   row stays the same height as the read-only rows around it. */
.price-form { display: flex; align-items: center; gap: 6px; margin: 0; }
.price-cur { color: var(--ov-ink-muted); font-size: 13px; }
.price-form input { width: 100px; text-align: right; }
.price-form .btn { padding: 4px 10px; font-size: 12.5px; }
.add-item-hint { margin: 0 0 12px; font-size: 12.5px; color: var(--ov-ink-muted); }
/* Search box above a list of records (customers today). */
.list-search { display: flex; gap: 8px; align-items: center; margin: 0 0 10px; flex-wrap: wrap; }
.list-search input { width: 340px; max-width: 100%; }
.list-search-hint { margin: 0 0 10px; font-size: 12.5px; color: var(--ov-ink-muted); }
/* Emailed report preview — monospace so the figure columns line up the
   way they do in the mail itself. */
.report-body {
    font-family: 'Consolas', 'Courier New', monospace;
    font-size: 12.5px;
    white-space: pre-wrap;
    background: var(--ov-bg);
    border: 1px solid var(--ov-line);
    border-radius: 6px;
    padding: 14px;
    overflow-x: auto;
}

/* Money panel (payment screen, Money Position) */
.money-warn { color: var(--ov-danger); }
.money-overdue { background: var(--ov-danger-wash); }
.money-overdue td:first-child { font-weight: 700; color: var(--ov-danger); }

/* Item-code lookup rows (Item Codes form, Goods Received bench) */
.code-taken { color: var(--ov-danger); background: var(--ov-danger-wash); font-weight: 600; }
.code-free { color: var(--ov-ink-muted); }

/* Camera scanning (stock take, on a phone). Capped so the viewfinder can't
   push the count table off the screen on a small display. */
.camera-scan-panel { margin: 0 0 22px; }
.camera-scan-panel video {
    width: 100%;
    max-width: 420px;
    max-height: 45vh;
    background: #000;
    border-radius: 8px;
    display: block;
}

/* The line a scan matched, so the item actually handed back is the obvious
   one to act on when a sale has several. */
.scan-match { background: var(--ov-teal-wash); }
.scan-match td:first-child { box-shadow: inset 3px 0 0 var(--ov-teal); font-weight: 600; }

.no-print { margin: 20px auto; max-width: 800px; }

/* --- Barcode label sheet --- */
/* Change these two to match your label stock; everything else follows —
   and change LABEL_WIDTH_MM/LABEL_HEIGHT_MM in inventory/barcodes.py to
   match, since the symbol is rendered to fit the label rather than scaled
   into it. 20x10mm carries the bars, the item code and the price and
   nothing else; there is no room for the description line. */
.label-sheet {
    --label-w: 20mm;
    --label-h: 10mm;
    display: flex;
    flex-wrap: wrap;
    gap: 2mm;
    background: #fff;
    padding: 5mm;
}
.label {
    width: var(--label-w);
    height: var(--label-h);
    border: 1px dotted #bbb;   /* cutting guide — see the print rules below */
    padding: 0.5mm;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    page-break-inside: avoid;
    break-inside: avoid;
}
/* No max-width scaling: barcodes.py renders the symbol at a width that
   already fits, and letting CSS shrink it would thin the bars past what a
   scanner reads. */
.label-barcode { display: block; height: auto; }
.label-code {
    font-size: 5pt;
    line-height: 1.05;
    font-weight: bold;
    font-family: monospace;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
}
.label-price { font-size: 4.5pt; line-height: 1.05; }

/* Send-to-lab WhatsApp screens */
.wa-preview {
    background: var(--ov-teal-wash);
    border: 1px solid var(--ov-line);
    border-radius: 8px;
    padding: 14px 16px;
    margin: 0 0 14px;
    font-family: 'Consolas', 'Courier New', monospace;
    font-size: 14px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-x: auto;
}
.wa-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.wa-note { font-size: 13px; color: #666; margin: 12px 0 0; }
.wa-warn { font-size: 13px; color: #b00020; margin: 10px 0 0; }

@media print {
    body { background: #fff; }
    .no-print { display: none !important; }
    .invoice-box { border: none; margin: 0; padding: 0; }
    /* The dotted guides stay: labels get cut by hand off plain sticker
       sheets. On pre-cut/die-cut stock, set this to `border: none`. */
    .label-sheet { padding: 0; }
}

/* --- Number inputs ---
   Money and quantity fields are typed, never dialled. The spinner arrows
   only crowd the box and invite a stray click, and a focused number input
   takes the mouse wheel as a value change — static/js/number_input.js
   handles that half. */
input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* --- Chart of accounts: the transaction code list ---
   Seventy-odd codes read as a wall when listed flat, so the page groups
   them by kind and marks who picks each one. The pill carries that in
   colour as well as words: a code the counter never sees should look
   different at a glance from one they pick every day. */
.code-page .code-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.code-page .code-filter {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding-top: 14px;
    border-top: 1px solid var(--ov-line);
}
.code-page .code-filter label {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ov-ink-muted);
}
.code-page .code-group-head {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
}
.code-page .code-prefix {
    font-family: 'Consolas', 'Courier New', monospace;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.5px;
    background: var(--ov-teal);
    color: #fff;
    padding: 2px 8px;
    border-radius: 4px;
}
.code-page .code-guidance {
    color: var(--ov-ink-muted);
    font-size: 12.5px;
}
.code-page .code-hint {
    color: var(--ov-ink-muted);
    font-size: 12.5px;
    margin-top: 10px;
}
.code-page details summary { cursor: pointer; }
.usage-pill {
    display: inline-block;
    font-size: 11.5px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 20px;
    white-space: nowrap;
    border: 1px solid var(--ov-line);
    color: var(--ov-ink-muted);
    background: var(--ov-bg);
}
.usage-pill.voucher {
    border-color: var(--ov-teal);
    color: var(--ov-teal-deep);
    background: var(--ov-teal-wash);
}

/* --- Financial statements ---
   A statement is read down its number columns, so the figures are right
   aligned and tabular: digits that do not line up are digits nobody can
   scan. The month picker is deliberately identical on the section page
   and on each statement, so choosing a month never feels like a
   different control depending on where you are. */
.statement-page .statement-period {
    color: var(--ov-ink-muted);
    font-size: 13px;
    margin-top: -8px;
}
.statement-month {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}
.statement-month label {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ov-ink-muted);
}
.statement-month-note { font-size: 12.5px; color: var(--ov-ink-muted); }
.statement-table td.num, .statement-table th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.statement-table td.negative { color: var(--ov-danger); }
.statement-table tr.statement-total td {
    font-weight: 700;
    border-top: 2px solid var(--ov-teal);
    background: var(--ov-teal-wash);
}

/* Section headings and blank lines inside a statement. Every expense line
   in the chart is printed even when empty — a blank line says nothing was
   spent, which is information — but the empty ones are dimmed so the eye
   lands on the months that had figures. */
.statement-table tr.statement-section td {
    font-weight: 700;
    color: var(--ov-teal-deep);
    background: var(--ov-bg);
    padding-top: 10px;
}
.statement-table tr.statement-subtotal td {
    font-weight: 700;
    border-top: 1px solid var(--ov-teal);
}
.statement-table tr.statement-empty td { color: var(--ov-ink-muted); opacity: 0.55; }

/* The plain-words reading of a statement. Set larger than the table it
   sits above, because it is meant to be read first and the table only if
   a figure in it raises a question. */
.statement-comment { border-left: 3px solid var(--ov-teal); }
.statement-comment p {
    margin: 0;
    font-size: 15px;
    line-height: 1.65;
    color: var(--ov-ink);
}

/* A reconciling item that has been outstanding too long. Marked in the
   table as well as counted in the banner above it, because the count tells
   you there is a problem and the row tells you which one. */
.statement-table tr.statement-stale td {
    background: var(--ov-danger-wash);
    color: var(--ov-danger);
}
.statement-table tr.statement-stale td.num { font-weight: 700; }

/* --- Idle auto-logout warning --- */
.idle-warning {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 900;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: 380px;
    padding: 12px 16px;
    background: var(--ov-danger-wash);
    border: 1px solid var(--ov-danger);
    border-radius: 6px;
    font-size: 13px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);
}
/* .idle-warning sets display, which would otherwise beat the hidden attribute. */
.idle-warning[hidden] { display: none; }
.form-notice { color: var(--ov-teal-deep); text-align: center; margin: 10px 20px 0; font-size: 13px; }

/* --- Notice board (dashboard) ---
   Severity is carried by the left stripe and the figure colour, so the
   things needing action now read from across the counter. Amber is a
   third colour rather than a lighter red: "watch this" and "do this now"
   are different messages and must not look like the same one dimmed. */
:root {
    --ov-warn: #8A5A16;
    --ov-warn-line: #C08A2E;
    --ov-warn-wash: #F7EEDD;
    /* The green already used for a saved-successfully message, reused so
       a met target reads as the same "good" the rest of the app uses. */
    --ov-good: #1F6E4A;
}
.notice-welcome { font-size: 13px; color: var(--ov-ink-muted); margin: 0 0 16px; }
.notice-welcome a { color: var(--ov-teal-deep); margin-left: 8px; }

.notice-board { display: flex; flex-direction: column; gap: 8px; max-width: 900px; }
.notice-board-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 2px; }
.notice-board-head h2 { margin: 0; }
.notice-board-stamp { margin-left: auto; font-size: 11px; color: var(--ov-ink-muted); }
.notice-pill { font-size: 11px; font-weight: 700; padding: 2px 9px; border-radius: 10px; }
.notice-pill-critical { background: var(--ov-danger-wash); color: var(--ov-danger); }
.notice-pill-warning { background: var(--ov-warn-wash); color: var(--ov-warn); }

.notice {
    display: flex;
    align-items: flex-start;
    gap: 18px;
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-left: 4px solid var(--ov-line);
    border-radius: 3px;
    padding: 12px 16px;
}
.notice-critical { border-left-color: var(--ov-danger); }
.notice-warning { border-left-color: var(--ov-warn-line); }
.notice-info { border-left-color: var(--ov-teal); }
.notice-main { flex: 1; min-width: 0; }
.notice-title { font-weight: 600; font-size: 14px; color: var(--ov-ink); }
.notice-code {
    font-family: Consolas, 'Courier New', monospace;
    font-size: 10px;
    color: var(--ov-ink-muted);
    border: 1px solid var(--ov-line);
    border-radius: 3px;
    padding: 0 4px;
    margin-left: 6px;
    vertical-align: 1px;
}
.notice-detail { font-size: 12px; color: var(--ov-ink-muted); margin-top: 3px; }
.notice-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 8px; }
.notice-actions a { font-size: 12px; font-weight: 600; color: var(--ov-teal); text-decoration: none; border-bottom: 1px solid #BCD5CE; }
.notice-actions a:hover { color: var(--ov-teal-deep); }
.notice-actions form { margin: 0; }
.notice-snooze {
    background: none;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: 12px;
    color: var(--ov-ink-muted);
    cursor: pointer;
    border-bottom: 1px dotted var(--ov-line);
}
.notice-snooze:hover { color: var(--ov-ink); }

.notice-figure { text-align: right; flex-shrink: 0; align-self: center; }
.notice-figure-value { display: block; font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }
.notice-critical .notice-figure-value { color: var(--ov-danger); }
.notice-warning .notice-figure-value { color: var(--ov-warn); }
.notice-info .notice-figure-value { color: var(--ov-teal-deep); }
.notice-figure-caption { font-size: 10px; color: var(--ov-ink-muted); text-transform: uppercase; letter-spacing: 0.05em; }

/* The target bar. The fill is the month's takings; the red mark is where
   the month should have got to by today, so the gap between them is the
   whole message and needs no reading. */
.notice-progress { margin-top: 9px; }
.notice-bar { position: relative; height: 9px; background: #E8ECEA; border-radius: 5px; }
.notice-bar-fill { position: absolute; top: 0; bottom: 0; left: 0; background: var(--ov-teal); border-radius: 5px; }
/* Three states, not two. Red the moment the month falls behind where it
   should be by today, green once the target is met, and the ordinary teal
   in between — a bar that were red for twenty-nine days of every month
   would stop meaning anything by the third. */
.notice-bar-behind { background: var(--ov-danger); }
.notice-bar-on_pace { background: var(--ov-teal); }
.notice-bar-met { background: var(--ov-good); }
.notice-bar-pace { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--ov-danger); }
.notice-bar-legend { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 5px; font-size: 11px; color: var(--ov-ink-muted); }
.notice-behind { color: var(--ov-danger); font-weight: 600; }

/* A message somebody pinned by hand. Deliberately not a stripe-and-figure
   notice: it is a person talking, not a measurement, and it should not
   look like something the system worked out. */
.notice-pinned {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    background: var(--ov-teal-wash);
    border: 1px solid #BCD5CE;
    border-radius: 3px;
    padding: 11px 16px;
}
.notice-pinned-mark { font-size: 14px; line-height: 1.5; flex-shrink: 0; }
.notice-pinned-text { font-size: 14px; font-weight: 600; color: var(--ov-teal-deep); }
.notice-pinned-by { font-size: 11px; color: var(--ov-ink-muted); margin-top: 2px; }

.notice-empty {
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-left: 4px solid var(--ov-teal);
    border-radius: 3px;
    padding: 14px 16px;
    margin: 0;
    font-size: 13px;
    color: var(--ov-ink-muted);
}

/* The count of things needing action now, beside every screen's Dashboard
   link. There is no base template, so this rides on the two partials that
   between them reach every window. */
.notice-badge {
    display: inline-block;
    min-width: 17px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--ov-danger);
    color: #FFFFFF;
    font-size: 11px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
}

/* --- Monthly bills ---
   The month grid reads by its blanks as much as its figures, so status is
   a pill rather than a word in a column of words, and a row with nothing
   recorded is greyed rather than left empty. */
.bill-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.bill-bar-spacer { flex: 1 1 auto; }
.bill-month-form { display: flex; align-items: center; gap: 8px; margin: 0; }
.bill-month-form label { font-size: 12.5px; color: var(--ov-ink-muted); }
.bill-table-wrap { overflow-x: auto; }
.bill-table { width: 100%; }
.bill-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.bill-supplier { display: block; font-size: 11.5px; color: var(--ov-ink-muted); }
.bill-basis { font-size: 12.5px; }
.bill-none { color: var(--ov-ink-muted); }
.bill-doc { display: block; font-size: 12px; }
.bill-retired td { color: var(--ov-ink-muted); }
.bill-total td { border-top: 2px solid var(--ov-line); font-weight: 600; }
.bill-empty { color: var(--ov-ink-muted); margin: 0; }
.bill-foot-note { font-size: 12.5px; color: var(--ov-ink-muted); margin: 12px 0 0; }
.bill-capture { margin: 14px 0 18px; }
.bill-inline-form { display: inline; margin: 0; }
.bill-link-button {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--ov-danger);
    cursor: pointer;
    text-decoration: underline;
}
.bill-pill {
    display: inline-block;
    font-size: 11.5px;
    font-weight: 700;
    padding: 2px 9px;
    border-radius: 20px;
    white-space: nowrap;
    border: 1px solid var(--ov-line);
    color: var(--ov-ink-muted);
    background: var(--ov-bg);
}
.bill-pill-paid { border-color: var(--ov-good); color: var(--ov-good); background: #E7F5EC; }
.bill-pill-unpaid { border-color: var(--ov-warn-line); color: var(--ov-warn); background: var(--ov-warn-wash); }
.bill-pill-overdue { border-color: var(--ov-danger); color: var(--ov-danger); background: var(--ov-danger-wash); }

/* The tax calendar borrows the bill register's table and pills. Red is
   the same red the notice board turns: late, or within the last few days. */
.tax-month td { font-weight: 700; background: var(--ov-bg); padding-top: 10px; }
.tax-code { font-variant-numeric: tabular-nums; letter-spacing: 0.5px; }
.tax-actions a { margin-right: 8px; }
.tax-facts th { text-align: left; padding-right: 18px; font-weight: 600; }
.tax-restore { margin-top: 10px; }
.tax-pill-done { border-color: var(--ov-good); color: var(--ov-good); background: #E7F5EC; }
.tax-pill-this_month { border-color: var(--ov-warn-line); color: var(--ov-warn); background: var(--ov-warn-wash); }
.tax-pill-due_soon,
.tax-pill-overdue { border-color: var(--ov-danger); color: var(--ov-danger); background: var(--ov-danger-wash); }

/* A tile for a module that is built but not open yet. Reads as a promise
   rather than as a permission the reader is missing. */
.job-tile-soon {
    display: block;
    margin-top: 4px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--ov-teal);
}
.coming-soon { background: var(--ov-surface); border: 1px solid var(--ov-line); border-radius: 10px; padding: 28px 30px; max-width: 620px; }
.coming-soon h2 { margin: 4px 0 10px; }
.coming-soon-eyebrow { margin: 0; font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ov-teal); }
.coming-soon-note { margin: 0 0 18px; color: var(--ov-ink-muted); max-width: 60ch; }

/* --- Petty cash: a reimbursement the float has not been told about --- */
.float-gap { border-left: 4px solid var(--ov-warn-line); }
.float-gap h2 { color: var(--ov-warn); }

/* ---- Help page ------------------------------------------------------ */
/* Its own block because the help screen is prose, which nothing else in
   the app is: everywhere else a page is a form or a table. */
.help-page { max-width: 860px; }
.help-title { margin: 0 0 4px; }
.help-lead { color: var(--ov-ink-muted); margin: 0 0 18px; }

.help-contents {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    padding: 12px 16px;
    margin-bottom: 18px;
    background: var(--ov-teal-wash);
    border: 1px solid var(--ov-line);
    border-radius: 6px;
}
.help-contents a { color: var(--ov-teal-deep); font-weight: 600; }

.help-page .sales-card { margin-bottom: 18px; }
.help-page h2 { margin-top: 0; }
.help-page h3 {
    margin: 18px 0 6px;
    font-size: 0.95rem;
    color: var(--ov-teal-deep);
}
.help-page p { line-height: 1.55; }

.help-steps, .help-list { line-height: 1.55; padding-left: 20px; }
.help-steps li, .help-list li { margin-bottom: 8px; }

.help-flow {
    padding: 10px 14px;
    background: var(--ov-teal-wash);
    border-left: 3px solid var(--ov-teal);
    border-radius: 4px;
    font-weight: 600;
}

.help-table { border-collapse: collapse; width: 100%; margin: 10px 0 4px; }
.help-table th, .help-table td {
    border: 1px solid var(--ov-line);
    padding: 7px 10px;
    text-align: left;
    vertical-align: top;
}
.help-table th {
    background: var(--ov-teal-wash);
    font-size: 0.85rem;
    color: var(--ov-ink-muted);
}

@media (max-width: 700px) {
    .help-contents { gap: 6px 12px; }
    .help-table { font-size: 0.9rem; }
}

/* ---- Scanned prescription on the order form -------------------------- */
.scan-panel {
    margin: 14px 0 18px;
    padding: 12px 14px;
    background: var(--ov-teal-wash);
    border: 1px solid var(--ov-line);
    border-radius: 6px;
}
.scan-panel-title { font-weight: 600; display: block; margin-bottom: 2px; }
.scan-panel-hint {
    margin: 0 0 8px;
    font-size: 0.85rem;
    color: var(--ov-ink-muted);
}

.scan-preview { margin-top: 12px; }
.scan-preview-head {
    margin: 0 0 8px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--ov-teal-deep);
}
.scan-thumb-strip { display: flex; flex-wrap: wrap; gap: 12px; }
.scan-thumb { width: 130px; }
.scan-thumb a {
    display: block;
    border: 1px solid var(--ov-line);
    border-radius: 4px;
    background: var(--ov-surface);
    overflow: hidden;
}
/* contain, not cover: a cropped top strip of an A4 sheet cannot show
   that the scan went in upside down or came out blank, which is the
   only reason the thumbnail is here. */
.scan-thumb img {
    display: block;
    width: 100%;
    height: 170px;
    object-fit: contain;
    background: var(--ov-bg);
}
.scan-thumb-pdf {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 170px;
    font-weight: 700;
    color: var(--ov-ink-muted);
    letter-spacing: 1px;
}
.scan-thumb-name {
    display: block;
    margin-top: 4px;
    font-size: 0.75rem;
    color: var(--ov-ink-muted);
    /* anywhere, not break-all: a long scanner filename still wraps, but
       "51 KB" is not split down the middle. */
    overflow-wrap: anywhere;
}
.scan-thumb-size {
    display: block;
    font-size: 0.72rem;
    color: var(--ov-ink-muted);
}

/* The saved scans, on the printed order form. Screen only — the lab's
   copy is the keyed sheet, and printing a photograph of the paper it came
   from wastes the shop's ink saying nothing new. */
.scan-kept { margin-top: 14px; }
.scan-kept h3 { font-size: 0.95rem; margin: 0 0 8px; }

/* The two ways a scan gets in: the scanner's file, or the phone's camera.
   Side by side because they are alternatives, not steps. */
.scan-choices { display: flex; flex-wrap: wrap; gap: 14px; }
.scan-choice {
    flex: 1 1 280px;
    padding: 10px 12px;
    background: var(--ov-surface);
    border: 1px solid var(--ov-line);
    border-radius: 5px;
}
.scan-choice-label { display: block; font-weight: 600; margin-bottom: 6px; }
.scan-choice input[type="file"] { max-width: 100%; }
.scan-choice-note {
    display: block;
    margin-top: 6px;
    font-size: 0.78rem;
    color: var(--ov-ink-muted);
}

/* Download rather than print: the sheet above is the lab's copy, and a
   photograph of the handwriting it was read from adds nothing to it. This
   is how a copy gets off the system instead. */
.scan-thumb-download {
    display: inline-block;
    margin-top: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--ov-teal-deep);
}

/* The in-page camera. A live frame and a shutter, because the file
   input's capture attribute is only a hint and the counter PC ignores it
   -- that button opened the same picker as the scanner beside it. */
.scan-choice-camera { display: flex; flex-direction: column; }

.camera-stage {
    margin: 8px 0;
    border: 2px solid var(--ov-teal);
    border-radius: 5px;
    background: #000;
    overflow: hidden;
    /* A sheet of paper is taller than it is wide; this keeps the frame
       from collapsing before the stream reports its size. */
    aspect-ratio: 4 / 3;
}
.camera-video { display: block; width: 100%; height: 100%; object-fit: contain; }

.camera-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.camera-buttons .btn { padding: 6px 12px; font-size: 0.85rem; }
/* .btn sets display: inline-block, which beats the browser's own
   [hidden] { display: none } -- so without this every button shows at
   once however the script sets .hidden. */
.camera-buttons .btn[hidden] { display: none; }

.camera-note {
    margin: 8px 0 0;
    font-size: 0.8rem;
    color: var(--ov-teal-deep);
}
.camera-note-bad { color: var(--ov-danger); font-weight: 600; }

/* --- The shortcut bar ----------------------------------------------
   A strip under each window's header, listing whatever the admin put on
   it. There is no base template, so this rides on the partial included
   at the top of every screen, the way .notice-badge rides on the two
   that reach every window between them.

   It scrolls sideways rather than wrapping: a bar that grows to three
   rows on a narrow screen pushes the actual work below the fold, and
   the whole point of it is to stay out of the way. */
.shortcut-bar {
    background: var(--ov-surface);
    border-bottom: 1px solid var(--ov-line);
    overflow-x: auto;
}
.shortcut-bar-inner {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    white-space: nowrap;
}
.shortcut {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--ov-line);
    border-radius: 999px;
    background: var(--ov-surface);
    color: var(--ov-ink);
    text-decoration: none;
    font-weight: 600;
    font-size: 12.5px;
    flex-shrink: 0;
}
a.shortcut:hover { border-color: var(--ov-teal); background: var(--ov-teal-wash); color: var(--ov-teal-deep); }
.shortcut.active {
    background: var(--ov-teal-wash);
    border-color: var(--ov-teal);
    color: var(--ov-teal-deep);
}
.shortcut .menu-icon { font-size: 14px; width: auto; }

/* The preview on the settings screen, where the pills are not links. */
.shortcut-preview { display: flex; flex-wrap: wrap; gap: 6px; }
.shortcut-order { width: 64px; }

/* Print sheets do not carry the bar at all -- this is the second belt,
   for a screen printed straight off the browser. */
@media print {
    .shortcut-bar { display: none; }
}

/* --- Admin: the line under each section heading. The page is a door to
   screens that decide how the shop is set up rather than what it did
   today, and a tile's two words can't say which is which -- so each
   group gets one sentence. The Django admin group gets the warned
   variant, because that is the one tile with no checks behind it. --- */
.admin-note { margin: -6px 0 14px; max-width: 70ch; font-size: 13px; color: var(--ov-ink-muted); }
.admin-note-warn { border-left: 3px solid var(--ov-warn-line); padding-left: 10px; color: var(--ov-warn); }
