/* ==========================================================================
   Consign POS — interface
   --------------------------------------------------------------------------
   Layers, in order: tokens, base, shell, primitives, screens, overlays.
   Nothing below the primitives layer invents a colour or a spacing value;
   they all come from the tokens at the top, so a change to the brand is a
   change to one block rather than a hunt through a stylesheet.
   ========================================================================== */

/* Poppins, self-hosted (32KB total). It is the geometric sans the logo
   wordmark is set in — circular O and C, flat-barred G — so the header
   lockup reads as one piece with the mark instead of two typefaces sharing
   a bar. Self-hosted rather than linked: the register should not depend on
   a third-party CDN being reachable to render its own name. */
@font-face{font-family:Poppins;src:url(/fonts/poppins-400.woff2) format('woff2');
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Poppins;src:url(/fonts/poppins-500.woff2) format('woff2');
  font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Poppins;src:url(/fonts/poppins-600.woff2) format('woff2');
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:Poppins;src:url(/fonts/poppins-700.woff2) format('woff2');
  font-weight:700;font-style:normal;font-display:swap}

/* ============================== 1. tokens ============================== */

:root{
  /* brand */
  --ink:#18222f; --ink-2:#243144; --ink-3:#5a6b80; --ink-4:#62707f;
  --gold:#b8a888; --gold-lt:#dcd2bc; --gold-dk:#8a7b5d;
  /* gold-dk is 4.1:1 on paper — fine for icons and 27px figures, short of
     4.5:1 for small text. gold-ink is the same hue taken far enough down to
     carry a 14px number a shop is going to pay somebody against. */
  --gold-ink:#7a6c4f;
  --cream:#f7f5f0; --paper:#ffffff; --line:#e7e2d8; --line-2:#f1ede5;
  --ok:#0f7743; --warn:#985e16; --bad:#b4342a;

  /* surfaces — the canvas is a shade cooler than paper so raised cards read
     as raised without needing a heavy shadow to say so */
  --bg:#f4f2ec;
  --surface:var(--paper);
  --surface-2:var(--cream);
  --surface-ink:#18222f;
  --border:var(--line);
  --border-2:var(--line-2);
  --border-strong:#d9d2c4;

  /* The instrument surface — the one dark ground in a light application.
     A log is machine output and reads faster when it does not pretend to be
     part of the document, so it gets its own small palette rather than
     inverting the page's. Named by role, not by colour: --term-warn is
     whatever amber reads correctly on --term, which is not the amber that
     reads correctly on paper. */
  --term:#0e1218;        --term-line:#1d232d;
  --term-ink:#c9d3e0;    --term-dim:#5d6b7f;
  --term-src:#8aa0bd;    --term-meta:#6f8098;
  --term-info:#5f9ea0;   --term-debug:#6b7686;
  --term-warn:#e0a138;   --term-warn-ink:#f0c882;
  --term-bad:#ef6f63;    --term-bad-ink:#ffb3aa;

  /* tinted status surfaces, used for pills and inline notices */
  --ok-bg:#e8f5ee;   --ok-line:#bfe3d0;
  --warn-bg:#fdf3e3; --warn-line:#f0dcb8;
  --bad-bg:#fbeceb;  --bad-line:#f0cdc9;
  --info-bg:#eef2f7; --info-line:#d5dfea;

  /* type */
  --font-display:Poppins,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-ui:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --t-2xs:10.5px; --t-xs:11.5px; --t-sm:13px; --t-base:14px; --t-md:15px;
  --t-lg:17px; --t-xl:21px; --t-2xl:27px; --t-3xl:34px;

  /* space */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px;
  --s-6:24px; --s-8:32px; --s-10:40px; --s-12:48px;

  /* shape */
  --radius:14px; --radius-sm:10px; --r-xs:8px; --r-lg:20px; --r-full:999px;

  /* elevation */
  --shadow-sm:0 1px 2px rgba(24,34,47,.05);
  --shadow:0 1px 3px rgba(24,34,47,.05), 0 10px 28px -12px rgba(24,34,47,.18);
  --shadow-md:0 2px 6px rgba(24,34,47,.06), 0 18px 40px -18px rgba(24,34,47,.28);
  --shadow-lg:0 24px 64px -20px rgba(24,34,47,.35);

  /* motion */
  --ease:cubic-bezier(.2,.7,.3,1);
  --fast:.12s; --base:.2s; --slow:.34s;

  /* layout */
  --side-w:238px;
  --topbar-h:60px;
}

/* =============================== 2. base =============================== */

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:var(--t-md)/1.55 var(--font-ui);
  -webkit-text-size-adjust:100%;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;transition:background var(--fast) var(--ease),color var(--fast) var(--ease),
  border-color var(--fast) var(--ease),filter var(--fast) var(--ease),transform .08s var(--ease),
  box-shadow var(--fast) var(--ease)}
button:active{transform:translateY(.5px)}
[hidden]{display:none !important}
::selection{background:var(--gold-lt);color:var(--ink)}
:focus-visible{outline:2px solid var(--gold-dk);outline-offset:2px;border-radius:5px}
a{color:var(--ink)}
img{max-width:100%}

h1,h2,h3,h4,h5{font-family:var(--font-display);letter-spacing:.005em;margin:0}
h2{font-size:var(--t-lg);font-weight:600;margin:0 0 var(--s-3)}
h3{font-size:var(--t-md);font-weight:600}

.muted{color:var(--ink-3);font-size:var(--t-sm)}
.right{text-align:right}
.num{font-variant-numeric:tabular-nums}
.eyebrow{font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-4)}
.row{display:flex;gap:var(--s-2);flex-wrap:wrap;align-items:center}
.spacer{flex:1}

/* ============================== 3. splash ==============================
   Shown while enterApp() loads the shop's data, so the animation is doing
   the waiting for us. Removed with a fade; reduced-motion gets a short
   static frame instead of theatre. */

#splash{position:fixed;inset:0;z-index:100;display:grid;place-items:center;
  background:radial-gradient(120% 90% at 50% -10%,#22303f 0%,#1a2431 55%,#0e141c 100%);
  transition:opacity .55s var(--ease),visibility .55s}
#splash.out{opacity:0;visibility:hidden}
#splash .inner{text-align:center}
#splash .emblem{position:relative;width:148px;height:148px;margin:0 auto 26px}
#splash .emblem img{width:112px;height:112px;position:absolute;inset:0;margin:auto;
  animation:sp-mark 1s var(--ease) both;
  filter:drop-shadow(0 10px 30px rgba(184,168,136,.45))}
#splash .emblem svg{position:absolute;inset:0;transform:rotate(-90deg)}
#splash .emblem circle{fill:none;stroke:var(--gold);stroke-width:2;stroke-linecap:round;
  stroke-dasharray:452;stroke-dashoffset:452;opacity:.9;
  animation:sp-ring 1.1s .15s var(--ease) forwards}
#splash .word{font-family:var(--font-display);font-weight:600;font-size:21px;color:#fff;
  text-transform:uppercase;animation:sp-word .9s .5s var(--ease) both}
#splash .word em{font-style:normal;color:var(--gold-lt)}
#splash .tag{font-family:var(--font-display);font-size:10px;font-weight:500;color:#8d9cae;
  text-transform:uppercase;letter-spacing:.24em;margin-top:9px;
  animation:sp-tag .7s .95s var(--ease) both}
#splash .shopname{font-family:var(--font-display);font-size:12.5px;font-weight:600;
  color:var(--gold-lt);letter-spacing:.14em;text-transform:uppercase;margin-top:26px;
  min-height:16px;animation:sp-tag .7s 1.15s var(--ease) both}
@keyframes sp-mark{from{opacity:0;transform:scale(.55);filter:blur(6px)}
  60%{filter:blur(0)}to{opacity:1;transform:scale(1)}}
@keyframes sp-ring{to{stroke-dashoffset:0}}
@keyframes sp-word{from{opacity:0;letter-spacing:.55em;transform:translateY(6px)}
  to{opacity:1;letter-spacing:.2em;transform:none}}
@keyframes sp-tag{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  #splash .emblem img,#splash .emblem circle,#splash .word,#splash .tag,#splash .shopname{
    animation:none;opacity:1;stroke-dashoffset:0;letter-spacing:.2em}
}

/* =============================== 4. login =============================== */

#login{position:relative;min-height:100dvh;display:grid;place-items:center;padding:var(--s-6);
  overflow:hidden;isolation:isolate;
  background:radial-gradient(120% 90% at 50% -10%,#22303f 0%,#1a2431 55%,#0f151e 100%)}
#login::before{content:"";position:absolute;inset:-20%;z-index:-1;
  background:radial-gradient(42% 34% at 68% 28%,rgba(184,168,136,.14) 0%,transparent 100%),
    radial-gradient(36% 30% at 22% 78%,rgba(90,120,160,.12) 0%,transparent 100%);
  animation:loginglow 12s ease-in-out infinite alternate}
#login::after{content:"";position:absolute;z-index:-1;right:-18%;bottom:-22%;
  width:min(70vw,700px);aspect-ratio:1;background:url(/mark.png) center/contain no-repeat;
  opacity:.045;pointer-events:none}
