v0.9.0 - CSS refactor: split into device files, scanner UI improvements, scroll buttons

This commit is contained in:
Javier
2026-01-24 16:01:40 -06:00
parent 53158e76e4
commit 1a5168d155
8 changed files with 631 additions and 301 deletions

46
AI Prompt.txt Normal file
View File

@@ -0,0 +1,46 @@
You are **Carl** — a proud, detail-oriented software engineer who LOVES programming and gets genuinely excited about helping people build things (light jokes welcome). You are an expert in Python, Flask, SQL, HTML/CSS/JS, REST APIs, auth, debugging, logging, and testing.
You are helping build a project called **Scanlook**.
## Scanlook (current product summary)
Scanlook is a web app for warehouse counting workflows.
- Admin creates a **Count Session** (e.g., “Jan 24 2026 - First Shift”) and uploads a **Master Inventory list**.
- Staff select the active Count Session, enter a **Location/BIN**, and the app shows the **Expected** lots/items/weights that should be there (Cycle Count mode).
- Staff **scan lot numbers**, enter **weights**, and each scan moves from **Expected → Scanned**.
- System flags:
- duplicates
- wrong location
- “ghost” lots (physically found but not in system/master list)
- Staff can **Finalize** a BIN; once finalized, it should clearly report **missing items/lots**.
- Admin sees live progress in an **Admin Dashboard**.
- Multiple Count Sessions can exist even on the same day (e.g., First Shift vs Second Shift) and must be completely isolated.
There are two types of counts:
1) **Cycle Count**: shows Expected list for the BIN.
2) **Physical Inventory**: same workflow but **blind** (does NOT show Expected list; only scanned results, then missing is determined after).
Long-term goal: evolve into a WMS, but right now focus on making this workflow reliable.
## Operating rules (must follow)
1) **Be accurate, not fast.** Double-check code, SQL, and commands before sending.
2) **No assumptions about files/environment.** If you need code, schema, logs, config, versions, or screenshots, ask me to paste/upload them.
3) **Step-by-step only.** Im a beginner: give ONE small step at a time, then wait for my result before continuing.
4) **No command dumps.** Dont give long chains of commands. One command (or tiny set) per step.
5) **Keep it to the point.** Default to short answers. Only explain more if I ask.
6) **Verify safety.** Warn me before destructive actions (delete/overwrite/migrations). Offer a safer alternative.
7) **Evidence-based debugging.** Ask for exact error text/logs and versions before guessing.
## How you should respond
- Start by confirming which mode were working on: Cycle Count or Physical Inventory.
- Ask for the minimum needed info (36 questions max), then propose the next single step.
- When writing code: keep it small, readable, and consistent with Flask best practices.
- When writing SQL: be explicit about constraints/indexes that matter for lots/bins/sessions.
- When talking workflow: always keep session isolation (shift-based counts) as a hard requirement.
## First response checklist (every new task)
Ask for:
- DB type (SQLite/Postgres/MySQL) + ORM (SQLAlchemy?) or raw SQL
- Current data model (tables or SQLAlchemy models) for: count_session, bin/location, expected_lines, scans
- How the Master Inventory list is formatted (CSV columns)
- What “Finalize BIN” should do exactly (lock? allow reopen? who can override?)
Then proceed one step at a time.

30
app.py
View File

@@ -36,7 +36,7 @@ app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1)
# 1. Define the version
APP_VERSION = '0.8.6'
APP_VERSION = '0.9.0'
# 2. Inject it into all templates automatically
@app.context_processor
@@ -149,6 +149,34 @@ def serve_sw():
"""Serve the Service Worker file from the static directory"""
return send_from_directory('static', 'sw.js')
# ==================== Temp delete me later ====================
@app.route('/whatami')
def whatami():
"""Temporary route to identify device user-agent"""
ua = request.headers.get('User-Agent', 'Unknown')
return f"""
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body style="font-family: monospace; padding: 20px; word-wrap: break-word;">
<h1>Device Info</h1>
<h3>User-Agent:</h3>
<p style="background: #eee; padding: 10px;">{ua}</p>
<h3>Screen Size:</h3>
<p id="screen" style="background: #eee; padding: 10px;">Loading...</p>
<h3>Viewport Size:</h3>
<p id="viewport" style="background: #eee; padding: 10px;">Loading...</p>
<script>
document.getElementById('screen').textContent =
'Screen: ' + screen.width + ' x ' + screen.height + ' | Pixel Ratio: ' + window.devicePixelRatio;
document.getElementById('viewport').textContent =
'Viewport: ' + window.innerWidth + ' x ' + window.innerHeight;
</script>
</body>
</html>
"""
# ==================== RUN APPLICATION ====================
if __name__ == '__main__':

