The window a shop assistant stares at all day was the weakest surface in
this system, and it looked improvised because it was: navigation drawn
with text characters (◉ ☺ ▢) that sit on the text baseline and cannot
take a stroke weight, margins set inline per screen, and four large stat
boxes dominating the page while the product's entire reason for existing
- WHO JUST WALKED IN - was a list of "person.seen" rows in the corner.
Rebuilt around the person in front of it: a counter, a cheap monitor,
somebody mid-conversation with a customer.
- ui/icons.jsx: one drawn icon set, 24-unit grid, 1.6 stroke,
currentColor, so one icon works on every surface and in every state.
- styles.css: a real system. Four-step ground→raised palette biased
blue-green (this product lives in the world of lenses), one spacing
scale, one type scale, tabular figures wherever digits are compared
or refreshed in place, and the scrollbars restyled - the default
light scrollbar on a dark panel is the loudest "web page in a frame"
tell there is.
- Live: a status strip that answers "is this working" in one line,
cameras as pictures with the caption over the image, and arrivals as
cards big enough to match against the person standing there. The
four stat boxes became a slim strip at the foot, where numbers that
nobody acts on belong.
- State is carried by shape AND colour everywhere - a pill, a dot and
an edge stripe - because this gets read from two metres away and
some operators do not see red and green apart.
- Motion only where it means something: a live camera pulses, a fresh
arrival slides in once. Nothing loops for decoration; this process
shares a CPU with recognition.
Two things fixed because the screen showed them, not because a test did:
- The sidebar read "Stopped" beside a live camera feed and a counter
ticking up, whenever the engine was running but not started BY the
app. That is the two-surfaces-disagreeing bug the tray exists to
avoid. It now reads "Running outside the app" in amber, and Start is
disabled rather than offering to launch a second engine onto one
SQLite WAL.
- The arrivals panel shrank to fit its content and left a hole beside
a tall camera tile - so the layout looked broken exactly when the
shop was quiet, which is most of the time. Both panels stretch and
scroll their own content now.
Every existing class name still resolves, so the screens not rewritten
here pick the system up unchanged. Windows and darwin build; tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
2 lines
18 KiB
CSS
2 lines
18 KiB
CSS
:root{--bg: #0A0F13;--s1: #111A20;--s2: #17232B;--s3: #1E2D37;--line: #223038;--line-2: #1A252C;--ink: #ECF3F7;--ink-2: #A3B6C2;--ink-3: #6C808D;--accent: #40C4DC;--accent-2: #0F3B47;--accent-3: #0B2A33;--ok: #48C78E;--ok-2: #102E22;--warn: #EAAA3D;--warn-2: #31260F;--bad: #EC6A5C;--bad-2: #331815;--r-sm: 6px;--r: 10px;--r-lg: 14px;--sp-1: 4px;--sp-2: 8px;--sp-3: 12px;--sp-4: 16px;--sp-5: 20px;--sp-6: 24px;--sp-7: 32px;--sp-8: 40px;--shadow: 0 1px 2px rgb(0 0 0 / .4), 0 8px 24px -12px rgb(0 0 0 / .6);--shadow-lg: 0 2px 4px rgb(0 0 0 / .4), 0 24px 48px -16px rgb(0 0 0 / .7);--font: "Segoe UI Variable Text", "Segoe UI", Inter, -apple-system, BlinkMacSystemFont, system-ui, "Helvetica Neue", Arial, sans-serif;--font-display: "Segoe UI Variable Display", var(--font);--mono: "Cascadia Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;--ground: var(--bg);--surface: var(--s1);--surface-2: var(--s2);--line-soft: var(--line-2);--muted: var(--ink-3);--radius: var(--r);--accent-dim: var(--accent-3)}*{box-sizing:border-box;margin:0}html,body,#root{height:100%}body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden;-webkit-user-select:none;user-select:none}button,input,select,textarea{font:inherit;color:inherit}input,textarea{-webkit-user-select:text;user-select:text}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}::selection{background:var(--accent-2);color:var(--ink)}.num,.value,.metric-v,.when,.mono,.code,td{font-variant-numeric:tabular-nums}.mono,.code{font-family:var(--mono)}*{scrollbar-width:thin;scrollbar-color:var(--s3) transparent}*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--s3);border-radius:99px;border:3px solid var(--bg)}*::-webkit-scrollbar-thumb:hover{background:#2a3d49}.shell{display:grid;grid-template-columns:232px 1fr;height:100%}.side{background:var(--s1);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0}.side .brand{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-5) var(--sp-5) var(--sp-4)}.side .brand .mark{width:30px;height:30px;border-radius:9px;flex:none;display:grid;place-items:center;background:linear-gradient(160deg,var(--accent-2),var(--s2));border:1px solid #1B4C5A;color:var(--accent)}.side .brand .id{min-width:0}.side .brand h1{font-family:var(--font-display);font-size:15px;font-weight:600;letter-spacing:-.012em;line-height:1.2}.side .brand p{font-size:11.5px;color:var(--ink-3);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav{padding:var(--sp-2) var(--sp-3);display:flex;flex-direction:column;gap:2px;flex:1}.nav button{position:relative;display:flex;align-items:center;gap:var(--sp-3);width:100%;background:none;border:0;border-radius:var(--r-sm);padding:9px var(--sp-3);color:var(--ink-2);cursor:pointer;text-align:left;font-size:13.5px;font-weight:450;transition:background .12s ease,color .12s ease}.nav button svg{flex:none;opacity:.9}.nav button:hover{background:var(--s2);color:var(--ink)}.nav button[aria-current=page]{background:var(--accent-3);color:var(--accent);font-weight:550}.nav button[aria-current=page]:before{content:"";position:absolute;left:-12px;top:7px;bottom:7px;width:2.5px;border-radius:0 2px 2px 0;background:var(--accent)}.enginebox{margin:var(--sp-3);padding:var(--sp-3) var(--sp-4) var(--sp-4);border:1px solid var(--line);border-radius:var(--r);background:var(--s2)}.enginebox .row{display:flex;align-items:center;gap:var(--sp-2)}.enginebox .state{font-size:12.5px;font-weight:600;letter-spacing:-.005em}.enginebox .label{display:block;color:var(--ink-3);font-size:11px;line-height:1.45;margin-top:3px;font-variant-numeric:tabular-nums}.enginebox .actions,.enginebox .controls{display:flex;gap:var(--sp-2);margin-top:var(--sp-3)}.enginebox .actions .btn,.enginebox .controls .btn{flex:1;justify-content:center;padding:6px 8px;font-size:12px}.side .who{padding:var(--sp-3) var(--sp-5) var(--sp-5);border-top:1px solid var(--line-2);display:flex;align-items:center;gap:var(--sp-3)}.side .who .id{min-width:0;flex:1}.side .who .id b{display:block;font-size:12.5px;font-weight:550}.side .who .id span{display:block;font-size:11px;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.main{min-width:0;min-height:0;overflow:auto}.page{padding:var(--sp-6) var(--sp-7) var(--sp-8);max-width:1500px}.page>header{margin-bottom:var(--sp-5)}.page>header h2,.page h2{font-family:var(--font-display);font-size:22px;font-weight:600;letter-spacing:-.02em;line-height:1.2}.page>header p,.page header p{color:var(--ink-3);font-size:13px;margin-top:3px}.pagehead{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);margin-bottom:var(--sp-5);flex-wrap:wrap}h3{font-size:11px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.card{background:var(--s1);border:1px solid var(--line);border-radius:var(--r);padding:var(--sp-4)}.card>h3{margin-bottom:var(--sp-3)}.card.flush{padding:0;overflow:hidden}.panel{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;min-height:0}.panel>.panelhead{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-2);background:linear-gradient(var(--s2),var(--s1));flex:none}.panel>.panelhead h3{margin:0}.panel>.panelbody{padding:var(--sp-4);min-height:0;overflow:auto}.panel>.panelbody.flush{padding:0}.grid{display:grid;gap:var(--sp-4)}.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (max-width: 1180px){.cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width: 980px){.cols-2,.cols-3{grid-template-columns:minmax(0,1fr)}}.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(152px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}.metric{background:var(--s1);padding:var(--sp-3) var(--sp-4) var(--sp-4)}.metric .metric-k{font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.metric .metric-v{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1;margin-top:5px}.metric .metric-s{font-size:11.5px;color:var(--ink-3);margin-top:3px;line-height:1.4}.metric.ok .metric-v{color:var(--ok)}.metric.warn .metric-v{color:var(--warn)}.metric.bad .metric-v{color:var(--bad)}.stat h3{margin-bottom:var(--sp-2)}.stat .value{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1}.stat .unit{font-size:15px;color:var(--ink-3);margin-left:3px}.stat .sub{font-size:11.5px;color:var(--ink-3);margin-top:4px;line-height:1.4}.dot{width:7px;height:7px;border-radius:99px;flex:none;background:var(--ink-3)}.dot.ok{background:var(--ok);box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 18%,transparent)}.dot.warn{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 18%,transparent)}.dot.bad{background:var(--bad);box-shadow:0 0 0 3px color-mix(in srgb,var(--bad) 18%,transparent)}.dot.idle{background:var(--ink-3)}.dot.live{background:var(--ok);animation:pulse 2.4s ease-in-out infinite}@keyframes pulse{0%,to{box-shadow:0 0 color-mix(in srgb,var(--ok) 55%,transparent)}70%{box-shadow:0 0 0 6px color-mix(in srgb,var(--ok) 0%,transparent)}}.pill{display:inline-flex;align-items:center;gap:6px;padding:3px 9px 3px 7px;border-radius:99px;font-size:11px;font-weight:600;letter-spacing:.02em;background:var(--s3);color:var(--ink-2);border:1px solid var(--line);white-space:nowrap}.pill.ok{background:var(--ok-2);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 28%,transparent)}.pill.warn{background:var(--warn-2);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 28%,transparent)}.pill.bad{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 28%,transparent)}.pill.accent{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 30%,transparent)}.tag{display:inline-flex;align-items:center;padding:2px 7px;border-radius:var(--r-sm);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:var(--s3);color:var(--ink-2)}.tag.new{background:var(--accent-3);color:var(--accent)}.tag.seen{background:var(--ok-2);color:var(--ok)}.tag.miss{background:var(--warn-2);color:var(--warn)}.statusbar{display:flex;align-items:center;gap:var(--sp-5);flex-wrap:wrap;padding:var(--sp-3) var(--sp-4);background:var(--s1);border:1px solid var(--line);border-radius:var(--r);margin-bottom:var(--sp-4)}.statusbar .item{display:flex;align-items:center;gap:var(--sp-2);font-size:12.5px}.statusbar .item b{font-weight:600;letter-spacing:-.005em}.statusbar .item svg{color:var(--ink-3)}.statusbar .sep{width:1px;align-self:stretch;background:var(--line)}.statusbar .grow{flex:1}.arrivals{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-3)}.arrival{display:grid;grid-template-columns:46px 1fr auto;gap:var(--sp-3);align-items:center;padding:var(--sp-3);border-radius:var(--r);background:var(--s2);border:1px solid var(--line-2);position:relative;overflow:hidden}.arrival:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2.5px;background:var(--ink-3)}.arrival.is-new:before{background:var(--accent)}.arrival.is-seen:before{background:var(--ok)}.arrival.is-miss:before{background:var(--warn)}.arrival.fresh{animation:slidein .28s cubic-bezier(.2,.8,.3,1)}@keyframes slidein{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.arrival .avatar{width:46px;height:46px;border-radius:var(--r-sm);display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-family:var(--font-display);font-size:15px;font-weight:600;color:var(--ink-2);letter-spacing:-.01em;font-variant-numeric:tabular-nums}.arrival .avatar img{width:100%;height:100%;object-fit:cover}.arrival.is-new .avatar{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 25%,transparent)}.arrival .who{min-width:0}.arrival .who .name{font-size:14.5px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .who .meta{font-size:11.5px;color:var(--ink-3);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .right{text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:5px}.arrival .right .when{font-size:11.5px;color:var(--ink-3)}.feeds{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));padding:var(--sp-3)}.feed{position:relative;border-radius:var(--r);overflow:hidden;background:#05090c;border:1px solid var(--line);aspect-ratio:16 / 9}.feed img{width:100%;height:100%;object-fit:cover;display:block}.feed .placeholder{width:100%;height:100%;display:grid;place-items:center;color:var(--ink-3)}.feed .cap{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);padding:var(--sp-5) var(--sp-3) var(--sp-3);background:linear-gradient(transparent,#000c);font-size:12.5px;font-weight:600;letter-spacing:-.005em}.events,.timeline{list-style:none;padding:0;display:flex;flex-direction:column}.events li{display:flex;align-items:center;gap:var(--sp-3);padding:9px var(--sp-4);border-bottom:1px solid var(--line-2);font-size:13px}.timeline li{display:flex;align-items:center;gap:var(--sp-3);padding:9px 0;border-bottom:1px solid var(--line-2);font-size:13px}.events li:last-child,.timeline li:last-child{border-bottom:0}.events .when,.timeline .when{font-size:11.5px;color:var(--ink-3);width:46px;flex:none}.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-3);padding:var(--sp-8) var(--sp-5);color:var(--ink-3);text-align:center;font-size:12.5px}.empty svg{opacity:.35}.empty b{display:block;color:var(--ink-2);font-size:13.5px;font-weight:550}.empty p{max-width:34ch;line-height:1.5}.tablewrap{overflow:auto}table{border-collapse:collapse;width:100%;font-size:13px}th{text-align:left;padding:9px var(--sp-4);font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3);background:var(--s2);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1}td{padding:10px var(--sp-4);border-bottom:1px solid var(--line-2)}tbody tr:last-child td{border-bottom:0}tbody tr[role=button],tbody tr.clickable{cursor:pointer}tbody tr[role=button]:hover,tbody tr.clickable:hover{background:var(--s2)}.btn{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:var(--r-sm);background:var(--s3);color:var(--ink);border:1px solid var(--line);cursor:pointer;font-size:13px;font-weight:550;letter-spacing:-.005em;white-space:nowrap;transition:background .12s ease,border-color .12s ease,transform .06s ease}.btn:hover:not(:disabled){background:#253643;border-color:#2e414e}.btn:active:not(:disabled){transform:translateY(.5px)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn svg{flex:none}.btn.primary{background:var(--accent);color:#04171c;border-color:transparent;font-weight:600}.btn.primary:hover:not(:disabled){background:#55d0e6}.btn.danger{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 32%,transparent)}.btn.danger:hover:not(:disabled){background:#43201c}.btn.ghost{background:transparent}.btn.ghost:hover:not(:disabled){background:var(--s2)}.btn.sm{padding:5px 10px;font-size:12px}.btn.icon{padding:7px}.linkbtn{background:none;border:0;color:var(--accent);cursor:pointer;font-size:12.5px;padding:2px 0;text-align:left}.linkbtn:hover{text-decoration:underline}.seg{display:inline-flex;background:var(--s2);border:1px solid var(--line);border-radius:var(--r-sm);padding:2px;gap:2px}.seg button{background:none;border:0;border-radius:4px;padding:5px 11px;color:var(--ink-3);cursor:pointer;font-size:12.5px;font-weight:500}.seg button[aria-pressed=true]{background:var(--s3);color:var(--ink)}.field{display:block;margin-bottom:var(--sp-4)}.field>span{display:block;font-size:11.5px;font-weight:550;color:var(--ink-2);margin-bottom:6px}.field input,.field select,.field textarea{width:100%;padding:9px 11px;background:var(--s2);color:var(--ink);border:1px solid var(--line);border-radius:var(--r-sm);transition:border-color .12s ease,background .12s ease,box-shadow .12s ease}.field input::placeholder{color:var(--ink-3)}.field input:hover,.field select:hover,.field textarea:hover{border-color:#2c3d49}.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent);background:var(--s1);box-shadow:0 0 0 3px var(--accent-3)}.field .hint{display:block;font-size:11.5px;color:var(--ink-3);margin-top:5px;line-height:1.45}.fieldrow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3)}.fieldrow.three{grid-template-columns:repeat(3,minmax(0,1fr))}.err{display:flex;align-items:flex-start;gap:var(--sp-2);background:var(--bad-2);color:var(--bad);border:1px solid color-mix(in srgb,var(--bad) 30%,transparent);border-radius:var(--r-sm);padding:9px 11px;font-size:12.5px;line-height:1.45;margin-bottom:var(--sp-4)}.err svg{flex:none;margin-top:1px}.note{color:var(--ink-3);font-size:12px;line-height:1.5}.note.warn{color:var(--warn)}.note.bad{color:var(--bad)}.lead{color:var(--ink-2);font-size:13.5px;line-height:1.55}.sm{font-size:12px}.lbl,.key{color:var(--ink-3);font-size:11.5px}.grow{flex:1}.row{display:flex;align-items:center;gap:var(--sp-3)}.login{height:100%;display:grid;place-items:center;padding:var(--sp-6);overflow:auto;background:radial-gradient(900px 480px at 50% -10%,#10303A 0%,transparent 62%),var(--bg)}.login .box{width:100%;max-width:396px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-7);box-shadow:var(--shadow-lg)}.login .mark{width:38px;height:38px;border-radius:11px;margin-bottom:var(--sp-4);display:grid;place-items:center;color:var(--accent);background:linear-gradient(160deg,var(--accent-2),var(--s2));border:1px solid #1B4C5A}.login h1{font-family:var(--font-display);font-size:21px;font-weight:600;letter-spacing:-.022em}.login .lead{margin:6px 0 var(--sp-5)}.login .btn{width:100%;justify-content:center;margin-top:var(--sp-1)}.login .foot{font-size:11.5px;color:var(--ink-3);line-height:1.55;margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--line-2)}.login .alt{margin-top:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.login .alt .btn{margin-top:0}.login .note{margin:0}.drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;background:#04080b99;display:flex;justify-content:flex-end;animation:fade .16s ease}@keyframes fade{0%{opacity:0}to{opacity:1}}.drawer .sheet{width:min(540px,100%);height:100%;overflow:auto;background:var(--s1);border-left:1px solid var(--line);box-shadow:var(--shadow-lg);animation:slidein-r .2s cubic-bezier(.2,.8,.3,1)}@keyframes slidein-r{0%{transform:translate(16px);opacity:.6}to{transform:none;opacity:1}}.drawer .sheethead{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-4) var(--sp-5);background:var(--s1);border-bottom:1px solid var(--line)}.drawer .sheethead h2{font-family:var(--font-display);font-size:17px;font-weight:600;letter-spacing:-.015em}.drawer .sheetbody{padding:var(--sp-5)}.drawer .close{background:none;border:0;color:var(--ink-3);cursor:pointer;padding:6px;border-radius:var(--r-sm);display:grid;place-items:center}.drawer .close:hover{background:var(--s2);color:var(--ink)}.avatar{width:44px;height:44px;border-radius:var(--r-sm);flex:none;display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-weight:600;color:var(--ink-2);font-variant-numeric:tabular-nums}.avatar img{width:100%;height:100%;object-fit:cover}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation:none!important;transition:none!important}}.live-split{display:grid;gap:var(--sp-4);grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);align-items:stretch;min-height:420px}.live-split>.panel{max-height:62vh}@media (max-width: 1100px){.live-split{grid-template-columns:minmax(0,1fr)}.live-split>.panel{max-height:none}}
|