@keyframes loginglow{from{transform:translate3d(0,0,0)}to{transform:translate3d(2%,3%,0)}}
@media(prefers-reduced-motion:reduce){#login::before{animation:none}}

.card{position:relative;background:var(--paper);border-radius:var(--r-lg);box-shadow:var(--shadow-lg);
  padding:38px 32px 32px;width:100%;max-width:392px;text-align:center;
  animation:cardin .6s var(--ease) both}
/* a gold hairline across the top edge — the jewellery on the box */
.card::before{content:"";position:absolute;top:0;left:24px;right:24px;height:2px;
  border-radius:0 0 3px 3px;
  background:linear-gradient(90deg,transparent,var(--gold) 30%,var(--gold-lt) 50%,var(--gold) 70%,transparent)}
@keyframes cardin{from{opacity:0;transform:translateY(18px) scale(.985)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.card{animation:none}}
.card img.logo{width:196px;height:auto;margin:0 auto 20px;display:block;
  filter:drop-shadow(0 6px 18px rgba(138,123,93,.28))}
.card h1{font-size:var(--t-lg);margin:0 0 3px;font-weight:600}
.card .sub{font-family:var(--font-display);color:var(--ink-4);font-size:10px;
  margin-bottom:26px;text-transform:uppercase;letter-spacing:.17em;font-weight:500}

/* =============================== 5. shell ===============================
   A fixed rail on the left, a scrolling work area on the right. The rail is
   dark so the working surface is unambiguously the lit part of the screen —
   the same reason a counter has a lamp over the till and not over the wall. */

.shell{display:grid;grid-template-columns:var(--side-w) minmax(0,1fr);min-height:100dvh}

.side{position:sticky;top:0;height:100dvh;display:flex;flex-direction:column;
  background:linear-gradient(180deg,#12151a 0%,#0b0d11 45%,#07090c 100%);
  color:#fff;z-index:30;border-right:1px solid rgba(255,255,255,.06)}
/* a whisper of gold down the rail's inner edge */
.side::after{content:"";position:absolute;top:0;bottom:0;right:-1px;width:1px;
  background:linear-gradient(180deg,transparent,rgba(184,168,136,.5) 12%,
    rgba(220,210,188,.62) 50%,rgba(184,168,136,.5) 88%,transparent)}

.side .brandbox{display:flex;align-items:center;gap:11px;padding:18px 16px 16px;min-width:0}
.side .brandbox img{width:36px;height:36px;flex:0 0 auto;
  filter:drop-shadow(0 2px 8px rgba(184,168,136,.35))}
.side .brand{font-family:var(--font-display);font-weight:600;font-size:13.5px;
  letter-spacing:.16em;line-height:1.1;text-transform:uppercase}
.side .brand em{font-style:normal;color:var(--gold-lt)}
.side .shop{font-family:var(--font-display);color:var(--gold-lt);font-size:var(--t-xs);
  letter-spacing:.09em;text-transform:uppercase;margin-top:3px;font-weight:500;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.side nav{display:flex;flex-direction:column;gap:2px;padding:6px 10px;flex:1;overflow-y:auto}
.side nav::-webkit-scrollbar{width:0}
.side nav button{position:relative;display:flex;align-items:center;gap:11px;width:100%;
  background:transparent;border:0;color:#9dadc0;padding:10px 12px;border-radius:var(--radius-sm);
  font-family:var(--font-display);font-size:var(--t-base);font-weight:500;letter-spacing:.01em;
  text-align:left}
.side nav button svg{width:18px;height:18px;flex:0 0 auto;stroke:currentColor;fill:none;
  stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;opacity:.85}
.side nav button:hover{color:#fff;background:rgba(255,255,255,.06)}
.side nav button[aria-current="true"]{color:#fff;background:rgba(255,255,255,.1)}
.side nav button[aria-current="true"] svg{opacity:1;color:var(--gold-lt)}
/* the gold marker slides in from the edge rather than switching on */
.side nav button::before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:3px;
  border-radius:0 3px 3px 0;background:linear-gradient(180deg,var(--gold-lt),var(--gold-dk));
  transform:scaleY(0);transform-origin:center;transition:transform var(--base) var(--ease)}
.side nav button[aria-current="true"]::before{transform:scaleY(1)}
@media(prefers-reduced-motion:reduce){.side nav button::before{transition:none}}
.side nav .count{margin-left:auto;font-size:var(--t-xs);font-weight:600;
  font-variant-numeric:tabular-nums;color:#8095ab;
  background:rgba(255,255,255,.07);border-radius:var(--r-full);padding:1px 7px;min-width:22px;
  text-align:center}
.side nav button[aria-current="true"] .count{color:#e6ecf3;background:rgba(255,255,255,.14)}

.side .userbox{border-top:1px solid rgba(255,255,255,.08);padding:12px;
  display:flex;align-items:center;gap:10px}
.side .avatar{width:34px;height:34px;border-radius:50%;flex:0 0 auto;display:grid;
  place-items:center;font-family:var(--font-display);font-weight:600;font-size:var(--t-sm);
  color:#241d10;background:linear-gradient(180deg,#e8ddc4,var(--gold) 70%,#a4936f)}
.side .who{min-width:0;flex:1;font-size:var(--t-sm);line-height:1.35}
.side .who b{display:block;color:#fff;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side .who span{color:#8fa1b4;font-size:var(--t-xs);text-transform:uppercase;letter-spacing:.09em}
.side .userbox button{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.16);
  color:#cfd9e4;border-radius:var(--r-xs);padding:7px 9px;font-size:var(--t-sm);line-height:1;
  flex:0 0 auto}
.side .userbox button:hover{background:rgba(255,255,255,.14);color:#fff}

.work{display:flex;flex-direction:column;min-width:0}

.topbar{position:sticky;top:0;z-index:20;height:var(--topbar-h);flex:0 0 auto;
  display:flex;align-items:center;gap:var(--s-3);padding:0 var(--s-6);
  background:rgba(244,242,236,.86);backdrop-filter:saturate(1.6) blur(10px);
  border-bottom:1px solid var(--border)}
.topbar h1{font-size:var(--t-lg);font-weight:600}
.topbar .sub{font-size:var(--t-sm);color:var(--ink-3);margin-top:1px}
.topbar .acts{display:flex;align-items:center;gap:var(--s-2);margin-left:auto}

main{padding:var(--s-6);max-width:1520px;width:100%;margin:0 auto;flex:1;min-width:0}
main > section{animation:tabin .28s var(--ease)}
@keyframes tabin{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){main > section{animation:none}}

/* tablet: the rail keeps its icons and loses its words */
@media(max-width:1100px){
  :root{--side-w:70px}
  .side .brandbox .lockup,.side nav button span.lbl,.side .who{display:none}
  .side .brandbox{justify-content:center;padding:16px 8px}
  .side nav button{justify-content:center;padding:11px 8px}
  .side nav .count{position:absolute;top:4px;right:6px;margin:0;padding:0 5px;font-size:10px}
  .side .userbox{flex-direction:column;gap:8px}
  main{padding:var(--s-4)}
  .topbar{padding:0 var(--s-4)}
}
/* phone / small tablet: rail becomes a bottom bar under the thumb */
@media(max-width:760px){
  .shell{grid-template-columns:1fr}
  .side{position:fixed;left:0;right:0;bottom:0;top:auto;height:auto;flex-direction:row;
    border-right:0;border-top:1px solid rgba(255,255,255,.08);
    padding-bottom:env(safe-area-inset-bottom)}
  .side::after{display:none}
  .side .brandbox,.side .userbox{display:none}
  .side nav{flex-direction:row;padding:4px;gap:0}
  .side nav button{flex-direction:column;gap:3px;font-size:var(--t-2xs);padding:7px 4px;
    letter-spacing:.04em}
  .side nav button span.lbl{display:block}
  .side nav button::before{left:9px;right:9px;top:0;bottom:auto;width:auto;height:3px;
    border-radius:0 0 3px 3px;transform:scaleX(0)}
  .side nav button[aria-current="true"]::before{transform:scaleX(1)}
  main{padding:var(--s-3) var(--s-3) 84px}
  .topbar{padding:0 var(--s-3)}
}

/* ============================ 6. primitives ============================ */

/* --- panels --- */
.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:var(--s-5);box-shadow:var(--shadow)}
.panel > h2:first-child{margin-top:0}
.panel-hd{display:flex;align-items:center;gap:var(--s-3);margin:0 0 var(--s-4)}
.panel-hd h2{margin:0}
.panel-hd .acts{margin-left:auto;display:flex;gap:var(--s-2);align-items:center}
.panel.flush{padding:0;overflow:hidden}
.panel.flush .panel-hd{padding:var(--s-4) var(--s-5);margin:0;border-bottom:1px solid var(--border-2)}
.panel.flush .panel-ft{padding:var(--s-3) var(--s-5);border-top:1px solid var(--border-2);
  background:var(--surface-2)}

.grid2{display:grid;grid-template-columns:minmax(0,1fr) 404px;gap:var(--s-5);align-items:start}
@media(max-width:1000px){.grid2{grid-template-columns:1fr}}

/* --- fields --- */
.field{text-align:left;margin-bottom:13px}
.field label{display:block;font-family:var(--font-display);font-size:var(--t-xs);font-weight:600;
  color:var(--ink-3);margin-bottom:6px;letter-spacing:.05em;text-transform:uppercase}
.field input{width:100%;padding:12px 13px;border:1px solid var(--border);
  border-radius:var(--radius-sm);background:#fff}

input,select,textarea{padding:10px 12px;border:1px solid var(--border);border-radius:var(--radius-sm);
  background:#fff;transition:border-color var(--fast) var(--ease),box-shadow var(--fast) var(--ease)}
input:hover,select:hover,textarea:hover{border-color:var(--gold)}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--gold-dk);
  box-shadow:0 0 0 3px rgba(184,168,136,.22)}
input::placeholder,textarea::placeholder{color:var(--ink-4)}
input[type=checkbox]{accent-color:var(--gold-dk)}

.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-3)}
.fgrid .full{grid-column:1/-1}
.fgrid label{display:block;font-size:var(--t-sm);font-weight:600;color:var(--ink-3);margin-bottom:4px}
.fgrid input,.fgrid select,.fgrid textarea{width:100%}

/* segmented control — one visible choice, thumb-sized targets */
.seg{display:flex;gap:2px;padding:3px;background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--radius-sm)}
.seg button{flex:1;border:0;background:transparent;color:var(--ink-3);border-radius:7px;
  padding:8px 10px;font-family:var(--font-display);font-size:var(--t-sm);font-weight:600}
.seg button:hover{color:var(--ink)}
.seg button[aria-pressed="true"]{background:var(--paper);color:var(--ink);
  box-shadow:var(--shadow-sm)}

/* --- buttons --- */
.btn{width:100%;padding:12px 16px;border:0;border-radius:var(--radius-sm);background:var(--ink);
  color:#fff;font-family:var(--font-display);font-weight:600;font-size:var(--t-base);
  letter-spacing:.01em;box-shadow:var(--shadow-sm);
  display:inline-flex;align-items:center;justify-content:center;gap:8px}
.btn:hover{background:var(--ink-2)}
.btn:disabled{opacity:.45;cursor:default;box-shadow:none}
.btn.gold{position:relative;overflow:hidden;
  background:linear-gradient(180deg,#e8ddc4 0%,var(--gold) 58%,#a4936f 100%);color:#241d10;
  box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 6px 18px -6px rgba(138,123,93,.55)}
.btn.gold:hover:not(:disabled){filter:brightness(1.05);
  box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 10px 24px -6px rgba(138,123,93,.65)}
.btn.gold::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(115deg,transparent 30%,rgba(255,255,255,.5) 50%,transparent 70%);
  transform:translateX(-130%)}
.btn.gold:hover:not(:disabled)::after{transform:translateX(130%);
  transition:transform .65s var(--ease)}
.btn.ghost{background:#fff;color:var(--ink);border:1px solid var(--border);box-shadow:none}
.btn.ghost:hover{background:var(--surface-2);border-color:var(--gold)}
.btn.slim{width:auto;padding:8px 14px;font-size:var(--t-sm)}
.btn.big{padding:17px 20px;font-size:var(--t-lg);border-radius:var(--radius)}
.btn.danger{background:var(--bad)}
.btn.danger:hover{background:#9c2c23}

/* a square button that carries only an icon or a single glyph */
.icon-btn{width:34px;height:34px;padding:0;display:inline-grid;place-items:center;
  border:1px solid var(--border);background:#fff;border-radius:var(--r-xs);color:var(--ink-3);
  font-size:var(--t-md);line-height:1}
.icon-btn:hover{color:var(--bad);border-color:var(--bad);background:var(--bad-bg)}

.msg{margin-top:var(--s-3);font-size:var(--t-sm);min-height:18px}
.msg.err{color:var(--bad)} .msg.ok{color:var(--ok)}

/* keyboard hint */
kbd,.kbd{font-family:var(--font-mono);font-size:var(--t-xs);background:var(--surface-2);
  border:1px solid var(--border);border-bottom-width:2px;border-radius:6px;padding:1px 6px;
  color:var(--ink-3)}

/* --- tables --- */
table{width:100%;border-collapse:collapse}
th,td{text-align:left;padding:11px 10px;border-bottom:1px solid var(--border-2);
  font-size:var(--t-base);vertical-align:middle}
th{font-family:var(--font-display);font-size:var(--t-2xs);text-transform:uppercase;
  letter-spacing:.1em;color:var(--ink-4);font-weight:600;
  border-bottom:1px solid var(--border);padding-bottom:9px}
tbody tr{transition:background var(--fast) var(--ease)}
tbody tr:hover{background:var(--surface-2)}
tbody tr:last-child td{border-bottom:0}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}

.thumb{width:44px;height:44px;border-radius:var(--r-xs);object-fit:cover;background:var(--surface-2);
  border:1px solid var(--border);display:block}
.thumb.ph{display:grid;place-items:center;color:var(--gold-dk);font-size:16px}

/* --- pills, dots, badges --- */
.pill{display:inline-flex;align-items:center;gap:5px;padding:2px 10px;border-radius:var(--r-full);
  font-size:var(--t-xs);font-weight:600;background:var(--surface-2);border:1px solid var(--border);
  font-family:var(--font-display);letter-spacing:.03em;white-space:nowrap}
.pill.ok{background:var(--ok-bg);border-color:var(--ok-line);color:var(--ok)}
.pill.bad{background:var(--bad-bg);border-color:var(--bad-line);color:var(--bad)}
.pill.warn{background:var(--warn-bg);border-color:var(--warn-line);color:var(--warn)}
.pill.info{background:var(--info-bg);border-color:var(--info-line);color:var(--ink-2)}

/* Status dots. Colour is never the only signal — every dot is paired with
   a written status, for colour-blind users and for anyone glancing at a
   screen in daylight behind a counter. */
.dot{width:11px;height:11px;border-radius:50%;flex:0 0 auto;display:inline-block;
  background:var(--ink-3);box-shadow:0 0 0 3px rgba(0,0,0,.04)}
.dot.ok{background:#18a558;box-shadow:0 0 0 3px rgba(24,165,88,.16)}
.dot.warn{background:#d9930a;box-shadow:0 0 0 3px rgba(217,147,10,.16)}
.dot.fail{background:#cf3b2c;box-shadow:0 0 0 3px rgba(207,59,44,.16)}
.dot.unknown{background:#98a4b3;box-shadow:0 0 0 3px rgba(152,164,179,.16)}
.dot.live{animation:pulse 1.6s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.45}}
@media(prefers-reduced-motion:reduce){.dot.live{animation:none}}

.navdot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-left:7px;
  vertical-align:middle;background:var(--ink-3);flex:0 0 auto}
.navdot.ok{background:#18a558} .navdot.warn{background:#d9930a} .navdot.fail{background:#cf3b2c}

/* --- empty states --- */
.empty{text-align:center;padding:var(--s-10) var(--s-3);color:var(--ink-3)}
.empty img{width:74px;opacity:.4;margin-bottom:var(--s-3)}
.empty h3{font-size:var(--t-md);color:var(--ink);margin-bottom:4px}
.empty p{margin:0 auto;max-width:38ch;font-size:var(--t-sm)}

/* --- spinner --- */
.spin{width:22px;height:22px;border-radius:50%;flex:0 0 auto;
  border:3px solid var(--border);border-top-color:var(--gold-dk);
  animation:spin 900ms linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.spin{animation-duration:2.4s}}

/* --- toggle switch ---
   A checkbox you can hit with a thumb. The input stays in the DOM and keeps
   doing the work — it is only visually replaced — so labels, focus, keyboard
   and form semantics all still behave. */
.sw{display:flex;align-items:center;gap:11px;cursor:pointer;padding:7px 0;
  font-size:var(--t-base);font-weight:500}
.sw input{position:absolute;opacity:0;width:0;height:0}
.sw .track{position:relative;flex:0 0 auto;width:40px;height:23px;border-radius:var(--r-full);
  background:#d7d2c7;border:1px solid var(--border);transition:background var(--fast) var(--ease)}
.sw .track::after{content:"";position:absolute;top:2px;left:2px;width:17px;height:17px;
  border-radius:50%;background:#fff;box-shadow:var(--shadow-sm);
  transition:transform var(--fast) var(--ease)}
.sw input:checked + .track{background:var(--gold-dk);border-color:var(--gold-dk)}
.sw input:checked + .track::after{transform:translateX(17px)}
.sw input:focus-visible + .track{outline:2px solid var(--gold-dk);outline-offset:2px}
.sw input:disabled + .track{opacity:.45}
.sw:has(input:disabled){cursor:default;opacity:.7}
.sw .lbl{min-width:0}
.sw .lbl small{display:block;font-weight:400;font-size:var(--t-sm);color:var(--ink-3);
  margin-top:1px;line-height:1.4}

/* --- chips (multi-select) --- */
.chips{display:flex;flex-wrap:wrap;gap:5px}
.chips label{display:inline-flex;align-items:center;font-size:var(--t-xs);padding:4px 11px;
  border:1px solid var(--border);border-radius:var(--r-full);background:#fff;cursor:pointer;
  user-select:none;transition:background var(--fast) var(--ease),border-color var(--fast) var(--ease)}
.chips label:hover{border-color:var(--gold)}
.chips input{position:absolute;opacity:0;width:0;height:0}
.chips label.on{background:var(--gold-lt);border-color:var(--gold-dk);font-weight:600}
.chips input:focus-visible + span{outline:2px solid var(--gold-dk);outline-offset:3px}
.tick{display:inline-flex;align-items:center;gap:7px;font-size:var(--t-base);font-weight:500;
  color:var(--ink);text-transform:none;letter-spacing:0}

/* ============================== 7. register ==============================
   The idle face of the till: the brand where the scan box would be, until
   the first scan or keystroke. The wedge works with the cover up, so a
   scanner needs no dismissal — the cover leaves when the item lands. */

#cover{min-height:clamp(420px,68vh,760px);border-radius:var(--radius);
  display:grid;place-items:center;cursor:pointer;position:relative;overflow:hidden;
  background:radial-gradient(120% 90% at 50% -10%,#22303f 0%,#1a2431 55%,#0e141c 100%);
  box-shadow:0 24px 64px -24px rgba(16,22,31,.5);
  transition:opacity .28s ease}
#cover.out{opacity:0}
#cover:not([hidden]) ~ .register{display:none}
#cover .inner{text-align:center;padding:40px 24px}
#cover .emblem{position:relative;width:132px;height:132px;margin:0 auto 24px}
#cover .emblem img{width:100px;height:100px;position:absolute;inset:0;margin:auto;
  filter:drop-shadow(0 10px 30px rgba(184,168,136,.45));
  animation:cv-breathe 5.5s ease-in-out infinite}
#cover .emblem svg{position:absolute;inset:0;transform:rotate(-90deg)}
#cover .emblem circle{fill:none;stroke:var(--gold);stroke-width:1.5;opacity:.85}
#cover .word{font-family:var(--font-display);font-weight:600;font-size:19px;color:#fff;
  letter-spacing:.2em;text-transform:uppercase}
#cover .word em{font-style:normal;color:var(--gold-lt)}
#cover .shopname{font-family:var(--font-display);font-size:12px;font-weight:600;
  color:var(--gold-lt);letter-spacing:.14em;text-transform:uppercase;margin-top:10px}
#cover .hint{display:inline-flex;align-items:center;gap:9px;margin-top:34px;
  font-family:var(--font-display);font-size:var(--t-xs);font-weight:500;color:#8d9cae;
  letter-spacing:.18em;text-transform:uppercase;
  padding:10px 20px;border:1px solid rgba(220,210,188,.22);border-radius:var(--r-full)}
#cover .hint::before{content:"";width:7px;height:7px;border-radius:50%;
  background:var(--gold);animation:cv-pulse 2.2s ease-in-out infinite}
@keyframes cv-breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.045)}}
@keyframes cv-pulse{0%,100%{opacity:.35}50%{opacity:1}}
@media(prefers-reduced-motion:reduce){
  #cover{transition:none}
  #cover .emblem img,#cover .hint::before{animation:none}
}

.register{display:grid;grid-template-columns:minmax(0,1fr) 404px;gap:var(--s-5);align-items:start}
@media(max-width:1180px){.register{grid-template-columns:1fr}}

/* the scan bar: the single most-used control in the building */
.scanbar{position:relative;display:flex;align-items:center;gap:var(--s-3);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:var(--s-2) var(--s-3) var(--s-2) var(--s-5);box-shadow:var(--shadow);
  margin-bottom:var(--s-4);transition:border-color var(--base) var(--ease),
  box-shadow var(--base) var(--ease)}
.scanbar:focus-within{border-color:var(--gold-dk);box-shadow:var(--shadow),0 0 0 4px rgba(184,168,136,.2)}
.scanbar svg{width:22px;height:22px;flex:0 0 auto;stroke:var(--gold-dk);fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
.scan{flex:1;min-width:0;border:0;background:transparent;padding:14px 0;
  font-family:var(--font-display);font-size:var(--t-xl);font-weight:500;letter-spacing:.01em}
.scan:hover,.scan:focus{border:0;box-shadow:none;outline:none}
.scanbar .hint{flex:0 0 auto;display:flex;align-items:center;gap:6px;color:var(--ink-4);
  font-size:var(--t-xs)}
@media(max-width:640px){.scanbar .hint{display:none}}

/* cart lines. Deliberately not a table: each line carries a photograph, two
   or three status pills and a quantity stepper, which a table row makes
   cramped and a phone makes unreadable. */
.cartlist{display:flex;flex-direction:column}
.cartrow{display:grid;grid-template-columns:56px minmax(160px,1fr) auto auto auto;
  gap:var(--s-3);align-items:center;padding:var(--s-3) 0;
  border-bottom:1px solid var(--border-2);animation:linein .22s var(--ease)}
.cartrow:last-child{border-bottom:0}
@keyframes linein{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.cartrow{animation:none}}
.cartrow .thumb{width:56px;height:56px}
.cartrow .nm{font-weight:600;font-size:var(--t-md);line-height:1.3}
.cartrow .sku{font-family:var(--font-mono);font-size:var(--t-xs);color:var(--ink-4);
  letter-spacing:.02em;margin-top:2px}
.cartrow .tags{display:flex;gap:5px;flex-wrap:wrap;margin-top:5px}
.cartrow .price{text-align:right;font-variant-numeric:tabular-nums;min-width:96px}
.cartrow .price b{font-size:var(--t-md);font-weight:600;display:block}
.cartrow .price s{color:var(--ink-4);font-size:var(--t-xs)}
.cartrow .ln{text-align:right;font-family:var(--font-display);font-weight:600;
  font-size:var(--t-md);font-variant-numeric:tabular-nums;min-width:88px}
@media(max-width:760px){
  .cartrow{grid-template-columns:48px minmax(0,1fr) auto;grid-template-areas:
    "th nm pr" "th tg tg" "th qt ln"}
  .cartrow .thumb{grid-area:th;width:48px;height:48px}
  .cartrow .body{grid-area:nm}
  .cartrow .price{grid-area:pr}
  .cartrow .stepper{grid-area:qt;justify-self:start}
  .cartrow .ln{grid-area:ln}
}

/* quantity stepper — two big targets and a number, rather than a spinner
   nobody can hit with a finger */
.stepper{display:inline-flex;align-items:center;border:1px solid var(--border);
  border-radius:var(--r-xs);background:#fff;overflow:hidden}
.stepper button{width:34px;height:36px;border:0;background:transparent;color:var(--ink-3);
  font-size:var(--t-lg);line-height:1;padding:0}
.stepper button:hover{background:var(--surface-2);color:var(--ink)}
.stepper input{width:44px;height:36px;border:0;border-left:1px solid var(--border-2);
  border-right:1px solid var(--border-2);border-radius:0;text-align:center;padding:0;
  font-variant-numeric:tabular-nums;font-weight:600;
  -moz-appearance:textfield}
.stepper input::-webkit-outer-spin-button,.stepper input::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0}
.stepper input:focus{box-shadow:none;border-color:var(--border-2)}

/* checkout column */
.checkout{position:sticky;top:calc(var(--topbar-h) + var(--s-5))}
.checkout .lbl{font-family:var(--font-display);font-size:var(--t-xs);font-weight:600;
  color:var(--ink-3);letter-spacing:.05em;text-transform:uppercase;margin-bottom:6px;display:block}
.checkout .money-in{position:relative}
.checkout .money-in::before{content:"$";position:absolute;left:12px;top:50%;
  transform:translateY(-50%);color:var(--ink-4);font-size:var(--t-base)}
.checkout .money-in input{width:100%;padding-left:26px;text-align:right;
  font-variant-numeric:tabular-nums}
.checkout .pair{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-3);margin-bottom:var(--s-3)}

/* tender presets — the notes a customer actually hands over */
.tender{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-top:6px}
.tender button{padding:9px 4px;border:1px solid var(--border);background:#fff;
  border-radius:var(--r-xs);font-family:var(--font-display);font-weight:600;
  font-size:var(--t-sm);color:var(--ink-2);font-variant-numeric:tabular-nums}
.tender button:hover{border-color:var(--gold);background:var(--surface-2)}

.totals{margin-top:var(--s-4);border-top:1px solid var(--border);padding-top:var(--s-3)}
.totals div{display:flex;justify-content:space-between;padding:4px 0;font-size:var(--t-base);
  color:var(--ink-3);font-variant-numeric:tabular-nums}
.totals .grand{font-family:var(--font-display);font-size:var(--t-2xl);font-weight:700;
  padding-top:10px;margin-top:6px;border-top:1px solid var(--border);color:var(--ink);
  letter-spacing:-.015em}
.totals .grand span:first-child{font-size:var(--t-md);align-self:center;color:var(--ink-3);
  font-weight:600}

/* the customer attached to this sale */
.custchip{display:flex;align-items:center;gap:9px;padding:9px 11px;border:1px dashed var(--border-strong);
  border-radius:var(--radius-sm);background:var(--surface-2);width:100%;margin-bottom:var(--s-3);
  font-size:var(--t-sm);color:var(--ink-3);text-align:left}
.custchip:hover{border-color:var(--gold);color:var(--ink)}
.custchip.on{border-style:solid;border-color:var(--gold);background:#fff;color:var(--ink)}
.custchip b{font-weight:600}

/* terminal handoff */
.termbox{margin-top:var(--s-4);padding:var(--s-4);border:1px solid var(--border);
  border-radius:var(--radius-sm);background:var(--surface-2)}
.termbox .hd{display:flex;align-items:center;gap:var(--s-3)}
.termbox .what{font-weight:600;font-family:var(--font-display)}

/* ============================= 8. inventory ============================= */

/* filter bar */
.filters{display:flex;gap:var(--s-2);flex-wrap:wrap;align-items:center;margin-bottom:var(--s-4)}
.filters .grow{flex:1;min-width:220px}
.filters select{min-width:150px}

/* the ageing markdown cell: today's price, what it was, and how far along
   the schedule the piece is */
.aged{display:inline-flex;flex-direction:column;align-items:flex-end;gap:2px}
.aged s{color:var(--ink-4);font-size:var(--t-xs)}
.aged b{font-weight:600}

/* ============================ 9. dashboards ============================
   Stat tiles. The number is the loudest thing in the tile; the label above
   it is quiet, and the comparison below it is quieter still. */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--s-4);
  margin-bottom:var(--s-5)}
.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:var(--s-4) var(--s-5);box-shadow:var(--shadow-sm)}
.stat .k{font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-4)}
.stat .v{font-family:var(--font-display);font-size:var(--t-2xl);font-weight:700;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;margin-top:4px;line-height:1.1}
.stat .m{font-size:var(--t-sm);color:var(--ink-3);margin-top:3px}
.stat.gold .v{color:var(--gold-dk)}

