InvoiceParser/wwwroot/css/style.css
2026-09-16 13:09:19 -07:00

970 lines
29 KiB
CSS

/* Shared styles - ported from the invoiceProject ASP pages (highlight #6699CC). */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #333;
color: #eee;
font-family: Arial, sans-serif;
font-size: 13px;
}
h1 {
display: flex;
align-items: center;
background: #444;
color: #6699CC;
padding: 8px 16px;
font-size: 16px;
border-bottom: 1px solid #555;
}
h1 a { color: #aaa; font-size: 12px; font-weight: normal; margin-left: 16px; text-decoration: none; }
h1 a:hover { color: #eee; }
#pageMode { margin-left: 6px; }
#btnTogglePreview, #btnViewParsed {
display: none;
background: #555;
color: #eee;
border: 1px solid #666;
border-radius: 3px;
padding: 3px 10px;
font-size: 11px;
cursor: pointer;
}
#btnViewParsed { margin-left: auto; }
#btnTogglePreview { margin-left: 6px; }
#btnTogglePreview:hover, #btnViewParsed:hover { border-color: #6699CC; color: #6699CC; }
body.review-page #btnTogglePreview, body.review-page #btnViewParsed { display: inline-block; }
/* The review screen owns the whole viewport: nothing outside the preview
and the line-item table scrolls, so the form never needs a browser zoom-out. */
body.review-page { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
body.review-page h1 { flex-shrink: 0; }
/* Two-column layout */
#layout {
display: none;
gap: 0;
padding: 10px;
flex: 1;
min-height: 0;
}
#leftPanel {
flex: 0 0 38%;
min-width: 0;
display: flex;
flex-direction: column;
gap: 8px;
}
#leftPanel.collapsed, #leftPanel.collapsed + #splitter { display: none; }
#rightPanel {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Drag handle between the preview and the form */
#splitter {
flex: 0 0 8px;
cursor: col-resize;
background: transparent;
border-radius: 3px;
position: relative;
}
#splitter::after {
content: "";
position: absolute;
top: 0; bottom: 0; left: 3px;
width: 2px;
background: #4a4a4a;
border-radius: 2px;
}
#splitter:hover::after, #splitter.dragging::after { background: #6699CC; }
#canvasWrapper {
flex: 1;
overflow: auto;
background: #222;
border-radius: 4px;
padding: 8px;
}
#previewToolbar {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 6px;
}
#previewToolbar button {
background: #555;
color: #eee;
border: 1px solid #666;
border-radius: 3px;
padding: 2px 9px;
font-size: 12px;
line-height: 1.4;
cursor: pointer;
}
#previewToolbar button:hover { border-color: #6699CC; color: #6699CC; }
#zoomLevel { color: #bbb; font-size: 11px; min-width: 40px; text-align: center; }
/* One wrapper per rendered page. app.js sets its width for the zoom level;
the image fills it, so percentage-positioned line markers stay aligned. */
.page-wrap { position: relative; width: 100%; }
.page-wrap + .page-wrap { margin-top: 8px; }
.page-wrap img { display: block; width: 100%; height: auto; border-radius: 2px; }
.line-marker {
position: absolute;
left: 0;
width: 16px;
min-height: 3px;
background: rgba(220, 40, 40, 0.8);
border-radius: 0 2px 2px 0;
cursor: pointer;
z-index: 5;
}
.line-marker:hover {
background: #ff3030;
width: 26px;
}
/* The line last jumped to, from either direction. */
.line-marker.active {
background: #ffcc44;
width: 30px;
box-shadow: 0 0 6px rgba(255, 204, 68, 0.7);
}
.line-marker:hover::after {
content: attr(data-tip);
position: absolute;
left: 30px;
top: -4px;
background: #111;
color: #eee;
border: 1px solid #555;
border-radius: 4px;
padding: 3px 8px;
font-size: 11px;
white-space: nowrap;
pointer-events: none;
z-index: 10;
}
#lineItemsBody tr.has-source { cursor: pointer; }
#lineItemsBody tr.has-source input,
#lineItemsBody tr.has-source textarea,
#lineItemsBody tr.has-source select,
#lineItemsBody tr.has-source button { cursor: auto; }
#lineItemsBody tr.has-source button, #lineItemsBody tr.has-source .cand-item { cursor: pointer; }
#lineItemsBody tr.row-flash td { animation: rowFlash 1.6s ease-out; }
@keyframes rowFlash {
0% { background-color: rgba(220, 40, 40, 0.5); }
100% { background-color: transparent; }
}
#statusBar {
display: none;
flex: 0 0 auto;
padding: 7px 12px;
border-radius: 4px;
font-size: 12px;
margin-bottom: 8px;
}
.status-loading { background: #4a4a00; color: #ffee88; }
.status-error { background: #4a0000; color: #ff9999; }
.status-success { background: #004a00; color: #99ff99; }
/* Shown with display:flex by app.js - it is a full-height column so the
header and the action bar stay put and only the item table scrolls. */
#reviewSection {
display: none;
flex-direction: column;
flex: 1;
min-height: 0;
gap: 8px;
}
.form-section {
background: #3a3a3a;
border-radius: 6px;
padding: 10px 12px;
}
.form-section h2 {
display: flex;
align-items: center;
font-size: 13px;
color: #6699CC;
margin-bottom: 8px;
padding-bottom: 5px;
border-bottom: 1px solid #555;
}
.header-section, .actions-section { flex: 0 0 auto; }
.items-section {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.table-scroll { flex: 1; min-height: 0; overflow: auto; }
.actions-section { display: flex; align-items: center; gap: 10px; }
.actions-right { margin-left: auto; display: flex; gap: 8px; }
/* Header fields wrap across the panel width instead of stacking, which
keeps the vertical space for the line items. */
.hdr-grid { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.hdr-field { display: flex; flex-direction: column; gap: 2px; }
.hdr-field > label {
color: #bbb;
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.hdr-ctl { display: flex; align-items: center; gap: 6px; }
.hdr-field input, .hdr-field select {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
padding: 4px 7px;
border-radius: 3px;
font-size: 13px;
}
.hdr-field input:focus, .hdr-field select:focus { outline: none; border-color: #6699CC; }
.field-row {
display: flex;
align-items: center;
margin-bottom: 7px;
gap: 8px;
}
.field-row label {
width: 110px;
text-align: right;
color: #bbb;
flex-shrink: 0;
}
.field-row input, .field-row select {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
padding: 4px 7px;
border-radius: 3px;
font-size: 13px;
}
.field-row input:focus, .field-row select:focus {
outline: none;
border-color: #6699CC;
}
.field-note { color: #888; font-size: 11px; }
.parsed-hint { color: #777; font-size: 10px; font-style: italic; }
.match-badge {
display: inline-block;
padding: 2px 7px;
border-radius: 10px;
font-size: 11px;
font-weight: bold;
}
.badge-exact { background: #1a4a1a; color: #88ff88; }
.badge-fuzzy { background: #4a3a00; color: #ffcc44; }
.badge-none { background: #4a1a1a; color: #ff8888; }
.warn-badge {
display: inline-block;
margin-left: 5px;
padding: 2px 6px;
background: #4a0000;
color: #ff6666;
border-radius: 3px;
font-size: 10px;
}
#lineItemsTable {
width: 100%;
min-width: 1180px; /* below this the table-scroll wrapper scrolls sideways */
table-layout: fixed;
border-collapse: collapse;
font-size: 11.5px;
}
/* Fixed layout: these widths drive the columns, Description takes the rest. */
#lineItemsTable col.c-upc { width: 92px; }
#lineItemsTable col.c-cert { width: 78px; }
#lineItemsTable col.c-po { width: 44px; }
#lineItemsTable col.c-pocost { width: 56px; }
#lineItemsTable col.c-qty { width: 52px; }
#lineItemsTable col.c-cost { width: 68px; }
#lineItemsTable col.c-pack { width: 50px; }
#lineItemsTable col.c-unitcost { width: 62px; }
#lineItemsTable col.c-retail { width: 58px; }
#lineItemsTable col.c-gm { width: 54px; }
#lineItemsTable col.c-total { width: 64px; }
#lineItemsTable col.c-size { width: 48px; }
#lineItemsTable col.c-uom { width: 42px; }
#lineItemsTable col.c-match { width: 152px; }
#lineItemsTable col.c-del { width: 28px; }
#lineItemsTable th {
background: #444;
color: #6699CC;
padding: 4px 5px;
text-align: left;
border-bottom: 1px solid #555;
white-space: nowrap;
position: sticky;
top: 0;
z-index: 3;
}
#lineItemsTable td {
padding: 3px 4px;
border-bottom: 1px solid #444;
vertical-align: top;
}
#lineItemsTable tr:hover td { background: #3f3f3f; }
#lineItemsTable input {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
padding: 2px 4px;
border-radius: 2px;
font-size: 11.5px;
width: 100%;
}
#lineItemsTable input:focus { outline: none; border-color: #6699CC; }
#lineItemsBody tr.row-added td { background: rgba(102, 153, 204, 0.08); }
#lineItemsTable textarea.item-desc {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
padding: 2px 4px;
border-radius: 2px;
font-size: 11.5px;
width: 100%;
min-height: 30px;
resize: vertical;
font-family: Arial, sans-serif;
}
#lineItemsTable textarea.item-desc:focus { outline: none; border-color: #6699CC; }
/* Fixed, not absolute: the table scroller would otherwise clip the dropdown.
app.js positions it against the search box it belongs to. */
.search-results {
display: none;
position: fixed;
background: #2a2a2a;
border: 1px solid #6699CC;
border-radius: 3px;
z-index: 400;
max-height: 260px;
overflow-y: auto;
overscroll-behavior: contain; /* do not chain into the table and close itself */
width: 380px;
}
.search-result-item {
padding: 6px 8px;
cursor: pointer;
font-size: 11px;
border-bottom: 1px solid #3a3a3a;
}
.search-result-item:hover { background: #3a3a3a; }
.search-result-item:hover .search-result-desc { color: #6699CC; }
.search-result-desc { color: #eee; }
.search-result-meta { color: #777; font-size: 10px; }
.search-result-empty { padding: 5px 8px; color: #888; font-size: 11px; }
#lineItemsTable td:last-child, #lineItemsTable td:nth-last-child(2) { position: relative; }
.cand-list { margin-top: 3px; }
.cand-item {
color: #aaa;
font-size: 10px;
cursor: pointer;
padding: 1px 4px;
border: 1px solid #444;
border-radius: 3px;
margin-top: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cand-item:hover { border-color: #6699CC; color: #6699CC; }
.cand-meta { color: #666; }
/* Always available, on every row - the suggested match is not always right. */
.search-toggle {
display: inline-block;
margin-top: 3px;
background: transparent;
border: 1px solid #666;
color: #bbb;
border-radius: 3px;
padding: 1px 7px;
font-size: 10px;
cursor: pointer;
}
.search-toggle:hover { border-color: #6699CC; color: #6699CC; }
/* Sits under "Change product": nothing in the file fits, so make one. */
.btn-new-item {
display: inline-block;
margin-top: 3px;
background: transparent;
border: 1px solid #4c7a4c;
color: #8fce8f;
border-radius: 3px;
padding: 1px 7px;
font-size: 10px;
cursor: pointer;
}
.btn-new-item:hover { border-color: #88ff88; color: #88ff88; }
.search-inline-wrap { margin-top: 3px; }
.search-inline-wrap .product-search { width: 100%; }
.btn-search-cancel {
background: transparent;
border: none;
color: #777;
font-size: 10px;
cursor: pointer;
padding: 2px 0 0;
}
.btn-search-cancel:hover { color: #6699CC; }
#btnSave, #btnScan, #btnDeleteDraft, #btnRestoreDefaults {
background: #6699CC;
color: #111;
border: none;
padding: 7px 18px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
cursor: pointer;
}
#btnDeleteDraft {
background: #3a2a2a;
color: #ff9999;
border: 1px solid #663333;
}
#btnRestoreDefaults {
background: #4a3a00;
color: #ffcc44;
border: 1px solid #776600;
}
#btnSave:hover, #btnScan:hover, #btnDeleteDraft:hover, #btnRestoreDefaults:hover { opacity: 0.85; }
/* ---------- parsed data viewer ---------- */
#parsedModal {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 550;
background: rgba(0,0,0,0.75);
}
#parsedModal .parsed-box {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%,-50%);
background: #3a3a3a;
border: 1px solid #555;
border-radius: 8px;
padding: 16px 18px;
width: min(860px, 92vw);
height: min(700px, 88vh);
display: flex;
flex-direction: column;
}
#parsedModal h2 {
display: flex;
align-items: center;
font-size: 14px;
color: #6699CC;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #555;
}
#btnCloseParsed {
margin-left: auto;
background: #555;
color: #eee;
border: 1px solid #666;
border-radius: 3px;
padding: 3px 12px;
font-size: 11px;
cursor: pointer;
}
#btnCloseParsed:hover { border-color: #6699CC; color: #6699CC; }
.parsed-tabs { display: flex; gap: 6px; margin-bottom: 8px; }
.parsed-tab {
background: transparent;
border: 1px solid #555;
color: #aaa;
border-radius: 3px;
padding: 4px 12px;
font-size: 11px;
cursor: pointer;
}
.parsed-tab:hover { color: #eee; }
.parsed-tab.active { border-color: #6699CC; color: #6699CC; background: #333; }
.parsed-pane { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 6px; }
.parsed-pane .field-note { flex: 0 0 auto; }
#ocrText {
flex: 1;
width: 100%;
background: #2a2a2a;
color: #eee;
border: 1px solid #555;
padding: 8px;
border-radius: 3px;
font-size: 11px;
font-family: monospace;
resize: none;
}
#ocrText:focus { outline: none; border-color: #6699CC; }
#ocrMethod { color: #888; font-size: 11px; font-weight: normal; margin-left: 8px; }
.diff-only {
margin-left: 14px;
color: #aaa;
font-size: 11px;
font-weight: normal;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
}
.diff-only input { cursor: pointer; }
#compareScroll {
flex: 1;
overflow: auto;
background: #2a2a2a;
border: 1px solid #555;
border-radius: 3px;
padding: 8px;
}
#compareHeader, #compareTable { width: 100%; border-collapse: collapse; font-size: 11.5px; }
#compareHeader { margin-bottom: 14px; }
#compareHeader th, #compareTable th {
background: #444;
color: #6699CC;
padding: 4px 6px;
text-align: left;
border-bottom: 1px solid #555;
position: sticky;
top: -8px;
z-index: 2;
}
#compareHeader td, #compareTable td {
padding: 4px 6px;
border-bottom: 1px solid #3a3a3a;
vertical-align: top;
color: #ccc;
}
#compareHeader th:first-child, #compareTable th:first-child { width: 110px; }
#compareTable th:first-child { width: 34px; }
#compareTable th:last-child { width: 96px; }
#compareBody tr { cursor: pointer; }
#compareBody tr:hover td { background: #3a3a3a; }
.cmp-desc { color: #eee; }
.cmp-meta { color: #777; font-size: 10px; margin-top: 2px; }
.cmp-diff { color: #ffcc44; font-weight: bold; }
.cmp-empty { color: #666; font-style: italic; }
#compareBody tr.has-diff td:first-child { border-left: 3px solid #d0a84c; }
.cmp-none { color: #888; padding: 14px; text-align: center; }
.btn-confirm {
margin-top: 4px;
background: #4a3a00;
color: #ffcc44;
border: 1px solid #776600;
padding: 2px 8px;
border-radius: 3px;
font-size: 10px;
cursor: pointer;
}
.btn-confirm:hover { background: #665200; }
.btn-remove-row {
background: transparent;
border: 1px solid #553333;
color: #cc5555;
width: 22px;
height: 22px;
border-radius: 3px;
cursor: pointer;
font-size: 13px;
line-height: 1;
padding: 0;
}
.btn-remove-row:hover { background: #4a1a1a; color: #ff8888; border-color: #884444; }
.read-only-field {
display: inline-block;
padding: 4px 7px;
color: #ccc;
font-size: 13px;
}
.ro-val {
display: inline-block;
color: #ccc;
font-size: 12px;
padding: 2px 0;
min-width: 20px;
}
.desc-toggle-row { margin-top: 3px; display: flex; align-items: center; gap: 4px; }
.btn-desc-src {
background: transparent;
border: 1px solid #555;
color: #888;
padding: 1px 7px;
border-radius: 2px;
font-size: 10px;
cursor: pointer;
}
.btn-desc-src:hover:not(:disabled) { color: #eee; }
.btn-desc-src.active { border-color: #6699CC; color: #6699CC; background: #333; }
.btn-desc-src:disabled { color: #4d4d4d; border-color: #444; cursor: default; }
.upc-matched { font-size: 12px; color: #eee; }
.upc-parsed-val { font-size: 10px; color: #666; font-style: italic; margin-top: 2px; }
#lineItemsTable tr.po-diff td,
#lineItemsTable tr.po-inv-only td { background: rgba(255,204,68,0.06); }
#lineItemsTable tr.po-match td { background: rgba(80,180,100,0.035); }
.po-value { color: #ccc; font-size: 12px; white-space: nowrap; }
.po-cell-diff { color: #ffcc44; font-weight: bold; }
.cmp-na { color: #555; }
.po-note {
display: inline-block;
margin-left: 5px;
padding: 2px 6px;
background: #4a3a00;
color: #ffcc44;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.po-summary { color: #888; font-size: 11px; font-weight: normal; margin-left: 8px; }
.h2-actions { margin-left: auto; display: flex; gap: 6px; }
#btnAcceptAll, #btnAddLine {
background: #555;
color: #eee;
border: 1px solid #666;
padding: 4px 10px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
cursor: pointer;
}
#btnAddLine { background: #2a3a35; border-color: #336655; color: #88ffcc; }
#btnAcceptAll:hover, #btnAddLine:hover { border-color: #6699CC; color: #6699CC; }
.search-result-new {
padding: 5px 8px;
cursor: pointer;
font-size: 11px;
color: #6699CC;
border-top: 1px solid #3a3a3a;
}
.search-result-new:hover { background: #3a3a3a; }
/* ---------- Landing dashboard ---------- */
#dashboard {
display: none;
max-width: 980px;
margin: 0 auto;
padding: 26px 16px 40px;
}
.dash-hero {
background: linear-gradient(160deg, #3d3d3d, #353535);
border: 1px solid #555;
border-radius: 10px;
padding: 30px;
margin-bottom: 22px;
}
.dash-hero #uploadZone {
border: 2px dashed #6a6a6a;
border-radius: 8px;
padding: 40px 24px;
text-align: center;
cursor: pointer;
background: #333;
transition: border-color 0.2s, background 0.2s;
}
.dash-hero #uploadZone:hover, .dash-hero #uploadZone.drag-over {
border-color: #6699CC;
background: #3a3a3a;
}
.dash-hero #uploadZone .up-icon { font-size: 40px; display: block; margin-bottom: 10px; }
.dash-hero #uploadZone label {
cursor: pointer;
color: #6699CC;
font-size: 20px;
font-weight: bold;
}
.dash-hero #uploadPrompt { color: #aaa; margin-top: 10px; font-size: 13px; }
.dash-hero #statusBar { margin-top: 14px; }
#uploadZone input[type=file] { display: none; }
.dash-actions { display: flex; gap: 10px; margin-bottom: 22px; flex-wrap: wrap; }
.dash-btn {
background: #444;
color: #eee;
border: 1px solid #666;
border-radius: 5px;
padding: 9px 18px;
font-size: 13px;
font-weight: bold;
cursor: pointer;
text-decoration: none;
display: inline-block;
}
.dash-btn:hover { border-color: #6699CC; color: #6699CC; }
.dash-btn.primary { background: #6699CC; color: #111; border-color: #6699CC; }
.dash-btn.primary:hover { opacity: 0.85; color: #111; }
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
}
.stat-card {
background: #3a3a3a;
border: 1px solid #4d4d4d;
border-left: 4px solid #666;
border-radius: 8px;
padding: 16px 18px;
text-decoration: none;
color: #eee;
display: block;
transition: transform 0.1s, border-color 0.2s;
}
.stat-card:hover { transform: translateY(-2px); border-color: #777; }
.stat-num { font-size: 30px; font-weight: bold; line-height: 1; }
.stat-label { color: #aaa; font-size: 12px; margin-top: 7px; text-transform: uppercase; letter-spacing: 0.5px; }
.stat-sub { color: #777; font-size: 11px; margin-top: 3px; }
.sc-ready { border-left-color: #4caf50; }
.sc-ready .stat-num { color: #88ff88; }
.sc-queued { border-left-color: #5a8fd0; }
.sc-queued .stat-num { color: #88bbff; }
.sc-progress { border-left-color: #d0a84c; }
.sc-progress .stat-num { color: #ffcc44; }
.sc-error { border-left-color: #c05050; }
.sc-error .stat-num { color: #ff8888; }
.sc-archived .stat-num { color: #ccc; }
.sc-total { border-left-color: #9c7fd0; }
.sc-total .stat-num { color: #bba6ff; }
.sc-value { border-left-color: #4caf50; }
.sc-value .stat-num { color: #88ff88; }
.sc-lines { border-left-color: #5a8fd0; }
.sc-lines .stat-num { color: #88bbff; }
.dash-foot { color: #777; font-size: 11px; margin-top: 16px; text-align: right; }
/* ---------- pending list page ---------- */
#content { padding: 12px; }
#content #statusBar { margin-bottom: 10px; }
table.list { width: 100%; border-collapse: collapse; font-size: 12px; background: #3a3a3a; }
table.list th {
background: #444;
color: #6699CC;
padding: 6px 8px;
text-align: left;
border-bottom: 1px solid #555;
white-space: nowrap;
}
table.list td { padding: 6px 8px; border-bottom: 1px solid #444; vertical-align: top; }
table.list tr:hover td { background: #3f3f3f; }
.muted { color: #888; }
.stage {
display: inline-block;
padding: 2px 7px;
border-radius: 10px;
background: #4a3a00;
color: #ffcc44;
font-size: 11px;
font-weight: bold;
}
.stage-queued { background: #2a3a4a; color: #88bbff; }
.stage-processing { background: #3a3a00; color: #ffee88; }
.stage-parsed { background: #1a4a1a; color: #88ff88; }
.stage-review { background: #1a4a1a; color: #88ff88; }
.stage-editing { background: #1a4a1a; color: #88ff88; }
.stage-error { background: #4a1a1a; color: #ff8888; }
.btn {
border: 1px solid #666;
background: #555;
color: #eee;
border-radius: 3px;
padding: 4px 10px;
font-size: 11px;
cursor: pointer;
text-decoration: none;
display: inline-block;
margin-right: 5px;
}
.btn:hover { border-color: #6699CC; color: #6699CC; }
.btn-delete { border-color: #663333; color: #ff9999; background: #3a2a2a; }
.btn-process { border-color: #336655; color: #88ffcc; background: #2a3a35; }
#queueToolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
#queueToolbar .btn-process { padding: 7px 16px; font-size: 13px; font-weight: bold; }
#queueToolbar .btn-process:disabled { opacity: 0.6; cursor: default; }
#emptyState { color: #888; padding: 28px; text-align: center; background: #3a3a3a; border-radius: 5px; display: none; }
/* ---------- archive page ---------- */
body.archive-page { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
#listPanel { flex-shrink: 0; height: 210px; overflow-y: auto; border-bottom: 2px solid #555; background: #2e2e2e; }
#filterPanel { flex-shrink: 0; background: #333; border-bottom: 1px solid #555; padding: 10px 12px; }
#filterPanel form { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: flex-end; }
.filter-field { display: flex; flex-direction: column; gap: 3px; }
.filter-field label { color: #aaa; font-size: 11px; }
.filter-field input, .filter-field select {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
border-radius: 3px;
padding: 4px 6px;
font-size: 12px;
}
.filter-field input:focus, .filter-field select:focus { outline: none; border-color: #6699CC; }
.filter-actions { display: flex; gap: 6px; align-items: center; padding-bottom: 1px; }
.filter-btn {
border: 1px solid #666;
background: #555;
color: #eee;
border-radius: 3px;
padding: 5px 11px;
font-size: 12px;
cursor: pointer;
text-decoration: none;
}
.filter-btn.primary { background: #6699CC; color: #111; border-color: #6699CC; font-weight: bold; }
.filter-btn:hover { opacity: 0.85; }
#listPanel table { width: 100%; border-collapse: collapse; font-size: 12px; }
#listPanel th { background: #3a3a3a; color: #6699CC; padding: 5px 8px; text-align: left; border-bottom: 1px solid #555; position: sticky; top: 0; z-index: 1; white-space: nowrap; }
#listPanel td { padding: 4px 8px; border-bottom: 1px solid #3a3a3a; white-space: nowrap; }
.inv-row { cursor: pointer; }
.inv-row:hover td { background: #3a3a3a; }
.inv-row.selected td { background: #1a3a5a; }
#detailLayout { display: flex; flex: 1; overflow: hidden; }
#archiveLeft { flex: 1; overflow-y: auto; background: #222; padding: 10px; }
#archiveLeft img { max-width: 100%; display: block; border-radius: 2px; }
#archiveLeft img + img { margin-top: 8px; }
#archiveRight { flex: 1; overflow-y: auto; padding: 12px; background: #333; border-left: 1px solid #444; }
#pdfPlaceholder { color: #666; font-size: 12px; padding: 20px; text-align: center; }
.info-card { background: #3a3a3a; border-radius: 5px; padding: 12px 14px; margin-bottom: 12px; }
.info-card h2 { font-size: 13px; color: #6699CC; margin-bottom: 10px; padding-bottom: 5px; border-bottom: 1px solid #555; }
.info-row { display: flex; margin-bottom: 5px; gap: 8px; }
.info-label { color: #aaa; width: 100px; flex-shrink: 0; text-align: right; font-size: 12px; }
.info-value { color: #eee; font-size: 12px; }
/* Header and the batch it produced sit side by side; the batch card takes the
space the header card was leaving empty. Both stretch to the taller of the
two so the header card does not leave a ragged gap beside the batch list. */
.detail-top { display: flex; gap: 12px; align-items: stretch; flex-wrap: wrap; }
.detail-top > .info-card { flex: 1 1 300px; min-width: 0; }
.detail-top > .info-card:first-child { flex: 0 1 auto; }
#batchCard h2 { display: flex; align-items: center; gap: 8px; }
.batch-flag { background: #4a3a00; color: #ffcc44; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 3px; }
.batch-none { color: #888; font-size: 12px; }
.batch-scroll { max-height: 190px; overflow: auto; margin-top: 8px; border-top: 1px solid #555; }
#batchTable { width: 100%; border-collapse: collapse; font-size: 11px; }
#batchTable th { background: #444; color: #6699CC; padding: 4px 5px; text-align: left; border-bottom: 1px solid #555; white-space: nowrap; position: sticky; top: 0; }
#batchTable td { padding: 3px 5px; border-bottom: 1px solid #3a3a3a; white-space: nowrap; }
#batchTable td:nth-child(3), #batchTable td:nth-child(4),
#batchTable td:nth-child(5), #batchTable td:nth-child(6) { text-align: right; }
#batchTable tr.batch-low td { color: #ffcc44; }
#itemsTable { width: 100%; border-collapse: collapse; font-size: 12px; }
#itemsTable th { background: #444; color: #6699CC; padding: 5px 6px; text-align: left; border-bottom: 1px solid #555; white-space: nowrap; }
#itemsTable td { padding: 4px 5px; border-bottom: 1px solid #3a3a3a; vertical-align: top; }
#itemsTable tr:hover td { background: #3f3f3f; }
#itemsTable td:nth-child(4), #itemsTable td:nth-child(5), #itemsTable td:nth-child(6) { text-align: right; }
/* busy overlay */
#busyOverlay {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 600;
background: rgba(0, 0, 0, 0.55);
align-items: center;
justify-content: center;
}
#busyOverlay .busy-box {
background: #3a3a3a;
border: 1px solid #555;
border-radius: 8px;
padding: 22px 30px;
text-align: center;
min-width: 260px;
}
#busyOverlay .busy-spinner {
width: 30px;
height: 30px;
margin: 0 auto 12px;
border: 3px solid #555;
border-top-color: #6699CC;
border-radius: 50%;
animation: busySpin 0.8s linear infinite;
}
#busyOverlay .busy-msg { color: #ccc; font-size: 13px; }
@keyframes busySpin { to { transform: rotate(360deg); } }
/* new product modal */
#newProductModal {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 500;
background: rgba(0,0,0,0.75);
}
#newProductModal .modal-box {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%,-50%);
background: #3a3a3a;
border: 1px solid #555;
border-radius: 8px;
padding: 20px;
width: 420px;
max-height: 90vh;
overflow-y: auto;
}
#newProductModal h2 {
font-size: 14px;
color: #6699CC;
margin-bottom: 14px;
padding-bottom: 8px;
border-bottom: 1px solid #555;
}
/* ---- unit cost / retail / gross margin ---------------------------------- */
/* Computed cells: not inputs, so they read as derived rather than editable. */
.calc-cell {
text-align: right;
padding: 4px 6px;
color: #ccc;
font-variant-numeric: tabular-nums;
}
.calc-cell.cmp-na { color: #666; }
.gm-cell { font-weight: bold; }
.gm-good { color: #88ff88; }
.gm-thin { color: #ffcc66; }
.gm-loss { color: #ff8888; }
.np-select {
background: #2a2a2a;
border: 1px solid #555;
color: #eee;
padding: 4px 7px;
border-radius: 3px;
font-size: 13px;
}
/* Database failure banner (showDbError). Stays until the page reloads. */
.db-warning { display: none; margin: 0 12px 8px; padding: 7px 12px; border-radius: 4px; font-size: 12px; background: #4a0000; color: #ff9999; flex-shrink: 0; }
/* ---- review sanity checks ---------------------------------------------- */
.attention-count { color: #ffcc44; font-weight: bold; }
.attention-none { color: #88ff88; }
.save-blockers { color: #ffcc44; font-size: 11px; margin-left: 12px; }