Binary file not shown.

188
static/css/mobile.css Normal file
View File

@@ -0,0 +1,188 @@
/* ==================== MOBILE STYLES (Phones) ==================== */
/* Viewport: 360-767px | Target: min-width: 360px and max-width: 767px */
/* This file contains overrides for mobile phones (iPhone, Android, etc.) */
@media screen and (min-width: 360px) and (max-width: 767px) {
/* ---------------------------------------------------------
Base Typography
--------------------------------------------------------- */
html {
font-size: 14px;
}
/* ---------------------------------------------------------
Navbar
--------------------------------------------------------- */
.nav-content {
flex-direction: row;
gap: var(--space-md);
}
/* ---------------------------------------------------------
Forms
--------------------------------------------------------- */
.form-row {
grid-template-columns: 1fr;
}
/* ---------------------------------------------------------
Dashboard
--------------------------------------------------------- */
.dashboard-header {
flex-direction: column;
align-items: stretch;
gap: var(--space-md);
}
.sessions-grid {
grid-template-columns: 1fr;
}
.session-stats {
grid-template-columns: repeat(3, 1fr);
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.baseline-grid {
grid-template-columns: 1fr;
}
/* ---------------------------------------------------------
Scanning Interface
--------------------------------------------------------- */
.scan-input {
font-size: 1.25rem;
}
.location-name {
font-size: 2rem;
}
/* ---------------------------------------------------------
Modals
--------------------------------------------------------- */
.modal-content {
padding: var(--space-md);
margin: var(--space-xs);
}
.modal-header-bar {
padding: var(--space-md) 0;
margin-bottom: var(--space-md);
}
.modal-large,
.modal-xl {
width: 95%;
max-width: 95%;
margin: var(--space-xs);
}
/* ---------------------------------------------------------
Detail Sections (Scan Detail Modal)
--------------------------------------------------------- */
.detail-section {
padding: var(--space-md) 0;
}
.detail-section-title {
font-size: 1rem;
margin-bottom: var(--space-sm);
}
.detail-row {
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) 0;
}
.detail-label {
flex: none;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.detail-value {
font-size: 1rem;
}
.detail-lot {
font-size: 0.95rem;
word-break: break-all;
}
.detail-input {
width: 100%;
font-size: 1rem;
}
.detail-form {
gap: var(--space-sm);
}
.detail-actions {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-md) 0 0 0;
}
.detail-actions .btn {
width: 100%;
margin: 0;
}
/* ---------------------------------------------------------
Forms (Mobile)
--------------------------------------------------------- */
.form-group {
margin-bottom: var(--space-sm);
}
/* ---------------------------------------------------------
Scroll to Top or Bottom Buttonss
--------------------------------------------------------- */
/* ---------------------------------------------------------
Scroll Buttons - Floating, semi-transparent
--------------------------------------------------------- */
.scroll-to-top,
.scroll-to-bottom {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 44px;
height: 44px;
background: rgba(0, 212, 255, 0.3);
color: var(--color-text);
border: 1px solid rgba(0, 212, 255, 0.4);
border-radius: 50%;
font-size: 1.3rem;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
z-index: 50;
transition: var(--transition);
}
.scroll-to-top:active,
.scroll-to-bottom:active {
background: rgba(0, 212, 255, 0.6);
transform: scale(0.95);
}
.scroll-to-top {
right: 10px;
bottom: 270px;
}
.scroll-to-bottom {
right: 10px;
bottom: 170px;
}
}

344
static/css/scanner.css Normal file
View File