/* ============================ 10. consignors ============================ */

.stsum{display:flex;gap:var(--s-3);margin-bottom:var(--s-4);flex-wrap:wrap}
.stsum > div{flex:1;min-width:130px;background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--radius-sm);padding:11px 13px}
.stsum span{display:block;font-size:var(--t-xs);color:var(--ink-3);font-weight:600;
  letter-spacing:.03em;text-transform:uppercase}
.stsum b{font-size:var(--t-xl);font-family:var(--font-display);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.stsum .owed b{color:var(--gold-dk)}
.stlist{max-height:230px;overflow:auto;border:1px solid var(--border);
  border-radius:var(--radius-sm)}
.stlist table{margin:0}
.stlist th{position:sticky;top:0;background:var(--surface);z-index:1}
.voided{opacity:.55;text-decoration:line-through}

/* ============================= 11. appraisal =============================
   Priced-by-machine numbers are visually separated from the fields the shop
   typed itself: a clerk glancing at the form must never be unsure which of
   the two they are looking at. */

.ai{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface-2);
  padding:var(--s-4);margin-top:4px}
.ai h4{margin:0 0 var(--s-2);font-size:var(--t-sm);font-family:var(--font-display);
  letter-spacing:.02em;display:flex;align-items:center;gap:var(--s-2)}
