InvoiceParser/wwwroot/css/style.css

1122 lines
34 KiB
CSS
Raw Normal View History

2026-09-16 20:09:19 +00:00
/* 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; }
2026-09-30 18:50:04 +00:00
h1 a.active { color: #eee; box-shadow: inset 0 -2px 0 #6699CC; padding-bottom: 2px; }
2026-09-16 20:09:19 +00:00
#pageMode { margin-left: 6px; }
2026-09-30 18:50:04 +00:00
#btnTogglePreview, #btnViewParsed, .nav-draft {
2026-09-16 20:09:19 +00:00
display: none;
background: #555;
color: #eee;
border: 1px solid #666;
border-radius: 3px;
padding: 3px 10px;
font-size: 11px;
cursor: pointer;
}
2026-09-30 18:50:04 +00:00
#btnPrevDraft { margin-left: auto; }
#btnViewParsed { margin-left: 14px; }
2026-09-16 20:09:19 +00:00
#btnTogglePreview { margin-left: 6px; }
2026-09-30 18:50:04 +00:00
#btnTogglePreview:hover, #btnViewParsed:hover, .nav-draft:hover:not(:disabled) { border-color: #6699CC; color: #6699CC; }
.nav-draft:disabled { color: #777; cursor: default; }
.draft-pos { color: #999; font-size: 11px; font-weight: normal; margin: 0 6px; }
body.review-page #btnTogglePreview, body.review-page #btnViewParsed, body.review-page .nav-draft { display: inline-block; }
2026-09-16 20:09:19 +00:00
/* 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;
2026-09-30 18:50:04 +00:00
/* Solid edge bar plus a see-through fill: the marker sits over the
left margin, where the UPC usually is, so the text must stay readable. */
box-sizing: border-box;
border-left: 4px solid rgba(220, 40, 40, 0.9);
background: rgba(220, 40, 40, 0.15);
2026-09-16 20:09:19 +00:00
border-radius: 0 2px 2px 0;
cursor: pointer;
z-index: 5;
}
.line-marker:hover {
2026-09-30 18:50:04 +00:00
border-left-color: #ff3030;
background: rgba(255, 48, 48, 0.2);
2026-09-16 20:09:19 +00:00
width: 26px;
}
/* The line last jumped to, from either direction. */
.line-marker.active {
2026-09-30 18:50:04 +00:00
border-left-color: #ffcc44;
background: rgba(255, 204, 68, 0.25);
2026-09-16 20:09:19 +00:00
width: 30px;
2026-09-30 18:50:04 +00:00
box-shadow: 0 0 0 1px rgba(255, 204, 68, 0.8);
2026-09-16 20:09:19 +00:00
}
.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%;
2026-09-30 18:50:04 +00:00
min-width: 1078px; /* below this the table-scroll wrapper scrolls sideways */
2026-09-16 20:09:19 +00:00
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; }
2026-09-30 18:50:04 +00:00
#lineItemsTable col.c-cert { width: 72px; }
#lineItemsTable col.c-po { width: 38px; }
#lineItemsTable col.c-pocost { width: 46px; }
#lineItemsTable col.c-qty { width: 44px; }
#lineItemsTable col.c-cost { width: 64px; }
#lineItemsTable col.c-pack { width: 44px; }
#lineItemsTable col.c-unitcost { width: 60px; }
#lineItemsTable col.c-retail { width: 52px; }
#lineItemsTable col.c-gm { width: 50px; }
#lineItemsTable col.c-total { width: 74px; }
#lineItemsTable col.c-size { width: 42px; }
#lineItemsTable col.c-uom { width: 36px; }
#lineItemsTable col.c-match { width: 138px; }
#lineItemsTable col.c-del { width: 24px; }
2026-09-16 20:09:19 +00:00
#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; }
2026-09-30 18:50:04 +00:00
#btnSave, #btnScan {
2026-09-16 20:09:19 +00:00
background: #6699CC;
color: #111;
border: none;
padding: 7px 18px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
cursor: pointer;
}
2026-09-30 18:50:04 +00:00
#btnSave:hover, #btnScan:hover { opacity: 0.85; }
#btnSave:disabled { opacity: 0.5; cursor: default; }
/* Secondary draft actions: kept small and away from Save. */
.btn-quiet {
background: transparent;
border: 1px solid #555;
color: #aaa;
padding: 3px 9px;
border-radius: 3px;
font-size: 11px;
cursor: pointer;
2026-09-16 20:09:19 +00:00
}
2026-09-30 18:50:04 +00:00
.btn-quiet:hover { border-color: #6699CC; color: #6699CC; }
.btn-quiet-danger:hover { border-color: #884444; color: #ff8888; }
.autosave-error { color: #ff9999; }
2026-09-16 20:09:19 +00:00
/* ---------- 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;
}
2026-09-30 18:50:04 +00:00
.dash-welcome {
color: #ddd;
font-size: 22px;
font-weight: normal;
margin: 0 0 16px;
}
2026-09-16 20:09:19 +00:00
.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; }
2026-09-30 18:50:04 +00:00
.dash-foot { color: #999; font-size: 11px; margin-top: 16px; text-align: right; }
.dash-actions { align-items: center; }
.dash-note { color: #aaa; font-size: 12px; }
.dash-btn.disabled { background: #444; color: #999; border-color: #555; }
/* Ready / Queued / Errors lead; the rest are context. */
.stats-primary { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 12px; }
.stats-primary .stat-card { padding: 20px 22px; }
.stats-primary .stat-num { font-size: 40px; }
.stats-secondary { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; }
.stats-secondary .stat-card { padding: 10px 14px; border-left-width: 3px; }
.stats-secondary .stat-num { font-size: 20px; }
.stats-secondary .stat-label { font-size: 11px; margin-top: 5px; }
.stat-card.is-zero .stat-num { color: #888; }
.stat-card.sc-error.is-zero { border-left-color: #555; }
/* Per-file upload progress, updated live from the worker's stage events. */
.upload-list { list-style: none; margin-top: 12px; max-height: 220px; overflow-y: auto; }
.upload-list li {
display: flex;
align-items: center;
gap: 10px;
padding: 5px 8px;
border-bottom: 1px solid #444;
font-size: 12px;
}
.upload-list .ul-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upload-list .ul-open { color: #6699CC; text-decoration: none; font-weight: bold; }
.upload-list .ul-open:hover { text-decoration: underline; }
.stage.stage-uploading { background: #3a3a3a; color: #bbb; }
#uploadZone:focus-visible { outline: 2px solid #6699CC; outline-offset: 2px; }
2026-09-16 20:09:19 +00:00
/* ---------- 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; }
#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; }
2026-09-30 18:50:04 +00:00
#listPanel {
flex-shrink: 0;
height: 210px;
min-height: 80px;
max-height: 70vh;
overflow-y: auto;
resize: vertical;
border-bottom: 2px solid #555;
background: #2e2e2e;
}
#listPanel th.sortable { cursor: pointer; user-select: none; }
#listPanel th.sortable:hover { color: #99bbe0; }
#listPanel th.sort-asc::after { content: " \25B2"; font-size: 9px; }
#listPanel th.sort-desc::after { content: " \25BC"; font-size: 9px; }
.result-count { color: #999; font-size: 11px; margin-left: 6px; }
#archiveToolbar {
position: sticky;
top: 0;
margin: -10px -10px 8px;
padding: 6px 10px;
background: #222;
border-bottom: 1px solid #3a3a3a;
display: flex;
align-items: center;
gap: 6px;
z-index: 2;
}
#archiveToolbar button {
background: #555;
color: #eee;
border: 1px solid #666;
border-radius: 3px;
padding: 2px 9px;
font-size: 12px;
line-height: 1.4;
cursor: pointer;
}
#archiveToolbar button:hover { border-color: #6699CC; color: #6699CC; }
#archiveToolbar #btnOpenOriginal { margin-left: auto; margin-right: 0; }
2026-09-16 20:09:19 +00:00
#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; }
2026-09-30 18:50:04 +00:00
/* Width is set by the archive zoom (applyZoom). */
#archiveLeft img { max-width: none; display: block; border-radius: 2px; }
2026-09-16 20:09:19 +00:00
#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
2026-09-30 18:50:04 +00:00
space the header card was leaving empty. Each card ends at its own content -
stretching the short header card to the batch list's height left dead space. */
.detail-top { display: flex; gap: 12px; align-items: flex-start; flex-wrap: wrap; }
2026-09-16 20:09:19 +00:00
.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 ---------------------------------------------- */
2026-09-30 18:50:04 +00:00
.attention-count { color: #ffcc44; font-weight: bold; cursor: pointer; text-decoration: underline dotted; }
.attention-count:hover { color: #ffe08a; }
2026-09-16 20:09:19 +00:00
.attention-none { color: #88ff88; }
2026-09-30 18:50:04 +00:00
#lineItemsTable.attention-only tbody tr:not(.needs-attention) { display: none; }
2026-09-16 20:09:19 +00:00
.save-blockers { color: #ffcc44; font-size: 11px; margin-left: 12px; }
2026-09-30 18:50:04 +00:00
.total-ok { color: #88ff88; }
.total-diff { color: #ffcc44; font-weight: bold; }
/* Inline validation, set by handleSave and cleared on the next edit. */
.field-error { color: #ff9999; font-size: 10px; }
.hdr-field input.field-invalid, .hdr-field select.field-invalid,
#lineItemsTable input.field-invalid { border-color: #cc5555; background: #3a2626; }
#lineItemsBody tr.row-invalid td:first-child { box-shadow: inset 3px 0 0 #cc5555; }
/* Line total that does not equal qty x case cost. */
#lineItemsTable input.item-total.total-mismatch { border-color: #b08a2a; color: #ffcc44; }
.match-actions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.match-actions .search-toggle, .match-actions .btn-new-item { margin-top: 0; }
.search-result-item.active, .search-result-new.active { background: #3a3a3a; }
.search-result-item.active .search-result-desc { color: #6699CC; }
.status-actions { margin-left: 10px; }
.status-actions a, .status-actions button {
margin-left: 6px;
background: #2a2a2a;
border: 1px solid #5a8a5a;
color: #cfe;
border-radius: 3px;
padding: 2px 9px;
font-size: 11px;
cursor: pointer;
text-decoration: none;
}
.status-actions a:hover, .status-actions button:hover { border-color: #88ff88; }
#reviewSection.saved { opacity: 0.45; pointer-events: none; }
/* Undo toast for row removal and Accept All. */
#toast {
display: none;
position: fixed;
left: 50%;
bottom: 22px;
transform: translateX(-50%);
background: #222;
color: #eee;
border: 1px solid #555;
border-radius: 5px;
padding: 8px 12px;
font-size: 12px;
z-index: 700;
align-items: center;
gap: 12px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
#toast button {
background: transparent;
border: 1px solid #6699CC;
color: #6699CC;
border-radius: 3px;
padding: 2px 10px;
font-size: 11px;
font-weight: bold;
cursor: pointer;
}