@@ -0,0 +1,344 @@
/* ==================== SCANNER STYLES (MC9300) ==================== */
/* Viewport: 320 x 405 | Target: max-width: 359px */
/* This file contains overrides for Zebra MC9300 handheld scanners */
@media screen and (max-width: 359px) {
/* ---------------------------------------------------------
CSS Variables - Tighter spacing for small screen
--------------------------------------------------------- */
:root {
--space-2xl: 0.8rem;
--space-xl: 0.6rem;
--space-lg: 0.4rem;
--space-md: 0.3rem;
}
/* ---------------------------------------------------------
Navbar - Minimal, compact
--------------------------------------------------------- */
.navbar {
padding: 4px 10px;
height: 38px;
}
.logo {
font-size: 1rem;
}
.user-badge,
.role-pill,
.breadcrumb,
.settings-dropdown {
display: none;
}
.btn-logout {
padding: 2px 8px;
font-size: 0.7rem;
}
/* ---------------------------------------------------------
Page Header
--------------------------------------------------------- */
.page-title {
font-size: 1.1rem;
margin: 0;
padding: 2px 0;
}
.page-header {
margin-bottom: 5px;
flex-direction: row;
align-items: center;
}
/* ---------------------------------------------------------
Location Header - Compact single line top
--------------------------------------------------------- */
.location-header {
padding: 6px 10px;
margin-bottom: 6px;
border-width: 1px;
}
.location-info {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto auto;
gap: 0 8px;
align-items: center;
}
.location-label {
grid-column: 1;
grid-row: 1;
font-size: 0.6rem;
margin: 0;
}
.location-stats {
grid-column: 2;
grid-row: 1;
justify-content: flex-end;
gap: 4px;
}
.location-name {
grid-column: 1 / -1;
grid-row: 2;
font-size: 1.4rem;
margin: 0;
text-align: left;
}
.stat-pill {
padding: 2px 6px;
font-size: 0.65rem;
}
/* ---------------------------------------------------------
Scan Input Card - Compact
--------------------------------------------------------- */
.scan-card {
padding: 8px;
margin-bottom: 6px;
border-width: 0px;
}
.scan-header {
display: none;
}
.scan-input {
padding: 8px;
font-size: 1rem;
height: 38px;
border-width: 2px;
}
/* ---------------------------------------------------------
Scanned/Expected Lists
--------------------------------------------------------- */
.scans-section,
.expected-section {
padding: 5px;
background: none;
border: none;
}
.scans-header {
margin-bottom: 4px;
padding-bottom: 2px;
}
.scans-title {
font-size: 0.9rem;
}
/* ---------------------------------------------------------
Lists - No scroll boxes, natural page flow
--------------------------------------------------------- */
.scans-grid {
max-height: none;
overflow-y: visible;
gap: normal;
}
/* ---------------------------------------------------------
List Rows - 2-row layout for scanner
Row 1: Lot number (full width)
Row 2: Item + Weight
--------------------------------------------------------- */
.scan-row,
.expected-row {
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: auto auto;
gap: 2px 8px;
padding: 6px 8px;
margin-bottom: 4px;
font-size: 0.8rem;
}
/* Lot spans full width on row 1 */
.scan-row-lot {
grid-column: 1 / -1;
font-size: 0.85rem;
}
/* Item on row 2, left */
.scan-row-item {
grid-column: 1;
grid-row: 2;
}
/* Weight on row 2, right */
.scan-row-weight {
grid-column: 2;
grid-row: 2;
text-align: right;
}
/* Hide status column on scanner */
.scan-row-status {
display: none;
}
/* ---------------------------------------------------------
Row Status Colors (more visible without status badge)
--------------------------------------------------------- */
.scan-row-match {
background: rgba(0, 255, 136, 0.15);
}
.scan-row-wrong_location {
background: rgba(255, 170, 0, 0.15);
}
.scan-row-ghost_lot {
background: rgba(179, 102, 255, 0.15);
}
.scan-row-weight_discrepancy {
background: rgba(255, 152, 0, 0.25);
}
.scan-row-duplicate-01,
.scan-row-duplicate-04 {
background: rgba(0, 163, 255, 0.15);
}
.scan-row-duplicate-03 {
background: rgba(255, 140, 0, 0.15);
}
/* ---------------------------------------------------------
Action Buttons (Back / Finish)
--------------------------------------------------------- */
.finish-section {
position: relative; /* Not fixed/floating */
bottom: 0;
margin-top: 10px;
}
.action-buttons-row {
display: flex;
gap: 8px;
}
.action-buttons-row .btn {
flex: 1;
padding: 8px;
font-size: 0.85rem;
min-height: 40px;
}
.btn-success {
background: var(--color-success);
box-shadow: none; /* Remove glow for performance */
}
/* ---------------------------------------------------------
Detail Sections (Scan Detail Modal)
--------------------------------------------------------- */
.detail-section {
padding: var(--space-md) 0;
}
.detail-section-title {
font-size: 1rem;
margin-bottom: var(--space-sm);
}
.detail-row {
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) 0;
}
.detail-label {
flex: none;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.detail-value {
font-size: 1rem;
}
.detail-lot {
font-size: 0.95rem;
word-break: break-all;
}
.detail-input {
width: 100%;
font-size: 1rem;
}
.detail-form {
gap: var(--space-sm);
}
.detail-actions {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-md) 0 0 0;
}
.detail-actions .btn {
width: 100%;
margin: 0;
}
/* ---------------------------------------------------------
Scroll to Top or Bottom Buttonss
--------------------------------------------------------- */
/* ---------------------------------------------------------
Scroll Buttons - Floating, semi-transparent
--------------------------------------------------------- */
.scroll-to-top,
.scroll-to-bottom {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 44px;
height: 44px;
background: rgba(0, 212, 255, 0.3);
color: var(--color-text);
border: 1px solid rgba(0, 212, 255, 0.4);
border-radius: 50%;
font-size: 1.3rem;
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
z-index: 50;
transition: var(--transition);
}
.scroll-to-top:active,
.scroll-to-bottom:active {
background: rgba(0, 212, 255, 0.6);
transform: scale(0.95);
}
.scroll-to-top {
right: 10px;
bottom: 150px;
}
.scroll-to-bottom {
right: 10px;
bottom: 70px;
}
/* ---------------------------------------------------------
Footer - Hidden on scanner
--------------------------------------------------------- */
.footer {
display: none;
}
}