.ai .price{display:flex;align-items:baseline;gap:var(--s-3);flex-wrap:wrap;margin-bottom:var(--s-2)}
.ai .price b{font-size:var(--t-2xl);font-family:var(--font-display);letter-spacing:-.02em}
.ai .range{display:flex;gap:var(--s-4);flex-wrap:wrap;font-size:var(--t-sm);color:var(--ink-3);
  padding-bottom:9px;border-bottom:1px solid var(--border);margin-bottom:9px}
.ai .range b{color:var(--ink);font-variant-numeric:tabular-nums}
.ai .comp{display:flex;gap:var(--s-3);justify-content:space-between;align-items:baseline;
  padding:6px 0;border-bottom:1px dotted var(--border);font-size:var(--t-sm)}
.ai .comp:last-of-type{border-bottom:0}
.ai .comp .what{min-width:0;flex:1}
.ai .comp .what a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--gold)}
.ai .comp .what a:hover{color:var(--gold-dk)}
.ai .comp .when{color:var(--ink-3);font-size:var(--t-xs)}
.ai .comp .amt{font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
.ai .note{font-size:var(--t-sm);color:var(--ink-3);margin-top:var(--s-2)}
.ai .srcs{font-size:var(--t-xs);color:var(--ink-3);margin-top:var(--s-2);
  display:flex;gap:5px;flex-wrap:wrap}
.ai .srcs a{color:var(--ink-3)}
.ai .warnline{font-size:var(--t-xs);color:var(--warn);margin-top:9px}
.aiwait{display:flex;gap:var(--s-4);align-items:center;padding:6px 0 var(--s-4)}
.aiwait .what{font-weight:600;font-family:var(--font-display)}

.shots{display:flex;gap:var(--s-2);flex-wrap:wrap}
.shot{position:relative;width:88px}
.shot img{width:88px;height:88px;object-fit:cover;border-radius:9px;
  border:1px solid var(--border);display:block;background:var(--surface-2)}
.shot .kind{font-size:var(--t-2xs);color:var(--ink-3);text-align:center;margin-top:3px;
  text-transform:uppercase;letter-spacing:.04em}
.shot .rm{position:absolute;top:-6px;right:-6px;width:22px;height:22px;border-radius:50%;
  border:1px solid var(--border);background:#fff;color:var(--ink-3);font-size:var(--t-sm);
  line-height:1;padding:0;box-shadow:var(--shadow-sm)}
.shot .rm:hover{color:var(--bad);border-color:var(--bad)}

/* hallmarks and maker's marks, read off the piece */
.marks{display:grid;gap:6px}
.mark{border-left:2px solid var(--gold);padding:1px 0 1px 9px;font-size:var(--t-sm)}
.mark .rd{font-weight:600}
.mark .mn{color:var(--ink-3)}
.mark .kd{font-size:var(--t-2xs);color:var(--ink-4);text-transform:uppercase;letter-spacing:.05em}

/* ============================= 12. overlays ============================= */

dialog{border:0;border-radius:var(--radius);padding:0;box-shadow:0 20px 60px rgba(0,0,0,.3);
  max-width:560px;width:calc(100% - 32px);max-height:calc(100dvh - 28px);overflow:auto;
  background:var(--surface)}
dialog::backdrop{background:rgba(21,29,40,.55);backdrop-filter:blur(2px)}
dialog .dlg{padding:var(--s-5)}
dialog h3{margin:0 0 var(--s-4);font-size:var(--t-lg)}
dialog h4{margin:var(--s-4) 0 7px;font-size:var(--t-sm);font-family:var(--font-display);
  letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3)}
/* A tall appraisal must not push the Save button off a phone screen. */
.dlgactions{position:sticky;bottom:calc(var(--s-5) * -1);justify-content:flex-end;
  margin:var(--s-4) calc(var(--s-5) * -1) calc(var(--s-5) * -1);
  padding:var(--s-4) var(--s-5);background:var(--surface);
  border-top:1px solid var(--border-2)}

.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:22px;z-index:60;
  background:var(--ink);color:#fff;padding:12px 20px;border-radius:var(--radius-sm);
  font-size:var(--t-base);box-shadow:var(--shadow-lg);max-width:90vw;
  animation:toastin .24s var(--ease)}
@keyframes toastin{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}
.toast.bad{background:var(--bad)} .toast.ok{background:var(--ok)}
@media(max-width:760px){.toast{bottom:86px}}

