970 lines
29 KiB
CSS
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; }
|