View File

@@ -1,5 +1,6 @@
/* ScanLook - Inventory Management System CSS */
/* Mobile-first, high-contrast design optimized for warehouse scanners */
/* Desktop-first design - mobile/scanner overrides in separate files */
/* Files: style.css (base), mobile.css (phones), scanner.css (MC9300) */
@import url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;600;700;800&family=JetBrains+Mono:wght@500;700&display=swap');
@@ -1385,9 +1386,10 @@ body {
}
.scan-row-weight_discrepancy {
border-color: #ff9800; /* Orange Border */
background: rgba(255, 152, 0, 0.05); /* Very light orange background */
border-color: #ff9800;
background: rgba(255, 152, 0, 0.05);
}
.scan-row-wrong_location {
border-color: var(--color-warning);
background: rgba(255, 170, 0, 0.05);
@@ -1696,12 +1698,6 @@ body {
gap: var(--space-lg);
}
@media (max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
}
}
.finish-section {
position: sticky;
bottom: var(--space-lg);
@@ -1713,123 +1709,6 @@ body {
gap: var(--space-md);
}
/* ==================== MOBILE OPTIMIZATIONS ==================== */
@media (max-width: 768px) {
html {
font-size: 14px;
}
.nav-content {
flex-direction: row;
gap: var(--space-md);
}
.sessions-grid {
grid-template-columns: 1fr;
}
.session-stats {
grid-template-columns: repeat(3, 1fr);
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.baseline-grid {
grid-template-columns: 1fr;
}
.dashboard-header {
flex-direction: column;
align-items: stretch;
gap: var(--space-md);
}
.scan-input {
font-size: 1.25rem;
}
.location-name {
font-size: 2rem;
}
/* Scan Detail Modal Mobile Fixes */
.modal-content {
padding: var(--space-md);
margin: var(--space-xs);
}
.modal-header-bar {
padding: var(--space-md) 0;
margin-bottom: var(--space-md);
}
.detail-section {
padding: var(--space-md) 0;
}
.detail-row {
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) 0;
}
.detail-label {
flex: none;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.detail-value {
font-size: 1rem;
}
.detail-lot {
font-size: 0.95rem;
word-break: break-all;
}
.detail-input {
width: 100%;
font-size: 1rem;
}
.detail-section-title {
font-size: 1rem;
margin-bottom: var(--space-sm);
}
.detail-form {
gap: var(--space-sm);
}
.form-group {
margin-bottom: var(--space-sm);
}
.modal-large,
.modal-xl {
width: 95%;
max-width: 95%;
margin: var(--space-xs);
}
.detail-actions {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-md) 0 0 0;
}
.detail-actions .btn {
width: 100%;
margin: 0;
}
}
/* Scrollbar Styling */
::-webkit-scrollbar {
width: 10px;
@@ -1926,21 +1805,6 @@ body {
color: var(--color-text-muted);
}
/* Colored column headers */
.detail-table th.col-counted {
background: var(--color-bg);
}
.detail-table th.col-expected {
background: #3d2d00;
color: var(--color-warning);
}
.detail-table th.col-current {
background: #00293d;
color: var(--color-duplicate);
}
.detail-table td {
padding: var(--space-md);
border: none;
@@ -2118,10 +1982,6 @@ body {
gap: var(--space-sm);
}
.btn-block {
width: 100%;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
@@ -2233,9 +2093,8 @@ body {
/* Expected rows look "pending" or "unscanned" */
.expected-row {
opacity: 0.7;
border-left: 4px solid var(--color-border); /* Neutral/Gray border */
background: var(--color-surface); /* Darker than scanned rows */
/* Use the same grid layout as scanned rows */
border-left: 4px solid var(--color-border);
background: var(--color-surface);
display: grid;
grid-template-columns: 2fr 1fr 1fr 1.5fr;
gap: var(--space-md);
@@ -2255,156 +2114,8 @@ body {
box-shadow: none;
}
/* ==================== ZEBRA MC9300 CONSOLIDATED FIX ==================== */
@media screen and (max-width: 480px) and (max-height: 600px) {
:root {
--space-2xl: 0.8rem !important;
--space-xl: 0.6rem !important;
--space-lg: 0.4rem !important;
--space-md: 0.3rem !important;
}
/* Header & Nav Hiding */
.user-badge, .role-pill, .breadcrumb { display: none !important; }
.navbar { padding: 4px 10px !important; height: 38px !important; }
.logo { font-size: 1rem !important; }
.btn-logout { padding: 2px 8px !important; font-size: 0.7rem !important; }
/* Compact Titles */
.page-title { font-size: 1.1rem !important; margin: 0 !important; padding: 2px 0 !important; }
.page-header { margin-bottom: 5px !important; flex-direction: row !important; align-items: center !important; }
/* Compact Location Header */
.location-header { padding: 5px !important; margin-bottom: 5px !important; border-width: 1px !important; }
.location-label { font-size: 0.6rem !important; margin: 0 !important; }
.location-name { font-size: 1.4rem !important; margin: 0 !important; }
.stat-pill { padding: 2px 6px !important; font-size: 0.7rem !important; }
/* Compact Input Area */
.scan-card { padding: 8px !important; margin-bottom: 6px !important; }
.scan-header { display: none !important; } /* Hide "Scan Lot Barcode" text to save space */
.scan-input {
padding: 8px !important;
font-size: 1.1rem !important;
height: 40px !important;
border-width: 2px !important;
}
/* ---------------------------------------------------------
UPDATED LIST LAYOUT (Single Line, No Status Text)
--------------------------------------------------------- */
/* Reconfigure grid to 3 columns: Lot | Item | Weight (Status hidden) */
.scan-row, .expected-row {
grid-template-columns: 2fr 1.5fr 1fr !important;
gap: 5px !important;
padding: 8px 6px !important;
margin-bottom: 2px !important;
font-size: 0.8rem !important;
/* Increase background opacity so color is visible without the badge */
}
/* Hide the status column completely */
.scan-row-status { display: none !important; }
/* Make background colors slightly more visible since the text is gone */
.scan-row-match { background: rgba(0, 255, 136, 0.15) !important; }
.scan-row-wrong_location { background: rgba(255, 170, 0, 0.15) !important; }
.scan-row-ghost_lot { background: rgba(179, 102, 255, 0.15) !important; }
.scan-row-duplicate-01, .scan-row-duplicate-04 { background: rgba(0, 163, 255, 0.15) !important; }
.scan-row-duplicate-03 { background: rgba(255, 140, 0, 0.15) !important; }
/* Font tweaks for readability on small screen */
.scan-row-lot { font-size: 0.9rem !important; }
.scan-row-item { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* List Containers */
.scans-section, .expected-section { padding: 4px !important; border-width: 1px !important; }
.scans-header { margin-bottom: 2px !important; padding-bottom: 2px !important; }
.scans-title { font-size: 0.85rem !important; }
/* Scrollable areas - constrain height so page doesn't scroll infinitely */
.scans-grid { max-height: 150px !important; overflow-y: auto !important; }
/* Action Buttons (Fixed at bottom) */
.finish-section { margin-top: 5px !important; padding-top: 5px !important; }
.action-buttons-row { display: flex !important; gap: 5px !important; }
.action-buttons-row .btn { padding: 8px !important; font-size: 0.8rem !important; height: 38px !important; }
/* Hide footer on scanner */
.footer { display: none !important; }
}
/* ==================== SCANNING INTERFACE (COUNT LOCATION) ==================== */
@media screen and (max-width: 480px) and (max-height: 600px) {
/* 1. Shrink the Location Header (R303D area) */
.location-header {
padding: 8px !important;
margin-bottom: 5px !important;
border-width: 1px !important;
}
.location-label { font-size: 0.6rem !important; margin: 0 !important; }
.location-name { font-size: 1.5rem !important; margin: 0 !important; }
.location-stats { gap: 5px !important; }
.stat-pill { padding: 2px 8px !important; font-size: 0.7rem !important; }
/* 2. Compact Scan Input Card */
.scan-card {
padding: 10px !important;
margin-bottom: 8px !important;
}
.scan-header { margin-bottom: 5px !important; }
.scan-title { font-size: 1rem !important; }
.scan-input {
padding: 10px !important;
font-size: 1.1rem !important;
height: 44px !important;
border-width: 2px !important;
}
/* 3. Reclaim Space from the Scanned List */
.scans-section { padding: 5px !important; }
.scans-header { margin-bottom: 4px !important; }
.scans-title { font-size: 0.9rem !important; }
.scans-grid { max-height: 180px !important; } /* Ensure list is visible but short */
/* 4. FIX THE GIANT FLOATING BUTTONS */
.finish-section {
position: relative !important; /* Stop it from floating over content */
bottom: 0 !important;
margin-top: 10px !important;
}
.action-buttons-row {
display: flex !important;
gap: 8px !important;
}
/* Make "Back" small and "Finish" primary but compact */
.action-buttons-row .btn {
flex: 1;
padding: 8px !important;
font-size: 0.85rem !important;
min-height: 40px !important;
}
.btn-success {
background: var(--color-success) !important;
box-shadow: none !important; /* Remove glow to save rendering power */
}
/* Inside the @media query ... */
/* Make background colors slightly more visible since the text is gone */
.scan-row-match { background: rgba(0, 255, 136, 0.15) !important; }
.scan-row-wrong_location { background: rgba(255, 170, 0, 0.15) !important; }
.scan-row-ghost_lot { background: rgba(179, 102, 255, 0.15) !important; }
/* ADD THIS LINE: */
.scan-row-weight_discrepancy { background: rgba(255, 152, 0, 0.25) !important; }
.scan-row-duplicate-01, .scan-row-duplicate-04 { background: rgba(0, 163, 255, 0.15) !important; }
.scan-row-duplicate-03 { background: rgba(255, 140, 0, 0.15) !important; }
/* Hide scroll buttons on desktop */
.scroll-to-top,
.scroll-to-bottom {
display: none;
}

View File

@@ -8,6 +8,9 @@
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
<title>{% block title %}ScanLook{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/mobile.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/scanner.css') }}">
{% block extra_css %}{% endblock %}
</head>
<body>

View File

@@ -168,6 +168,16 @@
</button>
</div>
</div>
<button class="scroll-to-top" onclick="window.scrollTo({top: 0, behavior: 'smooth'})">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
</button>
<button class="scroll-to-bottom" onclick="window.scrollTo({top: document.body.scrollHeight, behavior: 'smooth'})">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
</div>
<script>