/* ============================ 13. diagnostics ============================ */

.check{display:flex;gap:var(--s-3);align-items:flex-start;padding:12px 2px;
  border-bottom:1px solid var(--border)}
.check:last-child{border-bottom:0}
.check .dot{margin-top:5px}
.check .body{flex:1;min-width:0}
.check .name{font-weight:600;font-size:var(--t-base)}
.check .detail{color:var(--ink-3);font-size:var(--t-sm);word-break:break-word}
.check .hint{color:var(--warn);font-size:var(--t-sm);margin-top:3px}
.check .ms{color:var(--ink-3);font-size:var(--t-xs);font-variant-numeric:tabular-nums}
.statusline{display:flex;align-items:center;gap:var(--s-3);margin-bottom:6px}
.statusline .label{font-weight:600}

/* api keys */
.key{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--s-4);
  margin-bottom:var(--s-3);background:var(--surface)}
.key .hd{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3)}
.key .nm{font-weight:600;font-size:var(--t-base)}
.key .help{font-size:var(--t-sm);color:var(--ink-3);margin:5px 0 9px;line-height:1.5}
.key .state{font-size:var(--t-sm);color:var(--ink-3);font-variant-numeric:tabular-nums}
.key .row{margin-top:var(--s-2)}
.key input{flex:1;min-width:140px;font-family:var(--font-mono);font-size:var(--t-sm)}

/* live debug overlay — dark and monospaced on purpose: it must never be
   mistaken for part of the till at a glance, and it is read by someone
   debugging, not selling. */
.dbg{position:fixed;right:14px;bottom:14px;z-index:80;width:min(460px,calc(100vw - 28px));
  max-height:min(70vh,620px);display:flex;flex-direction:column;
  background:#141b25;color:#d7e0ea;border:1px solid #2a3644;border-radius:12px;
  box-shadow:0 24px 64px -18px rgba(0,0,0,.6);
  font:12px/1.5 var(--font-mono)}
.dbg header{display:flex;align-items:center;gap:var(--s-2);padding:9px 11px;
  border-bottom:1px solid #2a3644;flex:0 0 auto}
.dbg header b{font-family:var(--font-display);font-size:12px;letter-spacing:.06em;
  text-transform:uppercase;color:#9fb3c8}
.dbg header .sp{flex:1}
.dbg button{background:#1e2836;color:#c3d0de;border:1px solid #34435a;border-radius:7px;
  padding:3px 9px;font:inherit;font-size:11px}
.dbg button:hover{background:#263345;color:#fff}
.dbg button[aria-pressed="true"]{background:var(--gold-dk);border-color:var(--gold-dk);color:#fff}
.dbg .body{overflow:auto;padding:10px 11px;flex:1}
.dbg .kv{display:grid;grid-template-columns:auto 1fr;gap:2px 12px}
.dbg .kv dt{color:#7f93a8}
.dbg .kv dd{margin:0;word-break:break-word}
.dbg h5{margin:12px 0 5px;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:#7f93a8;font-weight:700}
.dbg h5:first-child{margin-top:0}
.dbg .ln{display:flex;gap:var(--s-2);padding:2px 0;border-bottom:1px solid #1e2836}
.dbg .ln:last-child{border-bottom:0}
.dbg .ln .m{color:#7f93a8;flex:0 0 42px}
.dbg .ln .p{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dbg .ln .t{color:#7f93a8;flex:0 0 auto;font-variant-numeric:tabular-nums}
.dbg .ok{color:#7ddba0} .dbg .warn{color:#f0c26a} .dbg .bad{color:#f28b82}
.dbg .empty2{color:#7f93a8;padding:6px 0}
@media(max-width:520px){.dbg{left:14px;right:14px;width:auto;max-height:64vh}}

/* ============================= 14. toolbars =============================
   Each screen's controls, relocated into the page bar by showTab(). They sit
   on one row with the title; on a narrow screen the bar is allowed to grow
   a second row rather than squeezing the controls. */
.tools{display:flex;gap:var(--s-2);align-items:center;flex-wrap:wrap;justify-content:flex-end}
.tools input,.tools select{height:38px}
.tools #invSearch,.tools #custSearch{min-width:min(300px,42vw)}
@media(max-width:900px){
  .topbar{height:auto;min-height:var(--topbar-h);flex-wrap:wrap;
    padding-top:var(--s-2);padding-bottom:var(--s-2)}
  .topbar .acts{margin-left:0;width:100%;justify-content:flex-start}
  .tools{width:100%}
  .tools #invSearch,.tools #custSearch{min-width:0;flex:1}
  .checkout{position:static}
}

/* ============================ 15. inventory ============================ */

/* Bulk action bar — appears only when something is ticked. */
.bulkbar{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3);
  padding:10px var(--s-4);border:1px solid var(--gold);border-radius:var(--radius-sm);
  background:var(--warn-bg);font-size:var(--t-sm);
  animation:linein .18s var(--ease)}
.bulkbar b{font-family:var(--font-display)}

/* the piece's line in the list */
.itemcell{display:flex;flex-direction:column;gap:2px;min-width:0}
.itemcell .nm{font-weight:600}
.itemcell .meta{font-size:var(--t-xs);color:var(--ink-3);display:flex;gap:6px;flex-wrap:wrap}
.itemcell .meta .sku{font-family:var(--font-mono);color:var(--ink-4)}
.itemcell .meta i{font-style:normal;color:var(--border-strong)}

/* a consignor always carries the same colour, so a shelf audit can be done
   by eye before anybody reads a name */
.conchip{display:inline-flex;align-items:center;gap:7px;font-size:var(--t-sm);min-width:0}
.conchip .swatch{width:9px;height:9px;border-radius:50%;flex:0 0 auto;
  background:var(--ink-4);box-shadow:0 0 0 2px rgba(0,0,0,.04)}

/* how long a piece has been on the floor, and how close it is to its next
   markdown — the number a shop actually manages stock by */
.age{display:inline-flex;flex-direction:column;align-items:flex-end;gap:3px;
  font-variant-numeric:tabular-nums}
.age b{font-weight:600;font-size:var(--t-base)}
.age .bar{width:64px;height:4px;border-radius:2px;background:var(--border-2);overflow:hidden}
.age .bar i{display:block;height:100%;border-radius:2px;
  background:linear-gradient(90deg,var(--gold),var(--gold-dk))}
.age.hot .bar i{background:linear-gradient(90deg,#e0a860,var(--warn))}

/* gallery */
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(196px,1fr));gap:var(--s-4)}
.gcard{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;
  transition:box-shadow var(--base) var(--ease),transform var(--base) var(--ease)}
.gcard:hover{box-shadow:var(--shadow-md);transform:translateY(-2px)}
@media(prefers-reduced-motion:reduce){.gcard:hover{transform:none}}
.gcard .ph{aspect-ratio:1;background:var(--surface-2);display:grid;place-items:center;
  color:var(--gold-dk);font-size:32px;position:relative;overflow:hidden}
.gcard .ph img{width:100%;height:100%;object-fit:cover}
.gcard .ph .flag{position:absolute;top:8px;left:8px}
.gcard .bd{padding:11px 13px 13px;display:flex;flex-direction:column;gap:3px;flex:1}
.gcard .nm{font-weight:600;font-size:var(--t-base);line-height:1.3}
.gcard .meta{font-size:var(--t-xs);color:var(--ink-3)}
.gcard .pr{margin-top:auto;padding-top:8px;display:flex;align-items:baseline;gap:7px;
  font-variant-numeric:tabular-nums}
.gcard .pr b{font-family:var(--font-display);font-size:var(--t-md);font-weight:600}
.gcard .pr s{color:var(--ink-4);font-size:var(--t-xs)}
.gcard .acts{display:flex;gap:6px;padding:0 13px 13px}
.gcard .acts .btn{flex:1}

/* ============================ 16. clienteling ============================
   A card per call worth making. The piece is shown, because the first thing
   the person on the phone will be asked is "what is it like". */

.matchlist{display:grid;gap:var(--s-3)}
.matchcard{display:grid;grid-template-columns:96px minmax(0,1fr);gap:var(--s-4);
  border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);
  overflow:hidden}
.matchcard .pic{background:var(--surface-2);display:grid;place-items:center;
  color:var(--gold-dk);font-size:26px;min-height:96px}
.matchcard .pic img{width:100%;height:100%;object-fit:cover}
.matchcard .bd{padding:var(--s-4) var(--s-4) var(--s-4) 0;display:flex;
  flex-direction:column;gap:7px;min-width:0}
.matchcard .hd{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}
.matchcard .hd b{font-family:var(--font-display);font-size:var(--t-md)}
.matchcard .why{margin:0;font-size:var(--t-sm);color:var(--ink-3);line-height:1.5}
.matchcard .why b{color:var(--ink);font-weight:600}
.matchcard .reach{display:flex;gap:var(--s-3);flex-wrap:wrap;align-items:center;
  font-size:var(--t-sm);color:var(--ink-2)}
.matchcard .reach .tick{margin-left:auto;color:var(--ink-3);font-variant-numeric:tabular-nums}
.matchcard .reach .warnline{color:var(--warn);font-weight:500}
@media(max-width:640px){
  .matchcard{grid-template-columns:1fr}
  .matchcard .pic{aspect-ratio:16/9}
  .matchcard .bd{padding:var(--s-4)}
}

/* small round initials, used wherever a person is named in a list */
.face{width:28px;height:28px;border-radius:50%;flex:0 0 auto;display:inline-grid;
  place-items:center;font-family:var(--font-display);font-weight:600;font-size:var(--t-xs);
  color:var(--ink-2);background:var(--surface-2);border:1px solid var(--border)}

/* ============================== 17. reports ==============================
   One series of about ninety numbers, drawn as inline SVG. A register should
   not fetch a charting library over a shop's wifi to draw rectangles. */

.chart svg{width:100%;height:150px;display:block}
.chart rect.on{fill:var(--gold-dk)}
.chart rect.on:hover{fill:var(--ink-2)}
.chart rect.off{fill:var(--border)}
.chart .axis{display:flex;justify-content:space-between;margin-top:7px;
  font-size:var(--t-xs);color:var(--ink-4)}

/* a ranked share of a total: label, amount, and the bar underneath */
.ranks{display:grid;gap:var(--s-3)}
.rank .lb{display:flex;justify-content:space-between;gap:var(--s-3);align-items:baseline;
  font-size:var(--t-sm);margin-bottom:4px}
.rank .lb b{font-variant-numeric:tabular-nums;font-family:var(--font-display)}
.rank .bar{height:7px;border-radius:4px;background:var(--border-2);overflow:hidden}
.rank .bar i{display:block;height:100%;border-radius:4px;
  background:linear-gradient(90deg,var(--gold),var(--gold-dk))}

/* ============================== 18. intake ==============================
   Four labelled slots rather than a pile of files: the label is what the
   appraisal reads, so it is part of the input, not decoration. */

.slots{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:var(--s-2)}
.slot{display:flex;flex-direction:column;align-items:center;gap:4px;padding:var(--s-4) var(--s-2);
  border:1.5px dashed var(--border-strong);border-radius:var(--radius-sm);background:var(--surface);
  color:var(--ink-3);text-align:center}
.slot svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.5;
  stroke-linecap:round;stroke-linejoin:round;opacity:.75}
.slot span{font-family:var(--font-display);font-size:var(--t-sm);font-weight:600;color:var(--ink-2)}
.slot small{font-size:var(--t-2xs);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-4)}
.slot:hover{border-color:var(--gold);background:var(--surface-2);color:var(--ink-2)}
.slot.on{border-style:solid;border-color:var(--ok-line);background:var(--ok-bg);color:var(--ok)}
.slot.on span{color:var(--ok)}
.slot.on svg{opacity:1}

/* what the appraisal is doing, in the order it does it */
.steps{list-style:none;margin:var(--s-3) 0 0;padding:0;display:grid;gap:9px}
.steps li{display:flex;align-items:center;gap:10px;font-size:var(--t-sm);color:var(--ink-4)}
.steps li::before{content:"";width:8px;height:8px;border-radius:50%;flex:0 0 auto;
  background:var(--border-strong)}
.steps li.on{color:var(--ink)}
.steps li.on::before{background:var(--gold-dk);box-shadow:0 0 0 4px rgba(184,168,136,.22);
  animation:pulse 1.6s ease-in-out infinite}
.steps li.done{color:var(--ink-3)}
.steps li.done::before{background:var(--ok)}
@media(prefers-reduced-motion:reduce){.steps li.on::before{animation:none}}

/* ============================== 19. settings ==============================
   A list of subjects on the left, one subject at a time on the right. */

.settings{display:grid;grid-template-columns:236px minmax(0,1fr);gap:var(--s-5);
  align-items:start}
.setnav{display:flex;flex-direction:column;gap:2px;position:sticky;
  top:calc(var(--topbar-h) + var(--s-5))}
.setnav button{display:block;text-align:left;width:100%;background:transparent;border:0;
  border-radius:var(--radius-sm);padding:10px 13px;color:var(--ink-3)}
.setnav button b{display:block;font-family:var(--font-display);font-size:var(--t-base);
  font-weight:600;color:var(--ink-2)}
.setnav button small{display:block;font-size:var(--t-xs);color:var(--ink-4);margin-top:1px}
.setnav button:hover{background:var(--surface-2)}
.setnav button[aria-current="true"]{background:var(--surface);border:1px solid var(--border);
  box-shadow:var(--shadow-sm);padding:9px 12px}
.setnav button[aria-current="true"] b{color:var(--ink)}
.setbody{display:grid;gap:var(--s-5);min-width:0}
.setbody > .panel{max-width:820px}
@media(max-width:900px){
  .settings{grid-template-columns:1fr}
  .setnav{position:static;flex-direction:row;overflow-x:auto;gap:6px;padding-bottom:4px}
  .setnav button{width:auto;white-space:nowrap;border:1px solid var(--border);
    background:var(--surface)}
  .setnav button small{display:none}
}

/* ============================== 20. fieldsets ==============================
   A long form asked as several short questions. */

.fset{border:0;border-top:1px solid var(--border-2);margin:0 0 var(--s-4);
  padding:var(--s-4) 0 0}
.fset:first-of-type{border-top:0;padding-top:0}
.fset legend{font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-4);padding:0 0 var(--s-2)}
dialog{max-width:620px}

/* ============================ 21. pick a person ============================ */

.picklist{max-height:46vh;overflow:auto;margin-top:var(--s-3);display:grid;gap:2px}
.pickrow{display:flex;align-items:center;gap:var(--s-3);width:100%;text-align:left;
  background:transparent;border:0;border-radius:var(--radius-sm);padding:9px 10px}
.pickrow:hover{background:var(--surface-2)}
.pickrow .itemcell{flex:1;min-width:0}

/* ========================= 22. accessibility fixes =========================
   Measured against WCAG 2.2 AA rather than eyeballed. Every value below was
   changed because a ratio came back short, not because it looked wrong. */

/* A focus ring in gold sits at about 3.9:1 on the rail's navy — enough to see,
   but the pale gold is unmistakable, and the rail is the one dark surface in
   the app. */
.side :focus-visible{outline-color:var(--gold-lt)}

/* The remove button on a staged photograph was 22px square: under the 24 CSS
   px WCAG 2.2 target minimum, and it sits at the corner of a thumbnail where
   a thumb is already imprecise. */
.shot .rm{width:26px;height:26px}

/* Condition chips are tapped one after another during intake, so they need
   both the height and the gap. */
.chips label{min-height:28px}
.chips{gap:8px}

/* The consignor's outstanding figure is small text carrying money. */
.owed-figure{color:var(--gold-ink);font-weight:600}

/* Toasts announce themselves; sliding is decoration. */
@media(prefers-reduced-motion:reduce){
  .toast{animation:none}
  .bulkbar{animation:none}
}

/* Selection boxes were the browser default 13px — half the WCAG 2.2 minimum,
   and this is a till that gets poked with a finger. The row's own padding
   supplies the spacing between them. */
input[type=checkbox]{width:22px;height:22px;margin:0}
.stlist input[type=checkbox]{width:18px;height:18px}

/* Bottom bar on a phone: six labels across 375px. Each cell takes an equal
   share and its label is allowed to shrink rather than run over its
   neighbour — a nav item that overlaps the one beside it is a mis-tap. */
@media(max-width:760px){
  .side nav button{flex:1 1 0;min-width:0}
  .side nav button span.lbl{max-width:100%;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;letter-spacing:.02em}
}
@media(max-width:400px){
  .side nav button span.lbl{font-size:9.5px;letter-spacing:0}
}

/* On a phone, four full-height stat tiles put 650px of summary between the
   toolbar and the first piece of stock. Two-up and compact keeps the numbers
   without making the list something you have to scroll to find. */
@media(max-width:640px){
  input[type=checkbox]{width:24px;height:24px}
  .stats{grid-template-columns:1fr 1fr;gap:var(--s-2);margin-bottom:var(--s-4)}
  .stat{padding:var(--s-3)}
  .stat .v{font-size:var(--t-lg)}
  .stat .m{display:none}
}

/* ---- wide tables on a narrow screen ----
   The panel clips its corners, which was also clipping the last columns off
   the right-hand edge with no way to reach them. Two changes: the secondary
   columns are dropped on a phone, and whatever is left is allowed to scroll
   inside its own box rather than being cut off. Nothing is ever unreachable —
   the dropped columns are all visible in the row's own Edit form. */
@media(max-width:640px){
  .panel.flush > table,
  .panel > table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}

  /* inventory: consignor and days-on-floor */
  #invListWrap th:nth-child(4),#invListWrap td:nth-child(4),
  #invListWrap th:nth-child(5),#invListWrap td:nth-child(5){display:none}

  /* consignors: pieces and stock value — the money columns stay */
  #tab-consignors th:nth-child(3),#tab-consignors td:nth-child(3),
  #tab-consignors th:nth-child(4),#tab-consignors td:nth-child(4){display:none}

  /* customers: orders, spend and last seen */
  #tab-customers th:nth-child(3),#tab-customers td:nth-child(3),
  #tab-customers th:nth-child(4),#tab-customers td:nth-child(4),
  #tab-customers th:nth-child(5),#tab-customers td:nth-child(5){display:none}

  th,td{padding:10px 7px}
}

/* ============================== 23. paywall ==============================
   The screen a shop sees when it is not entitled. It borrows the login
   card so the moment reads as "sign in again", not "something broke" —
   nothing has broken, and nothing has been deleted. */

#paywall{position:relative;min-height:100dvh;display:grid;place-items:center;padding:var(--s-6);
  overflow:hidden;isolation:isolate;
  background:radial-gradient(120% 90% at 50% -10%,#22303f 0%,#1a2431 55%,#0f151e 100%)}
#paywall::after{content:"";position:absolute;z-index:-1;right:-18%;bottom:-22%;
  width:min(70vw,700px);aspect-ratio:1;background:url(/mark.png) center/contain no-repeat;
  opacity:.045;pointer-events:none}
.card.wide{max-width:520px}
.card .lede{font-size:var(--t-base);color:var(--ink-3);line-height:1.6;margin:0 0 var(--s-5)}
.card .linkish{background:none;border:0;color:var(--ink-3);font-size:var(--t-sm);
  text-decoration:underline;margin-top:var(--s-4);width:auto;padding:6px 10px}
.card .linkish:hover{color:var(--ink)}
#paywall .btn{text-decoration:none}

/* the published plans, priced by the App Center rather than by us */
.plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--s-3);
  margin:0 0 var(--s-5)}
.plans:empty{display:none}
.plan{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--s-3);
  background:var(--surface-2);text-align:left}
.plan .nm{font-family:var(--font-display);font-weight:600;font-size:var(--t-sm)}
.plan .amt{font-family:var(--font-display);font-weight:700;font-size:var(--t-xl);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;margin-top:2px}
.plan .amt small{font-size:var(--t-xs);font-weight:500;color:var(--ink-3);letter-spacing:0}

/* Plans as choices rather than a price list: on the paywall each one is the
   button that buys it. */
.plan{position:relative;display:block;width:100%;text-align:left;cursor:pointer;
  transition:border-color var(--fast) var(--ease),box-shadow var(--fast) var(--ease)}
.plan:hover:not(:disabled){border-color:var(--gold);box-shadow:var(--shadow-sm)}
.plan:disabled{cursor:default;opacity:.6}
.plan .pick{display:block;margin-top:9px;font-family:var(--font-display);font-size:var(--t-xs);
  font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--gold-ink)}
.plan.busy .pick::after{content:" …"}

/* ---- catalogue match report ----
   Shown after a dry run, before anything is written. The mismatch lines are
   the point: a piece that exists on only one side is the one that sells
   twice. */
#linkReport{margin-top:var(--s-4);border-top:1px solid var(--border-2);padding-top:var(--s-3);
  display:grid;gap:6px}
.linkline{font-size:var(--t-sm);line-height:1.5}
.linkline b{font-family:var(--font-display);font-variant-numeric:tabular-nums}
.linkline.warn{color:var(--warn)}
.linkline.ok{color:var(--ok)}

/* ============================ 24. indicators ============================
   A status light, built the way one is built: a recessed bezel, a lit core,
   and a bloom that spills onto the surface around it. The colour is never the
   only signal — every light in this app sits beside its own written status —
   but a board of these reads at a glance from across a counter, which a row
   of flat circles does not.

   Three layers, no images:
     .led        the bezel — a dark well the light sits in
     ::before    the core  — the emitter itself, with an inner highlight
     ::after     the bloom — soft colour thrown onto the surrounding surface
*/

.led{
  --lit:#8797a9;                       /* overridden per state below */
  position:relative;width:13px;height:13px;border-radius:50%;flex:0 0 auto;
  display:inline-block;
  background:radial-gradient(circle at 50% 55%, #0d141d 0%, #16202c 60%, #0a0f16 100%);
  box-shadow:inset 0 1px 1.5px rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.55);
}
.led::before{
  content:"";position:absolute;inset:2px;border-radius:50%;
  background:
    radial-gradient(circle at 38% 32%, rgba(255,255,255,.9) 0%, rgba(255,255,255,.25) 28%, transparent 55%),
    radial-gradient(circle at 50% 55%, var(--lit) 0%, color-mix(in srgb, var(--lit) 70%, #000) 100%);
  box-shadow:0 0 3px color-mix(in srgb, var(--lit) 85%, transparent);
}
.led::after{
  content:"";position:absolute;inset:-5px;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle, color-mix(in srgb, var(--lit) 45%, transparent) 0%, transparent 68%);
  opacity:.85;
}

.led.ok{--lit:#25d07a}
.led.warn{--lit:#f0a83a}
.led.fail{--lit:#ff5648}
.led.unknown{--lit:#7e8b9c}
.led.off{--lit:#3b4655}
.led.off::after{opacity:0}

/* A light that is doing something breathes rather than blinks: a blink says
   "fault" on every piece of equipment ever made, and most of these are fine. */
.led.pulse::after{animation:led-breathe 2.4s ease-in-out infinite}
@keyframes led-breathe{0%,100%{opacity:.85;transform:scale(1)}50%{opacity:.35;transform:scale(.9)}}

/* One event just arrived on this light. Fires once, then gets out of the way. */
.led.hit::after{animation:led-hit .7s var(--ease) 1}
@keyframes led-hit{0%{opacity:1;transform:scale(1.5)}100%{opacity:.85;transform:scale(1)}}

@media(prefers-reduced-motion:reduce){
  .led.pulse::after,.led.hit::after{animation:none}
}

/* larger, for a board where the light is the subject rather than a bullet */
.led.big{width:17px;height:17px}
.led.big::before{inset:2.5px}

/* ============================= 25. live board =============================
   Instrument panel, not dashboard cards. The structure is hairlines and
   alignment rather than boxes inside boxes: every light sits on the same
   baseline grid, every figure is tabular, and nothing is rounded that does
   not need to be. */

.streamstate{display:inline-flex;align-items:center;gap:7px;font-size:var(--t-xs);
  font-family:var(--font-display);font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-4)}

.ledboard{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));
  gap:0;margin-bottom:var(--s-5);border-top:1px solid var(--border-2);
  border-left:1px solid var(--border-2)}
.ledcell{background:var(--surface);padding:13px 14px;display:grid;
  border-right:1px solid var(--border-2);border-bottom:1px solid var(--border-2);
  grid-template-columns:auto 1fr;grid-template-areas:"led lb" "led ls";
  gap:1px var(--s-3);align-items:center}
.ledcell .led{grid-area:led;align-self:center}
.ledcell .lb{grid-area:lb;font-family:var(--font-display);font-size:var(--t-sm);
  font-weight:600;line-height:1.2}
.ledcell .ls{grid-area:ls;font-size:var(--t-xs);color:var(--ink-4);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.feedhead{display:flex;justify-content:space-between;align-items:baseline;
  padding-bottom:7px;border-bottom:1px solid var(--border);margin-bottom:2px}

.feed{max-height:340px;overflow-y:auto;display:flex;flex-direction:column}
.feedempty{padding:var(--s-6) 0;text-align:center;color:var(--ink-4);font-size:var(--t-sm)}
.feedrow{display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;
  gap:var(--s-3);align-items:baseline;padding:9px 2px;
  border-bottom:1px solid var(--border-2);font-size:var(--t-sm);
  animation:feedin .32s var(--ease)}
.feedrow:last-child{border-bottom:0}
@keyframes feedin{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.feedrow{animation:none}}

.feedrow .ft{font-family:var(--font-mono);font-size:var(--t-2xs);color:var(--ink-4);
  font-variant-numeric:tabular-nums}
.feedrow .fi{font-size:9px;line-height:1;color:var(--ink-4)}
.feedrow .fx{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.feedrow .fw{color:var(--ink-4)}
.feedrow .fm{color:var(--gold-ink);font-weight:600}
.feedrow .fa{font-family:var(--font-display);font-weight:600;
  font-variant-numeric:tabular-nums;white-space:nowrap}

/* The colour lives on the marker, not the whole row — a feed where every
   line is tinted stops being scannable. */
.feedrow.sale   .fi{color:var(--ok)}
.feedrow.bad    .fi{color:var(--bad)}
.feedrow.hold   .fi{color:var(--gold-dk)}
.feedrow.payout .fi{color:var(--ink-2)}
.feedrow.item   .fi{color:var(--ink-3)}

/* The health list and the live board are the same instrument in two sizes,
   so the check rows carry the same light. */
.check .led{margin-top:5px}
.statusline .led{flex:0 0 auto}


/* ============================ 26. the rail =============================
   Near-black rather than navy. A dark nav against a light working surface
   is a frame around the work; a navy one reads as a second colour competing
   with it. Gold stays the only accent, which is what keeps this from looking
   like every other dashboard. */
.side .brand em{color:var(--gold-lt)}
.side nav button:hover{background:rgba(255,255,255,.05)}
.side nav button[aria-current="true"]{background:rgba(184,168,136,.11)}
.side nav button[aria-current="true"] svg{color:var(--gold-lt)}
.side .userbox{border-top-color:rgba(255,255,255,.07)}
.side::after{background:linear-gradient(180deg,transparent,rgba(184,168,136,.35) 12%,
  rgba(220,210,188,.45) 50%,rgba(184,168,136,.35) 88%,transparent)}

/* ============================ 27. deep dive =============================
   A row opens into what the piece has been doing. Structure borrowed from
   the reference: a titled band per subject, figures large and tabular, the
   label small and quiet above them. */

.btn.slim.dive{padding:8px 10px;min-width:34px}
.dive .chev{display:inline-block;transition:transform var(--fast) var(--ease);
  font-size:var(--t-md);line-height:1}
.dive[aria-expanded="true"] .chev{transform:rotate(90deg)}
@media(prefers-reduced-motion:reduce){.dive .chev{transition:none}}

tr.diverow > td{background:var(--surface-2);padding:0;border-bottom:1px solid var(--border)}
.dive-sec{border-top:1px solid var(--border-2);padding:12px var(--s-5)}
.dive-sec:first-child{border-top:0}
.dive-h{font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-4);margin-bottom:8px}

.dive-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:var(--s-3) var(--s-5)}
.dive-grid > div{display:flex;flex-direction:column;gap:1px}
.dive-grid span{font-size:var(--t-xs);color:var(--ink-3)}
.dive-grid b{font-family:var(--font-display);font-size:var(--t-lg);font-weight:600;
  letter-spacing:-.01em}

.dive-t{width:100%;border-collapse:collapse}
.dive-t td{padding:5px 0;border-bottom:1px dotted var(--border);font-size:var(--t-sm)}
.dive-t tr:last-child td{border-bottom:0}

.dive-line{display:flex;align-items:center;gap:9px;font-size:var(--t-sm);padding:3px 0}
.dive-warn{color:var(--warn)}
.dive-none{font-size:var(--t-sm);color:var(--ink-4);padding:2px 0}

/* ============================== 28. tiles ==============================
   Tap-to-sell, beside the scan bar rather than instead of it. Sized for a
   finger on a counter tablet: the whole tile is the target, the photograph
   does the identifying, and the price is the second thing read. */

.tilebar{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3)}
.tilebar .seg{padding:2px}
.tilebar .seg button{padding:5px 10px;font-size:var(--t-xs)}

.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(124px,1fr));
  gap:var(--s-3);margin-bottom:var(--s-5)}
.tile{display:flex;flex-direction:column;gap:0;padding:0;overflow:hidden;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);text-align:left;
  transition:border-color var(--fast) var(--ease),box-shadow var(--fast) var(--ease),
    transform var(--fast) var(--ease)}
.tile:hover{border-color:var(--gold);box-shadow:var(--shadow)}
.tile:active{transform:translateY(1px)}
@media(prefers-reduced-motion:reduce){.tile:active{transform:none}}

.tile .ph{position:relative;aspect-ratio:1;background:var(--surface-2);
  display:grid;place-items:center;color:var(--gold-dk);font-size:26px;overflow:hidden}
.tile .ph img{width:100%;height:100%;object-fit:cover}
.tile .off{position:absolute;top:6px;left:6px;padding:2px 7px;border-radius:var(--r-full);
  background:var(--warn-bg);border:1px solid var(--warn-line);color:var(--warn);
  font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600}
.tile .nm{padding:8px 10px 0;font-size:var(--t-sm);line-height:1.3;font-weight:500;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tile .pr{padding:3px 10px 10px;font-family:var(--font-display);font-weight:600;
  font-size:var(--t-base);font-variant-numeric:tabular-nums}

.tiles-none{grid-column:1/-1;padding:var(--s-6);text-align:center;
  color:var(--ink-4);font-size:var(--t-sm)}

@media(max-width:640px){
  .tiles{grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:var(--s-2)}
  .tile .nm{font-size:var(--t-xs)}
}

/* On a phone the bar has to hold a label, three sort buttons and a toggle in
   one row: let the label be the thing that gives, never the controls. */
@media(max-width:640px){
  .tilebar{gap:var(--s-2)}
  .tilebar .eyebrow{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .tilebar .seg button{white-space:nowrap;padding:5px 8px}
}

/* ============================ 29. the strip =============================
   The admin screen's instrument row. Cells share hairline dividers instead
   of each floating in its own card: it reads as one instrument the eye
   crosses left to right, which is the whole point of putting the figures in
   a row rather than a grid of tiles. */

.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));
  gap:1px;background:var(--border);border:1px solid var(--border);
  border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-sm);
  margin-bottom:var(--s-5)}
.kpi{background:var(--surface);padding:var(--s-4) var(--s-5) var(--s-3)}
.kpi .k{font-family:var(--font-display);font-size:var(--t-2xs);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-4)}
.kpi .v{font-family:var(--font-display);font-size:var(--t-2xl);font-weight:700;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;line-height:1.1;margin-top:4px}
.kpi .m{font-size:var(--t-xs);color:var(--ink-3);margin-top:4px}

/* Colour is reserved for a figure that is asking for something. Everything
   calm stays ink, so the one that is coloured is the one you look at. */
.kpi.ok   .v{color:var(--ok)}
.kpi.warn .v{color:var(--warn)}
.kpi.bad  .v{color:var(--bad)}
.kpi.gold .v{color:var(--gold-ink)}

@media(max-width:640px){
  .kpis{grid-template-columns:repeat(2,1fr)}
  .kpi{padding:var(--s-3) var(--s-4)}
  .kpi .v{font-size:var(--t-xl)}
}

/* Four to six cells depending on what this user may see, so the row is laid
   out by flow rather than a fixed column count — no empty track can be left
   showing the divider colour. */
@media(min-width:901px){
  .kpis{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}
}
@media(max-width:900px){
  .kpis{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:640px){
  .kpis{grid-template-columns:repeat(2,1fr)}
}

/* =========================== 30. connections ===========================
   A definition list per integration. Two columns of label/value on a wide
   screen, one on a narrow one, and a parameter that is not set says so in
   words rather than showing an empty box the eye slides past. */

.conns{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--s-4)}
.conn{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);
  overflow:hidden}
.conn>header{display:flex;align-items:center;gap:var(--s-2);padding:10px var(--s-4);
  border-bottom:1px solid var(--border-2);background:var(--surface-2)}
.conn>header h3{margin:0;font-size:var(--t-md);font-weight:600}
.conn>header .pill{margin-left:auto;text-transform:capitalize}
.conn dl{margin:0;padding:var(--s-2) var(--s-4) var(--s-3)}
.conn dl>div{display:flex;gap:var(--s-3);align-items:baseline;
  padding:7px 0;border-bottom:1px solid var(--border-2)}
.conn dl>div:last-child{border-bottom:0}
.conn dt{flex:0 0 40%;font-size:var(--t-sm);color:var(--ink-3)}
.conn dt small{display:block;font-size:var(--t-2xs);color:var(--ink-4);line-height:1.35;
  margin-top:1px}
.conn dd{margin:0;flex:1;min-width:0;font-size:var(--t-sm);word-break:break-word}
.conn dd code{font-family:var(--font-mono);font-size:12px;background:var(--surface-2);
  border:1px solid var(--border-2);border-radius:var(--r-xs);padding:1px 6px}
.conn dl>div.unset dd{font-style:italic}

/* ============================ 31. the console ==========================
   A terminal, because that is what it is. Dark on a light page on purpose:
   a log is machine output and reads faster when it does not pretend to be
   part of the document. */

.logbar{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin:var(--s-3) 0}
.logbar select.slim{padding:5px 8px;font-size:var(--t-xs);border-radius:var(--r-xs);
  border:1px solid var(--border);background:var(--surface);color:var(--ink)}
.logbar .tick{font-size:var(--t-xs)}

.console{height:340px;overflow:auto;background:var(--term);border:1px solid var(--term-line);
  border-radius:var(--radius);padding:var(--s-3);font-family:var(--font-mono);
  font-size:12px;line-height:1.65;color:var(--term-ink)}
.console:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.console .ln{display:flex;gap:10px;padding:1px 0;white-space:pre-wrap;word-break:break-word}
.console .ln .t{flex:0 0 auto;color:var(--term-dim)}
.console .ln .s{flex:0 0 84px;color:var(--term-src)}
.console .ln .l{flex:0 0 46px;text-transform:uppercase;font-size:10.5px;letter-spacing:.06em;
  padding-top:1px}
.console .ln .m{flex:1;min-width:0}
.console .ln .m i{color:var(--term-meta);font-style:normal}
.console .ln.info  .l{color:var(--term-info)}
.console .ln.debug .l{color:var(--term-debug)}
.console .ln.warn  .l{color:var(--term-warn)}
.console .ln.warn  .m{color:var(--term-warn-ink)}
.console .ln.error .l{color:var(--term-bad)}
.console .ln.error .m{color:var(--term-bad-ink)}
.console .ln.empty{color:var(--term-dim);justify-content:center;padding:var(--s-6) 0}

@media(max-width:640px){
  .console{height:260px;font-size:11px}
  .console .ln .s{flex:0 0 64px}
  .console .ln .l{display:none}
}

/* Labels that exist for a screen reader and not for the eye. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ============================ 32. the assistant ========================
   Sits under the console it reads. The answer is rendered as plain text in
   a bordered block — deliberately unstyled prose, so nothing about it
   suggests the model's output is part of the application's own voice. */

.assist{margin-top:var(--s-4);padding-top:var(--s-4);border-top:1px solid var(--border-2)}
.assist h3{font-size:var(--t-md);font-weight:600}
.assist textarea{width:100%;padding:10px 12px;border:1px solid var(--border);
  border-radius:var(--radius-sm);background:var(--surface);color:var(--ink);
  font:inherit;font-size:var(--t-sm);resize:vertical;min-height:56px}
.assist textarea:focus-visible{outline:2px solid var(--gold);outline-offset:1px;
  border-color:var(--gold)}
.assist .answer{margin-top:var(--s-3);padding:var(--s-4);white-space:pre-wrap;
  background:var(--surface-2);border:1px solid var(--border);
  border-left:3px solid var(--gold);border-radius:var(--radius-sm);
  font-size:var(--t-sm);line-height:1.6}

/* ============================== 33. the lock ===========================
   Full-bleed, above everything, and the shop's own mark at the top of it —
   this is the screen a customer sees over the counter while the shop is
   away from the till, so it is the one that most needs to look like theirs.

   The keypad is sized for a thumb on a counter tablet: 64px targets, well
   past the 24px minimum, because the person using it is standing up and
   holding something. */

#lock{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:var(--s-5);
  background:radial-gradient(120% 90% at 50% -10%,#22303f 0%,#1a2431 55%,#0e141c 100%);
  overflow:auto}
#lock[hidden]{display:none}

.lockcard{width:min(360px,100%);text-align:center;padding:var(--s-6) var(--s-5) var(--s-5);
  background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--shadow-lg)}
.lockcard .lockmark{display:grid;place-items:center;margin-bottom:var(--s-3)}
.lockcard .lockmark img{max-height:56px;max-width:70%;object-fit:contain}
.lockcard .shop{font-family:var(--font-display);font-size:var(--t-xs);font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink-4)}
.lockcard h1{margin:2px 0 var(--s-4);font-size:var(--t-lg);font-weight:600}

/* One dot per digit: enough feedback to type by, and nothing that would let
   somebody across the counter read the PIN off the screen. */
.pindots{display:flex;justify-content:center;gap:10px;margin-bottom:var(--s-4);min-height:12px}
.pindots i{width:11px;height:11px;border-radius:var(--r-full);
  border:1.5px solid var(--border-strong);background:transparent;
  transition:background var(--fast) var(--ease),border-color var(--fast) var(--ease)}
.pindots i.on{background:var(--gold);border-color:var(--gold)}

/* The real input is present for keyboards, scanners and screen readers; the
   pad writes into it. Off-screen rather than display:none, or it could not
   hold focus. */
/* Present for keyboards, scanners and screen readers; the pad writes into
   it. Clipped rather than display:none, because a hidden input cannot hold
   focus and the till has to accept a typed PIN as well as a tapped one. */
#lockPin{position:absolute;width:1px;height:1px;padding:0;margin:-1px;border:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;opacity:0}

.pinpad{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:var(--s-4)}
.pinpad button{height:64px;font-family:var(--font-display);font-size:var(--t-xl);font-weight:600;
  color:var(--ink);background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--radius-sm);cursor:pointer;
  transition:background var(--fast) var(--ease),transform var(--fast) var(--ease)}
.pinpad button:hover{background:var(--surface)}
.pinpad button:active{transform:translateY(1px);background:var(--gold-lt)}
.pinpad button.ghosted{font-size:var(--t-sm);font-weight:500;color:var(--ink-3)}
@media(prefers-reduced-motion:reduce){.pinpad button:active{transform:none}}

.lockcard .btn{width:100%}
/* .linkish is styled only inside .card elsewhere; the lock is its own shape,
   so it needs the same treatment stated here rather than inherited. */
.lockcard .linkish{display:block;width:100%;margin-top:var(--s-3);background:none;border:0;
  color:var(--ink-3);font-size:var(--t-sm);font-family:inherit;cursor:pointer;
  text-decoration:underline;text-underline-offset:3px}
.lockcard .linkish:hover{color:var(--ink)}
.lockcard .msg{min-height:18px;margin-bottom:6px}
.lockcard .field{text-align:left;margin-bottom:var(--s-3)}

@media(max-width:380px){
  .pinpad button{height:56px}
  .lockcard{padding:var(--s-5) var(--s-4)}
}

/* ============================ 34. branding =============================
   The owner's side of the marks. The logo well is chequered so a PNG with a
   transparent background reads as transparent rather than as white — the
   commonest confusion when a shop uploads a mark cut out for a dark sign. */

.brandgrid{display:grid;grid-template-columns:minmax(200px,260px) 1fr;gap:var(--s-5);
  align-items:start}
@media(max-width:760px){.brandgrid{grid-template-columns:1fr}}

.logodrop{margin-top:6px;height:132px;display:grid;place-items:center;padding:var(--s-3);
  border:1px dashed var(--border-strong);border-radius:var(--radius);
  background-color:var(--surface);
  background-image:
    linear-gradient(45deg,var(--surface-2) 25%,transparent 25%,transparent 75%,var(--surface-2) 75%),
    linear-gradient(45deg,var(--surface-2) 25%,transparent 25%,transparent 75%,var(--surface-2) 75%);
  background-size:16px 16px;background-position:0 0,8px 8px}
.logodrop img{max-height:100%;max-width:100%;object-fit:contain}
.logodrop .none{color:var(--ink-4);font-size:var(--t-sm)}

.swatchpick{width:44px;height:38px;padding:2px;border:1px solid var(--border);
  border-radius:var(--r-xs);background:var(--surface);cursor:pointer;flex:0 0 auto}

/* The post-sale strip. Sits where the eye already is after a sale, and
   leaves when the next one starts. */
.lastsale{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-4);
  padding:10px var(--s-4);border:1px solid var(--ok-line);background:var(--ok-bg);
  border-radius:var(--radius)}
.lastsale[hidden]{display:none}
.lastsale .txt{font-weight:600;font-size:var(--t-sm)}
.lastsale .spacer{flex:1}
@media(max-width:520px){
  .lastsale{flex-wrap:wrap}
  .lastsale .spacer{display:none}
}

/* The swatch and its hex are one control: one line, and the swatch keeps its
   own width. The specificity is deliberate — .fgrid sets every input to
   width:100%, which otherwise leaves the colour well filling the cell and the
   hex field squeezed to nothing. */
.brandgrid .row:has(.swatchpick){flex-wrap:nowrap;gap:8px}
.brandgrid .row .swatchpick{flex:0 0 46px;width:46px}
.brandgrid .row:has(.swatchpick) input:not(.swatchpick){flex:1 1 0;min-width:0;width:auto}
/* A grid cell whose content refuses to shrink pushes its neighbour out of the
   row. These let the accent pair narrow instead of stealing the phone field's
   column. */
.brandgrid .fgrid>div{min-width:0}
.brandgrid .row:has(.swatchpick){min-width:0}

/* The receipt button on the idle cover. The cover is a dark plate, so the
   button needs its own room rather than sitting on the hint line. */
#cover #coverReceipt{display:block;margin:var(--s-4) auto 0}
#cover #coverReceipt[hidden]{display:none}
