@import './assets/fonts.css';

/* ════════════════════════════════════════════════════════════════════════════
   ESL HUB — control surface
   ────────────────────────────────────────────────────────────────────────────
   A tool for changing prices on physical hardware in a live shop. The design
   follows from that job:

     · DARK RAIL, LIGHT CANVAS. The rail is chrome — always there, never read.
       Keeping it dark pushes it out of the way and frames the work. The canvas
       is white because that is where prices, money and product names are read
       for hours at a time, and white is where printed-price thinking lives.
     · Hairlines, not shadows. Density without noise.
     · Monospace for every machine value (MAC, opcode, barcode, key, bytes) so
       digits line up and a wrong character is visible at a glance.
     · Colour is reserved for meaning. Green = confirmed/live, amber = waiting,
       red = failed, blue = informational. Nothing is coloured decoratively, so
       a coloured thing on screen is always worth looking at.
   ════════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── canvas (light) ── */
  --bg: #f5f6f8;
  --panel: #ffffff;
  --panel-2: #fafbfc;
  --panel-3: #f0f2f5;
  --line: #e4e7ee;
  --line-2: #ccd3de;

  --ink: #0d1117;
  --ink-2: #333d4d;
  /* Secondary text was too light to read comfortably against white; these are
     both a step darker and used at a larger size. */
  --muted: #5a6472;
  --muted-2: #7d8798;

  /* ── rail (dark) ── */
  --rail-bg: #10141b;
  --rail-bg-2: #0b0e13;
  --rail-line: #222835;
  --rail-ink: #e7ecf4;
  --rail-ink-2: #98a2b3;
  --rail-muted: #616b7b;
  --lime: #c9f751;

  /* ── signal palette, tuned for white ── */
  --ok: #0b8a58;
  --ok-soft: #e8f7f0;
  --ok-line: #9fdcc0;
  --warn: #b8600a;
  --warn-soft: #fef4e6;
  --warn-line: #f3cf99;
  --err: #cf2130;
  --err-soft: #fdecee;
  --err-line: #f5b8bd;
  --info: #2563eb;
  --info-soft: #eaf1fe;
  --info-line: #b6d0fb;
  --violet: #6d38d6;
  --violet-soft: #f1eafd;
  --violet-line: #cfc0f6;
  --teal: #0d7d8c;
  --teal-soft: #e6f6f8;
  --teal-line: #a5dde4;

  /* primary action: charcoal, matching the rail — deliberately not the
     purple/indigo every generated dashboard reaches for */
  --btn: #141920;
  --btn-hover: #262e3a;
  --btn-ink: #ffffff;

  --radius: 14px;
  --radius-sm: 10px;
  /* Onest for the interface, Unbounded for anything that should feel loud.
     Both carry Cyrillic, which IBM Plex Sans does not — Bulgarian was falling
     back to whatever the system had. Mono is now reserved for machine values
     (MAC, barcode, URL) instead of every caption, which is what made this look
     like a terminal. */
  --sans: 'Manrope', 'Onest', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --display: 'Manrope', 'Onest', ui-sans-serif, system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --shadow-sm: 0 1px 2px rgba(13, 17, 23, .04), 0 1px 1px rgba(13, 17, 23, .03);
  --shadow: 0 2px 4px rgba(13, 17, 23, .05), 0 12px 28px -12px rgba(13, 17, 23, .16);
  --shadow-lg: 0 24px 60px -14px rgba(13, 17, 23, .26);

  --rail: 234px;
  --topbar: 56px;
  --row-y: 11px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: tabular-nums;
}

::selection { background: #d9e8ff; color: var(--ink); }

* { scrollbar-width: thin; scrollbar-color: #c8cdd6 transparent; }
*::-webkit-scrollbar { width: 11px; height: 11px; }
*::-webkit-scrollbar-thumb { background: #c8cdd6; border-radius: 7px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background: #aeb5c0; background-clip: content-box; }
*::-webkit-scrollbar-track { background: transparent; }

/* ── typography primitives ───────────────────────────────────────────────── */
.mono { font-family: var(--mono); font-feature-settings: 'zero' 1; }

/* Labels read as words, not as machine output. The old rule set every column
   header, section title and metric caption in tracked uppercase mono, which is
   what made the whole app look like a console. */
.sec-label, thead th, .field > label, .kpi-lbl, .fx-group > label, .ctx-lbl {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
thead th { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.field > label { color: var(--ink-2); }

h1 { font-family: var(--display); font-size: 26px; font-weight: 800; letter-spacing: -.035em; }
h2 { font-size: 15px; font-weight: 700; letter-spacing: -.01em; }
h3 { font-family: var(--display); font-size: 18px; font-weight: 700; letter-spacing: -.02em; }

a { color: var(--info); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: var(--mono); font-size: .92em; background: var(--panel-3); padding: 1px 5px; border-radius: 4px; color: var(--ink-2); }

.hint { color: var(--muted); font-size: 13px; line-height: 1.65; }
.hint-inline { color: var(--muted); font-size: 12.5px; }
.dim { color: var(--muted-2); }
.nowrap { white-space: nowrap; }
.num-big { font-family: var(--display); font-weight: 800; letter-spacing: -.03em; }

/* ── app shell ───────────────────────────────────────────────────────────── */
.app { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); min-height: 100vh; }

.sidebar {
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, var(--rail-bg), var(--rail-bg-2));
  color: var(--rail-ink);
}

.brand { padding: 17px 18px 15px; border-bottom: 1px solid var(--rail-line); }
.brand-logo { display: block; height: 24px; width: auto; max-width: 100%; filter: brightness(0) invert(1); opacity: .94; }
.brand-tag {
  margin-top: 8px;
  font-family: var(--sans); font-size: 10.5px; font-weight: 500; letter-spacing: .04em;
  color: var(--rail-muted);
}
.brand-tag .accent { color: var(--lime); }

.nav { padding: 10px 10px 16px; display: flex; flex-direction: column; gap: 1px; overflow-y: auto; flex: 1; }
.nav-sec {
  padding: 15px 10px 6px;
  font-family: var(--sans); font-size: 11px; font-weight: 600; letter-spacing: .02em;
  color: var(--rail-muted);
}
.nav-sec:first-child { padding-top: 6px; }
.nav button {
  position: relative;
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 11px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--rail-ink-2);
  font-family: var(--sans); font-size: 13.5px; font-weight: 500;
  cursor: pointer; text-align: left;
  transition: background .13s, color .13s;
}
.nav button:hover { background: rgba(255, 255, 255, .05); color: var(--rail-ink); }
.nav button.active { background: rgba(255, 255, 255, .08); color: #fff; }
.nav button.active::before {
  content: ''; position: absolute; left: -10px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 17px; border-radius: 0 3px 3px 0;
  background: var(--lime); box-shadow: 0 0 12px rgba(201, 247, 81, .5);
}
.nav button .nav-count {
  margin-left: auto;
  font-family: var(--sans); font-size: 11.5px; color: var(--rail-muted);
  background: rgba(255, 255, 255, .07); border-radius: 20px; padding: 1px 7px;
}
.nav button.active .nav-count { color: var(--rail-ink); background: rgba(255, 255, 255, .12); }
.nav button .nav-count.alert { color: var(--rail-bg); background: var(--lime); font-weight: 600; }

.side-foot {
  padding: 11px 18px; border-top: 1px solid var(--rail-line);
  font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; color: var(--rail-muted);
  display: flex; align-items: center; gap: 7px;
}
.dot-mini { width: 5px; height: 5px; border-radius: 50%; background: var(--lime); box-shadow: 0 0 7px var(--lime); flex: none; }

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

.topbar {
  position: sticky; top: 0; z-index: 40;
  height: var(--topbar);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 0 20px;
  /* Opaque on purpose. A sticky bar with backdrop-filter has to re-sample the
     backdrop on every scrolled frame, and with a sticky table header moving
     underneath it the compositor visibly tore — the bar flickered while you
     scrolled. The canvas behind it is flat, so the blur bought nothing. */
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.ctx { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ctx-group { display: flex; flex-direction: column; gap: 0; min-width: 0; }
.ctx-lbl { font-size: 11px; font-weight: 500; letter-spacing: 0; color: var(--muted); }
/* The context pickers are custom dropdowns now, so the old background caret
   would sit next to the widget's own — two chevrons on one control. */
.dd.ctx-sel { max-width: 210px; }
.dd.ctx-sel .dd-btn {
  border: 0; background: transparent; padding: 0 2px 0 0;
  font-size: 14px; font-weight: 700; letter-spacing: -.01em;
}
.dd.ctx-sel .dd-btn:hover:not(:disabled) { color: var(--info); }
.dd.ctx-sel .dd-btn.dd-open { box-shadow: none; color: var(--info); }
.ctx-sep { width: 1px; height: 24px; background: var(--line-2); margin: 0 5px; }

.status { display: flex; align-items: center; gap: 11px; }
.status-flag {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 11px 4px 9px;
  border: 1px solid var(--line-2); border-radius: 20px;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; 
  color: var(--muted); white-space: nowrap; background: var(--panel);
}
.status-flag .sf-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted-2); flex: none; }
.status-flag.ok { color: var(--ok); border-color: var(--ok-line); background: var(--ok-soft); }
.status-flag.ok .sf-dot { background: var(--ok); box-shadow: 0 0 0 3px rgba(15, 123, 86, .16); animation: pulse 2.4s ease-in-out infinite; }
.status-flag.down { color: var(--err); border-color: var(--err-line); background: var(--err-soft); }
.status-flag.down .sf-dot { background: var(--err); }

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }

.lang-sw { display: flex; border: 1px solid var(--line-2); border-radius: 7px; overflow: hidden; background: var(--panel); }
.lang-sw button {
  border: 0; background: transparent; color: var(--muted);
  font-family: var(--sans); font-size: 11.5px; font-weight: 500; letter-spacing: 0;
  padding: 5px 9px; cursor: pointer; transition: background .12s, color .12s;
}
.lang-sw button:hover { color: var(--ink-2); }
.lang-sw button.active { background: var(--ink); color: #fff; }

.user-chip { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--ink-2); }
.user-chip b { font-weight: 500; }

main#view { padding: 22px 20px 72px; max-width: 1800px; width: 100%; }

.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.page-head h1 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.page-head p { margin-top: 4px; color: var(--muted); font-size: 13px; max-width: 92ch; line-height: 1.6; }
.page-head .head-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ── cards ───────────────────────────────────────────────────────────────── */
.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 20px;
  margin-bottom: 16px;
}
.card.flush { padding: 0; overflow: hidden; }
.card.plain { box-shadow: none; }
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 13px; flex-wrap: wrap; margin-bottom: 13px;
}
.card.flush .card-head { margin: 0; padding: 12px 15px; border-bottom: 1px solid var(--line); }
.card-head h2 { display: flex; align-items: center; gap: 9px; }
.h2-badge {
  font-family: var(--sans); font-size: 11.5px; font-weight: 500;
  letter-spacing: 0;
  color: var(--muted); background: var(--panel-3);
  border: 1px solid var(--line); border-radius: 20px; padding: 1px 8px;
}
.sec-label { display: block; margin: 18px 0 9px; padding-top: 14px; border-top: 1px solid var(--line); }
.sec-label:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 14px; align-items: start; }

/* ── buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 14px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: var(--btn); color: var(--btn-ink);
  font-family: var(--sans); font-size: 13px; font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: background .13s, border-color .13s, color .13s, opacity .13s, box-shadow .13s, transform .1s;
  box-shadow: 0 1px 2px rgba(13, 17, 23, .16);
}
.btn:hover:not(:disabled) { background: var(--btn-hover); box-shadow: 0 3px 10px -3px rgba(13, 17, 23, .35); }
.btn:active:not(:disabled) { transform: translateY(.5px); }
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }
.btn:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }

.btn.ghost { background: var(--panel); border-color: var(--line-2); color: var(--ink-2); box-shadow: var(--shadow-sm); }
.btn.ghost:hover:not(:disabled) { background: var(--panel-3); color: var(--ink); border-color: #c3c9d3; }
.btn.quiet { background: transparent; border-color: transparent; color: var(--muted); box-shadow: none; }
.btn.quiet:hover:not(:disabled) { background: var(--panel-3); color: var(--ink); }
.btn.danger { color: var(--err); border-color: var(--err-line); background: var(--err-soft); }
.btn.danger:hover:not(:disabled) { background: #fbdcdb; }
.btn.ok { color: var(--ok); border-color: var(--ok-line); background: var(--ok-soft); }
.btn.ok:hover:not(:disabled) { background: #d8efe5; }
.btn.sm { padding: 5px 10px; font-size: 12px; gap: 5px; }
.btn.xs { padding: 3px 8px; font-size: 11px; gap: 4px; }
.btn.block { width: 100%; }
.btn.icon { padding: 6px; }
.btn svg.lucide { width: 15px; height: 15px; }
.btn.sm svg.lucide { width: 13px; height: 13px; }
.btn.xs svg.lucide { width: 12px; height: 12px; }

.rowbtns { display: flex; align-items: center; gap: 4px; justify-content: flex-end; }
.icon-btn {
  display: none;
  border: 1px solid var(--line-2); background: var(--panel); color: var(--ink-2);
  border-radius: var(--radius-sm); padding: 6px 9px; cursor: pointer; font-size: 15px;
}

/* segmented control (density, period) */
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: var(--radius-sm); overflow: hidden; background: var(--panel); }
.seg button {
  border: 0; background: transparent; color: var(--muted);
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  padding: 5px 10px; cursor: pointer; white-space: nowrap;
}
.seg button + button { border-left: 1px solid var(--line); }
.seg button:hover { color: var(--ink-2); background: var(--panel-2); }
.seg button.on { background: var(--ink); color: #fff; }

/* ── forms ───────────────────────────────────────────────────────────────── */
/* Fields were bottom-aligned, so a longer hint under one of them pushed its
   input up and the row came out as a staircase. Align to the top and give the
   label band a floor instead, so every input in a row starts at the same y. */
.row { display: flex; flex-wrap: wrap; gap: 14px 12px; align-items: flex-start; }
.field { display: flex; flex-direction: column; gap: 6px; min-width: 140px; }
.field > label { min-height: 17px; line-height: 1.35; }
.field.wide { flex: 1; min-width: 210px; }
.field.narrow { max-width: 150px; }
.field.grow { flex: 1; }
.field .fhint { font-size: 12px; color: var(--muted); line-height: 1.5; }

input, select, textarea {
  font-family: var(--sans); font-size: 13.5px; color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  padding: 8px 11px; width: 100%;
  transition: border-color .13s, box-shadow .13s;
}
input::placeholder, textarea::placeholder { color: var(--muted-2); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(20, 25, 32, .09);
}
input.mono { font-family: var(--mono); }
select {
  appearance: none; cursor: pointer; padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2369737f' stroke-width='2.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 11px;
}
input.ro, .ro { background: var(--panel-3); color: var(--muted); cursor: default; }
.ro-wrap { display: flex; gap: 6px; }
.with-btn { display: flex; gap: 6px; }
.with-btn input { flex: 1; }

.checkline { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--ink-2); cursor: pointer; user-select: none; }
input[type=checkbox] {
  appearance: none; width: 16px; height: 16px; flex: none;
  border: 1.5px solid var(--line-2); border-radius: 4px;
  background: var(--panel); cursor: pointer; position: relative; padding: 0;
  transition: background .12s, border-color .12s;
}
input[type=checkbox]:checked, input[type=checkbox]:indeterminate { background: var(--ink); border-color: var(--ink); }
input[type=checkbox]:checked::after {
  content: ''; position: absolute; inset: 0; background: #fff;
  clip-path: polygon(21% 48%, 41% 68%, 79% 29%, 86% 37%, 41% 82%, 14% 55%);
}
input[type=checkbox]:indeterminate::after {
  content: ''; position: absolute; left: 3px; right: 3px; top: 50%;
  height: 2px; margin-top: -1px; background: #fff;
}
input[type=checkbox]:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }

/* ── toolbar ─────────────────────────────────────────────────────────────── */
.toolbar {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 9px 12px; border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.toolbar .sep { width: 1px; height: 20px; background: var(--line-2); margin: 0 2px; }

.search { position: relative; flex: 1 1 250px; min-width: 190px; max-width: 440px; }
.search > svg.lucide {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--muted-2); pointer-events: none;
}
.search input { padding: 6px 30px 6px 31px; font-size: 13px; }
.search .sclear {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  border: 0; background: transparent; color: var(--muted-2); cursor: pointer;
  padding: 3px; border-radius: 4px; display: none; line-height: 0;
}
.search .sclear:hover { color: var(--ink); background: var(--panel-3); }
.search.has-val .sclear { display: block; }
.search kbd {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-family: var(--sans); font-size: 11.5px; color: var(--muted-2);
  border: 1px solid var(--line-2); border-radius: 4px; padding: 0 4px; pointer-events: none;
}
.search.has-val kbd, .search input:focus ~ kbd { display: none; }

.chips { display: flex; gap: 4px; flex-wrap: wrap; }
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  border: 1px solid var(--line-2); border-radius: 20px;
  background: var(--panel); color: var(--muted);
  font-family: var(--sans); font-size: 11.5px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.chip:hover { color: var(--ink-2); border-color: #c3c9d3; }
.chip.on { background: var(--ink); border-color: var(--ink); color: #fff; }
.chip .c { font-family: var(--sans); font-size: 11.5px; color: var(--muted-2); }
.chip.on .c { color: rgba(255, 255, 255, .72); }
.chip .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }

.fx-toggle .fx-n {
  font-family: var(--sans); font-size: 11.5px; font-weight: 600;
  background: var(--ink); color: #fff; border-radius: 20px; padding: 0 5px; margin-left: 1px;
}
.chip.on .fx-n { background: #fff; color: var(--ink); }

.fx-panel {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 10px 12px; padding: 13px 12px;
  border-bottom: 1px solid var(--line); background: var(--panel-3);
  animation: fxopen .16s ease;
}
@keyframes fxopen { from { opacity: 0; transform: translateY(-4px); } }
.fx-group { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fx-group > select, .fx-group > input { padding: 5px 9px; font-size: 12.5px; }
.fx-group > select { padding-right: 26px; background-position: right 8px center; }
.fx-range { display: flex; align-items: center; gap: 5px; }
.fx-range input { padding: 5px 8px; font-size: 12.5px; }
.fx-range span { color: var(--muted-2); font-family: var(--sans); font-size: 11px; }
.fx-foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding-top: 2px; }

.count { font-family: var(--sans); font-size: 11px; color: var(--muted); white-space: nowrap; }
.spacer { flex: 1; }

/* popover (column chooser, saved views) */
.pop-wrap { position: relative; }
.pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 50;
  min-width: 210px; padding: 8px;
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  animation: pop .13s ease;
}
.pop-title { font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; color: var(--muted); padding: 4px 6px 7px; }
.pop label {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 6px; border-radius: 5px; font-size: 12.5px; color: var(--ink-2); cursor: pointer;
}
.pop label:hover { background: var(--panel-3); }
.pop .pop-sep { height: 1px; background: var(--line); margin: 6px 0; }
.pop button.pop-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 6px; border: 0; border-radius: 5px; background: transparent;
  font-family: var(--sans); font-size: 12.5px; color: var(--ink-2); cursor: pointer; text-align: left;
}
.pop button.pop-item:hover { background: var(--panel-3); color: var(--ink); }

/* ── tables ──────────────────────────────────────────────────────────────── */
.tbl-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
thead th {
  position: sticky; top: 0; z-index: 2;
  text-align: left; padding: 11px 14px;
  background: var(--panel); border-bottom: 1.5px solid var(--line-2);
  white-space: nowrap;
}
thead th.sortable { cursor: pointer; user-select: none; }
thead th.sortable:hover { color: var(--ink-2); }
thead th .sort-ind { color: var(--ink); margin-left: 3px; }
thead th.num, td.num { text-align: right; }
thead th.center, td.center { text-align: center; }

tbody td { padding: var(--row-y) 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tbody tr { transition: background .12s, box-shadow .12s; }
tbody tr:hover { background: var(--panel-2); }
tbody tr:hover td:first-child { box-shadow: inset 3px 0 0 var(--info); }
tbody tr.sel { background: var(--info-soft); }
tbody tr.cursor { box-shadow: inset 3px 0 0 var(--ink); }
tbody tr:last-child td { border-bottom: 0; }
td.mono, .mac { font-family: var(--mono); font-size: 12.5px; letter-spacing: .01em; }
.mac { color: var(--ink); }
td.tight { width: 1%; white-space: nowrap; }
.dense { --row-y: 7px; }
.dense tbody td { font-size: 13px; }

.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 11px; padding: 46px 24px; text-align: center; color: var(--muted); font-size: 13px;
}
.empty-ico {
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 12px;
  background: var(--panel-3); border: 1px solid var(--line); color: var(--muted-2);
}
.empty-ico svg.lucide { width: 20px; height: 20px; }
.empty strong { color: var(--ink-2); font-weight: 600; display: block; margin-bottom: 3px; }

.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 9px 13px; border-top: 1px solid var(--line); flex-wrap: wrap;
  background: var(--panel-2);
}
.pages { display: flex; align-items: center; gap: 6px; }

/* ── badges & indicators ─────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 20px;
  border: 1px solid var(--line-2); background: var(--panel-3);
  font-family: var(--sans); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0; color: var(--muted); white-space: nowrap;
}
.badge svg.lucide { width: 12px; height: 12px; }
.badge.on { color: var(--ok); border-color: var(--ok-line); background: var(--ok-soft); }
.badge.off { color: var(--err); border-color: var(--err-line); background: var(--err-soft); }
.badge.warn { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }
.badge.info { color: var(--info); border-color: var(--info-line); background: var(--info-soft); }
.badge.key { color: var(--violet); border-color: var(--violet-line); background: var(--violet-soft); }
.badge.nokey { color: var(--muted-2); border-style: dashed; background: transparent; }
.badge.mut { color: var(--muted); }
.badge.role { letter-spacing: 0; }
.badge.sm { padding: 2px 7px; font-size: 11px; }

.stat-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--muted-2); flex: none; }
.stat-dot.live { background: var(--ok); box-shadow: 0 0 0 3px rgba(15, 123, 86, .15); }
.stat-dot.idle { background: var(--muted-2); }
.stat-dot.never { background: transparent; border: 1.5px dashed var(--muted-2); width: 8px; height: 8px; }
.stat-dot.warn { background: var(--warn); box-shadow: 0 0 0 3px rgba(180, 83, 9, .14); }
.stat-dot.bad { background: var(--err); box-shadow: 0 0 0 3px rgba(198, 43, 43, .14); }

/* liveness reads as a sentence, never a bare number or a question mark */
.live-cell { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.live-cell .lc-txt { font-size: 13px; font-weight: 500; color: var(--ink-2); }
.live-cell .lc-since { font-size: 12px; color: var(--muted); }
.live-cell.off .lc-txt { color: var(--muted); }
.live-cell.never .lc-txt { color: var(--muted-2); font-style: italic; }

.batcell { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 500; }
.batbar { width: 28px; height: 5px; border-radius: 3px; background: var(--panel-3); overflow: hidden; flex: none; border: 1px solid var(--line); }
.batbar i { display: block; height: 100%; }
.bat-ok { color: var(--ink-2); } .bat-ok .batbar i { background: var(--ok); }
.bat-mid { color: var(--warn); } .bat-mid .batbar i { background: var(--warn); }
.bat-low { color: var(--err); } .bat-low .batbar i { background: var(--err); }

.sig { display: inline-flex; align-items: flex-end; gap: 1.5px; height: 11px; vertical-align: middle; }
.sig i { width: 3px; border-radius: 1px; background: var(--line-2); }
.sig i:nth-child(1) { height: 35%; } .sig i:nth-child(2) { height: 58%; }
.sig i:nth-child(3) { height: 79%; } .sig i:nth-child(4) { height: 100%; }
.sig.s2 i:nth-child(-n+2), .sig.s3 i:nth-child(-n+3), .sig.s4 i { background: var(--ok); }
.sig.s1 i:nth-child(1) { background: var(--warn); }

/* A price must never wrap — "0.99 KM" split across two lines reads as two
   different numbers at a glance, which on a pricing tool is unacceptable. */
td[data-c="price"], .eff-price, .eff-old { white-space: nowrap; }
.eff-price { font-size: 14px; font-weight: 700; letter-spacing: -.015em; color: var(--ink); }
.eff-old { font-size: 12px; color: var(--muted-2); text-decoration: line-through; margin-left: 7px; }
.pill-promo {
  font-size: 11px; font-weight: 700;
  color: #fff; background: var(--warn); border: 1px solid var(--warn);
  border-radius: 5px; padding: 1px 6px; margin-left: 7px;
}
.pill-stale {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 600;
  color: var(--warn); border: 1px solid var(--warn-line); background: var(--warn-soft);
  border-radius: 20px; padding: 2px 8px;
}
.pill-stale svg.lucide { width: 12px; height: 12px; }

/* ── article cell ────────────────────────────────────────────────────────── */
/* Was a bare <select> of every article: you could not see the binding without
   reading the option, and one stray scroll silently moved a price to the wrong
   shelf. Now it states the binding and opens a deliberate, searchable picker. */
.artcell {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-width: 190px; padding: 4px 8px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: inherit; text-align: left;
  cursor: pointer; font-family: var(--sans);
  transition: background .12s, border-color .12s;
}
.artcell:hover { background: var(--panel-3); border-color: var(--line-2); }
.artcell .ac-body { min-width: 0; flex: 1; }
.artcell .ac-name { font-size: 13px; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.artcell .ac-meta { display: flex; align-items: center; gap: 8px; margin-top: 2px; font-family: var(--sans); font-size: 11.5px; color: var(--muted); flex-wrap: wrap; }
.artcell .ac-edit { color: var(--muted-2); opacity: 0; transition: opacity .12s; flex: none; }
.artcell:hover .ac-edit { opacity: 1; }
.artcell svg.lucide { width: 14px; height: 14px; }
.artcell.unbound { border: 1px dashed var(--line-2); color: var(--muted); }
.artcell.unbound:hover { border-color: var(--ok); color: var(--ok); background: var(--ok-soft); }
.artcell.unbound .ac-name { font-weight: 500; font-size: 12.5px; color: inherit; }

/* ── push state chip ─────────────────────────────────────────────────────── */
.pushcell { display: flex; align-items: center; gap: 5px; justify-content: flex-end; }
.pchip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px;
  border: 1px solid var(--line-2); border-radius: 20px;
  background: var(--panel); color: var(--muted);
  font-family: var(--sans); font-size: 11.5px; font-weight: 500; letter-spacing: 0;
  cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s;
}
.pchip:hover { border-color: #c3c9d3; color: var(--ink-2); }
.pchip .pc-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
/* The elapsed time sits right after the state word. At 10px in a grotesque,
   "1h" read as "ln" — it needs the size and a separator to be a time. */
.pchip .pc-t { font-size: 11.5px; opacity: .7; font-variant-numeric: tabular-nums; }
.pchip .pc-t::before { content: '· '; opacity: .6; }
.pchip svg.lucide { width: 11px; height: 11px; }
.pchip.running { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }
.pchip.running .pc-dot { animation: pulse 1.1s ease-in-out infinite; }
.pchip.ok { color: var(--ok); border-color: var(--ok-line); background: var(--ok-soft); }
.pchip.partial { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }
.pchip.bad { color: var(--err); border-color: var(--err-line); background: var(--err-soft); }

/* ── push timeline ───────────────────────────────────────────────────────── */
.timeline { display: flex; flex-direction: column; }
.tl-step { display: grid; grid-template-columns: 22px 1fr auto; gap: 11px; padding: 8px 0; position: relative; }
.tl-step:not(:last-child)::before { content: ''; position: absolute; left: 10px; top: 25px; bottom: -3px; width: 1px; background: var(--line-2); }
.tl-ico {
  width: 21px; height: 21px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: var(--panel-3); border: 1px solid var(--line-2); color: var(--muted); z-index: 1;
}
.tl-ico svg.lucide { width: 11px; height: 11px; }
.tl-step.ok .tl-ico { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }
.tl-step.bad .tl-ico { background: var(--err-soft); border-color: var(--err-line); color: var(--err); }
.tl-step.run .tl-ico { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.tl-step.run .tl-ico svg.lucide { animation: spin 1.5s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.tl-label { font-size: 13px; font-weight: 600; color: var(--ink); }
.tl-detail { font-size: 12px; color: var(--muted); line-height: 1.55; margin-top: 2px; }
.tl-at { font-family: var(--sans); font-size: 11.5px; color: var(--muted-2); white-space: nowrap; padding-top: 3px; }

/* ── drawer ──────────────────────────────────────────────────────────────── */
.drawer-back { position: fixed; inset: 0; z-index: 90; background: rgba(15, 19, 25, .3); backdrop-filter: blur(2px); animation: fade .16s ease; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 91;
  width: min(580px, 100vw); display: flex; flex-direction: column;
  background: var(--panel); border-left: 1px solid var(--line-2);
  box-shadow: -20px 0 50px rgba(15, 19, 25, .16);
  animation: slidein .2s cubic-bezier(.2, .8, .3, 1);
}
@keyframes slidein { from { transform: translateX(26px); opacity: .5; } }
@keyframes fade { from { opacity: 0; } }
.drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 15px 18px; border-bottom: 1px solid var(--line); }
.drawer-head h3 { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.drawer-body { flex: 1; overflow-y: auto; padding: 18px; }
.drawer-foot { padding: 12px 18px; border-top: 1px solid var(--line); display: flex; gap: 8px; flex-wrap: wrap; align-items: center; background: var(--panel-2); }

/* ── key/value list ──────────────────────────────────────────────────────── */
.kv { display: flex; flex-direction: column; }
.kv-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line); }
.kv-row:last-child { border-bottom: 0; }
.kv-row .k { font-size: 12.5px; color: var(--muted); }
.kv-row .v { font-family: var(--sans); font-size: 12.5px; color: var(--ink-2); text-align: right; }
.kv-row .v.strong { color: var(--ink); font-weight: 600; }

/* ── dashboard ───────────────────────────────────────────────────────────── */
.dash { display: flex; flex-direction: column; gap: 14px; }
.dash-cols { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 14px; align-items: start; }
.dash-cols-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 14px; align-items: start; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 12px; }
.kpi {
  position: relative; overflow: hidden; text-align: left;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 16px 17px 17px;
  font-family: var(--sans); cursor: pointer;
  transition: border-color .16s, box-shadow .16s, transform .16s;
}
/* A wash of the metric's own colour, so a row of cards reads as six different
   things at a glance instead of six identical white rectangles. */
.kpi::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(340px 130px at 100% 0%, var(--accent-soft, transparent), transparent 70%);
}
.kpi:hover:not(:disabled) { border-color: var(--accent, var(--line-2)); box-shadow: var(--shadow); transform: translateY(-1px); }
.kpi:disabled { cursor: default; }
.kpi-ico {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 10px; margin-bottom: 11px;
  background: var(--accent, var(--muted)); color: #fff;
  box-shadow: 0 4px 10px -4px var(--accent, transparent);
}
.kpi-ico svg.lucide { width: 17px; height: 17px; }
.kpi-num { position: relative; font-family: var(--display); font-size: 31px; font-weight: 800; letter-spacing: -.04em; line-height: 1; color: var(--ink); }
.kpi-lbl { position: relative; margin-top: 8px; color: var(--ink-2); }
.kpi-sub { position: relative; margin-top: 3px; font-size: 12px; color: var(--muted); }
.kpi.ok { --accent: #0f9d63; --accent-soft: rgba(15,157,99,.10); }
.kpi.info { --accent: #2563eb; --accent-soft: rgba(37,99,235,.10); }
.kpi.warn { --accent: #e07a12; --accent-soft: rgba(224,122,18,.12); }
.kpi.violet { --accent: #7c3aed; --accent-soft: rgba(124,58,237,.10); }
.kpi.bad { --accent: #e0333a; --accent-soft: rgba(224,51,58,.10); }
.kpi.slate { --accent: #55607a; --accent-soft: rgba(85,96,122,.09); }

/* the value / time-saved panel — the one screen shown to a shop owner */
.value-panel {
  background: linear-gradient(140deg, #12161d, #1d242f 62%, #223040);
  color: #fff; border: 0; border-radius: var(--radius);
  padding: 20px; box-shadow: var(--shadow);
  position: relative; overflow: hidden;
}
.value-panel::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(520px 220px at 88% 0%, rgba(201, 247, 81, .13), transparent 62%);
  pointer-events: none;
}
.value-panel .vp-head {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; 
  color: rgba(255, 255, 255, .55);
}
.value-panel .vp-main { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 14px 0 4px; }
.value-panel .vp-num { font-family: var(--sans); font-size: 40px; font-weight: 600; letter-spacing: -.03em; line-height: 1; color: var(--lime); }
.value-panel .vp-unit { font-size: 15px; font-weight: 500; color: rgba(255, 255, 255, .8); }
.value-panel .vp-sub { font-size: 13px; color: rgba(255, 255, 255, .72); line-height: 1.6; }
.value-panel .vp-assume {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(255, 255, 255, .13);
  font-size: 11.5px; color: rgba(255, 255, 255, .5); line-height: 1.55;
}
.value-panel .vp-assume a { color: var(--lime); }
.value-panel .vp-split { display: flex; gap: 26px; flex-wrap: wrap; margin-top: 14px; }
.value-panel .vp-cell .vc-n { font-family: var(--sans); font-size: 19px; font-weight: 600; color: #fff; }
.value-panel .vp-cell .vc-l { font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; color: rgba(255, 255, 255, .48); margin-top: 2px; }

/* exception list — what needs a human, with the fix one click away */
.exc { display: flex; flex-direction: column; }
.exc-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 15px; border-bottom: 1px solid var(--line);
}
.exc-row:last-child { border-bottom: 0; }
.exc-ico { width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; flex: none; }
.exc-ico svg.lucide { width: 15px; height: 15px; }
.exc-ico.warn { background: var(--warn-soft); color: var(--warn); border: 1px solid var(--warn-line); }
.exc-ico.bad { background: var(--err-soft); color: var(--err); border: 1px solid var(--err-line); }
.exc-ico.info { background: var(--info-soft); color: var(--info); border: 1px solid var(--info-line); }
.exc-ico.ok { background: var(--ok-soft); color: var(--ok); border: 1px solid var(--ok-line); }
.exc-body { flex: 1; min-width: 0; }
.exc-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.exc-sub { font-size: 12px; color: var(--muted); margin-top: 1px; line-height: 1.5; }
.exc-n { font-family: var(--sans); font-size: 17px; font-weight: 600; color: var(--ink); flex: none; }
.exc-clean { display: flex; align-items: center; gap: 9px; padding: 15px; color: var(--ok); font-size: 13px; }

/* charts */
.chart-wrap { padding: 4px 2px 0; }
.chart-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 10px; }
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--muted); }
.chart-legend i { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.bar-col rect { transition: opacity .12s; }
.bar-col:hover rect { opacity: .78; }

/* horizontal distribution rows (battery, panel mix, per-gateway) */
.dist { display: flex; flex-direction: column; gap: 9px; }
.dist-row { display: grid; grid-template-columns: 92px minmax(0, 1fr) 44px; align-items: center; gap: 10px; }
.dist-row .dl { font-size: 12px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dist-row .db { height: 7px; border-radius: 4px; background: var(--panel-3); overflow: hidden; }
.dist-row .db i { display: block; height: 100%; background: var(--ink); border-radius: 4px; }
.dist-row .dn { font-family: var(--sans); font-size: 12px; color: var(--muted); text-align: right; }

/* quick actions */
.quick { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.quick button {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 12px; border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  background: var(--panel); color: var(--ink-2);
  font-family: var(--sans); font-size: 12.5px; font-weight: 500; cursor: pointer; text-align: left;
  transition: background .12s, border-color .12s, color .12s;
}
.quick button:hover { background: var(--panel-3); border-color: #c3c9d3; color: var(--ink); }
.quick button svg.lucide { width: 15px; height: 15px; color: var(--muted); flex: none; }
.quick button:hover svg.lucide { color: var(--ink); }

/* ── audit log ───────────────────────────────────────────────────────────── */
.evt-row { display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; gap: 11px; align-items: start; padding: 9px 0; border-bottom: 1px solid var(--line); }
.evt-row:last-child { border-bottom: 0; }
.evt-ico { width: 25px; height: 25px; border-radius: 7px; display: grid; place-items: center; flex: none; background: var(--panel-3); border: 1px solid var(--line); color: var(--muted); }
.evt-ico svg.lucide { width: 12px; height: 12px; }
.evt-row.ok .evt-ico { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok); }
.evt-row.bad .evt-ico { background: var(--err-soft); border-color: var(--err-line); color: var(--err); }
.evt-sum { font-size: 13px; color: var(--ink); }
.evt-meta { font-size: 11.5px; color: var(--muted); margin-top: 1px; display: flex; gap: 9px; flex-wrap: wrap; }
.evt-meta .mono { font-size: 11px; }
.evt-at { font-family: var(--sans); font-size: 11px; color: var(--muted-2); white-space: nowrap; }

/* ── settings sub-navigation ─────────────────────────────────────────────── */
.set-grid { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: 18px; align-items: start; }
.set-nav { position: sticky; top: calc(var(--topbar) + 18px); display: flex; flex-direction: column; gap: 1px; }
.set-nav button {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 11px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--muted);
  font-family: var(--sans); font-size: 13px; font-weight: 500; cursor: pointer; text-align: left;
}
.set-nav button:hover { background: var(--panel-3); color: var(--ink-2); }
.set-nav button.on { background: var(--panel); border: 1px solid var(--line); color: var(--ink); box-shadow: var(--shadow-sm); }
.set-nav button svg.lucide { width: 15px; height: 15px; }

/* ── selection / bulk bar ────────────────────────────────────────────────── */
.bulkbar {
  position: sticky; bottom: 16px; z-index: 45;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 14px auto 0; width: fit-content; max-width: 100%;
  padding: 9px 12px 9px 16px;
  background: var(--ink); border-radius: 40px; color: #fff;
  box-shadow: 0 14px 36px rgba(15, 19, 25, .3);
  animation: pop .16s ease;
}
.bulkbar .bb-n { font-family: var(--sans); font-size: 12.5px; font-weight: 600; }
.bulkbar .hint-inline { color: rgba(255, 255, 255, .6); }
.bulkbar .btn.ghost { background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .18); color: #fff; }
.bulkbar .btn.ghost:hover { background: rgba(255, 255, 255, .2); }
.bulkbar .btn.quiet { color: rgba(255, 255, 255, .7); }
.bulkbar .btn.quiet:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.bulkbar .btn:not(.ghost):not(.quiet) { background: var(--lime); color: #10141b; }

/* ── modal ───────────────────────────────────────────────────────────────── */
.modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 22px; }
.modal-back { position: absolute; inset: 0; background: rgba(13, 17, 23, .42); backdrop-filter: blur(3px); }
.modal-card {
  position: relative; background: var(--panel);
  border: 1px solid var(--line-2); border-radius: 18px;
  padding: 26px; width: min(660px, 100%); max-height: 88vh; overflow-y: auto;
  box-shadow: 0 24px 64px rgba(15, 19, 25, .28);
  animation: pop .17s cubic-bezier(.2, .8, .3, 1);
}
.modal-card.wide { width: min(900px, 100%); }
@keyframes pop { from { transform: translateY(9px) scale(.985); opacity: 0; } }
.modal-close { position: absolute; top: 12px; right: 12px; z-index: 2; }
.modal-card > h3 { margin-bottom: 13px; padding-right: 34px; }

/* an explanatory block inside confirm dialogs — says exactly what will happen */
.explain {
  display: flex; gap: 11px; padding: 12px 13px; margin: 4px 0 16px;
  background: var(--info-soft); border: 1px solid var(--info-line); border-radius: var(--radius-sm);
  font-size: 12.5px; color: var(--ink-2); line-height: 1.6;
}
.explain svg.lucide { width: 16px; height: 16px; color: var(--info); flex: none; margin-top: 1px; }
.explain.warn { background: var(--warn-soft); border-color: var(--warn-line); }
.explain.warn svg.lucide { color: var(--warn); }
.explain code { background: rgba(255, 255, 255, .6); }

/* ── picker ──────────────────────────────────────────────────────────────── */
.picker-list { max-height: 44vh; overflow-y: auto; margin: 6px -6px 0; }
.pick {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 12px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: inherit; text-align: left; cursor: pointer; font-family: var(--sans);
}
.pick:hover { background: var(--panel-3); }
.pick.cursor { background: var(--panel-3); border-color: var(--ink); }
.pick-thumb {
  width: 34px; height: 34px; border-radius: 6px; flex: none;
  background: var(--panel-3); border: 1px solid var(--line);
  display: grid; place-items: center; overflow: hidden; color: var(--muted-2);
}
.pick-thumb img { width: 100%; height: 100%; object-fit: contain; }
.pick-thumb svg.lucide { width: 15px; height: 15px; }
.pick-body { flex: 1; min-width: 0; }
.pick-name { font-size: 13px; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pick-meta { font-family: var(--sans); font-size: 11.5px; color: var(--muted); margin-top: 1px; display: flex; gap: 9px; flex-wrap: wrap; }
.pick-price { font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--ink); flex: none; }
.pick-src { font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; color: var(--info); }

/* ── toast ───────────────────────────────────────────────────────────────── */
.toast-host { position: fixed; right: 18px; bottom: 18px; z-index: 200; display: flex; flex-direction: column; gap: 8px; align-items: flex-end; pointer-events: none; }
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  min-width: 250px; max-width: 420px; padding: 11px 13px;
  background: var(--panel); border: 1px solid var(--line-2); border-left: 3px solid var(--muted-2);
  border-radius: 12px; box-shadow: var(--shadow-lg);
  font-size: 13.5px; color: var(--ink-2); pointer-events: auto;
  animation: toastin .2s cubic-bezier(.2, .8, .3, 1);
}
.toast.out { animation: toastout .18s ease forwards; }
@keyframes toastin { from { transform: translateX(16px); opacity: 0; } }
@keyframes toastout { to { transform: translateX(16px); opacity: 0; } }
.toast.ok { border-left-color: var(--ok); }
.toast.err { border-left-color: var(--err); }
.toast.warn { border-left-color: var(--warn); }
.toast.info { border-left-color: var(--info); }
.toast > svg.lucide { width: 15px; height: 15px; flex: none; margin-top: 1px; }
.toast.ok > svg.lucide { color: var(--ok); }
.toast.err > svg.lucide { color: var(--err); }
.toast.warn > svg.lucide { color: var(--warn); }
.toast.info > svg.lucide { color: var(--info); }
.toast-body { flex: 1; min-width: 0; }
.toast-title { font-weight: 700; color: var(--ink); }
.toast-sub { font-size: 12px; color: var(--muted); margin-top: 1px; line-height: 1.5; }

/* ── login ───────────────────────────────────────────────────────────────── */
.login-overlay {
  position: fixed; inset: 0; z-index: 150;
  display: flex; align-items: center; justify-content: center; padding: 22px;
  background: var(--rail-bg);
}
.login-overlay::before {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(660px 380px at 50% 0%, rgba(201, 247, 81, .09), transparent 62%),
    linear-gradient(rgba(255, 255, 255, .022) 1px, transparent 1px) 0 0 / 100% 34px,
    linear-gradient(90deg, rgba(255, 255, 255, .022) 1px, transparent 1px) 0 0 / 34px 100%;
}
.login-wrap { position: relative; width: min(380px, 100%); text-align: center; }
.login-logo { height: 28px; filter: brightness(0) invert(1); opacity: .95; }
.login-tag { margin: 12px 0 24px; font-family: var(--sans); font-size: 13px; font-weight: 500; letter-spacing: .02em; color: var(--rail-ink-2); }
.login-tag .accent { color: var(--lime); }
.login-card { background: var(--panel); border-radius: 18px; padding: 28px; text-align: left; box-shadow: 0 30px 70px rgba(0, 0, 0, .45); }
.login-sub { color: var(--muted); font-size: 12.5px; line-height: 1.6; margin-bottom: 18px; }
.login-card label { display: block; margin: 0 0 6px; font-size: 12px; font-weight: 600; color: var(--ink-2); }
.login-card input { margin-bottom: 14px; }
.login-card .btn { margin-top: 4px; }
.login-err { margin-top: 12px; color: var(--err); font-size: 12.5px; min-height: 17px; }

/* ── preview frame (e-paper mock) ────────────────────────────────────────── */
.preview-frame {
  background: #fff; border-radius: 8px; padding: 7px;
  border: 1px solid var(--line-2); box-shadow: var(--shadow);
  display: inline-block; line-height: 0;
}
.preview-frame img, .preview-frame svg { display: block; max-width: 100%; height: auto; border-radius: 3px; }

/* ── template designer ───────────────────────────────────────────────────── */
.tpl-grid { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 18px; align-items: start; }
.tpl-add { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 14px; }
.tpl-props { border-top: 1px solid var(--line); padding-top: 13px; display: flex; flex-direction: column; gap: 10px; }
.tpl-prop-title { font-family: var(--sans); font-size: 11.5px; letter-spacing: 0; color: var(--ink); }
.tpl-canvas-wrap { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.tpl-canvas { background: repeating-conic-gradient(#eceef2 0% 25%, #f6f7f9 0% 50%) 50% / 14px 14px; padding: 18px; border-radius: 10px; border: 1px solid var(--line-2); }
.tpl-check { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ink-2); cursor: pointer; }

/* ── scanner ─────────────────────────────────────────────────────────────── */
.scanwrap { position: relative; border-radius: 10px; overflow: hidden; background: #000; aspect-ratio: 4 / 3; }
.scanwrap video { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-frame { position: absolute; inset: 18% 12%; border: 2px solid var(--lime); border-radius: 8px; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .45); }
.scan-line { position: absolute; left: 12%; right: 12%; height: 2px; background: var(--lime); box-shadow: 0 0 12px var(--lime); animation: scan 2s ease-in-out infinite; }
@keyframes scan { 0%, 100% { top: 20%; } 50% { top: 78%; } }

/* ── misc ────────────────────────────────────────────────────────────────── */
.savebar {
  position: sticky; bottom: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  margin-top: 16px; padding: 12px 15px;
  background: var(--panel);
  border: 1px solid var(--line-2); border-radius: var(--radius); box-shadow: var(--shadow);
}
.savebar-txt { font-size: 12.5px; color: var(--muted); }

pre.raw {
  font-family: var(--sans); font-size: 11.5px; line-height: 1.6; color: var(--ink-2);
  background: var(--panel-3); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px; white-space: pre-wrap; word-break: break-word; max-height: 300px; overflow: auto;
}
details.raw-wrap summary { cursor: pointer; font-size: 12.5px; color: var(--muted); padding: 6px 0; user-select: none; }
details.raw-wrap summary:hover { color: var(--ink-2); }

svg.lucide { stroke: currentColor; fill: none; stroke-width: 2; flex: none; width: 16px; height: 16px; }
.nav button svg.lucide { width: 17px; height: 17px; }

/* ── responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 1240px) {
  .dash-cols { grid-template-columns: 1fr; }
}
@media (max-width: 1080px) {
  .app { grid-template-columns: 1fr; }
  .sidebar { position: fixed; inset: 0 auto 0 0; z-index: 80; width: var(--rail); transform: translateX(-100%); transition: transform .2s cubic-bezier(.2, .8, .3, 1); }
  .app.side-open .sidebar { transform: none; box-shadow: 20px 0 50px rgba(15, 19, 25, .3); }
  .icon-btn { display: inline-flex; }
  main#view { padding: 16px 13px 64px; }
  .topbar { padding: 0 13px; }
  .ctx-sel { max-width: 128px; font-size: 12.5px; }
  .tpl-grid, .set-grid { grid-template-columns: 1fr; }
  .set-nav { position: static; flex-direction: row; overflow-x: auto; gap: 5px; padding-bottom: 4px; }
  .set-nav button { white-space: nowrap; }
}
@media (max-width: 780px) {
  /* The two-line "label over select" context blocks collided and truncated the
     store name to "Gl…". On a narrow screen the labels are dead weight — the
     selects say what they are. */
  .ctx-lbl { display: none; }
  .ctx-group { flex-direction: row; align-items: center; }
  .ctx-sel { font-size: 13px; max-width: 108px; }
  .ctx-sep { height: 18px; margin: 0 3px; }
  .topbar { gap: 8px; }
  .status { gap: 7px; }
}
@media (max-width: 640px) {
  .user-chip b { display: none; }
  .status-flag { padding: 4px 8px; }
  .status-flag span:not(.sf-dot) { display: none; }
  .drawer { width: 100vw; }
  .value-panel .vp-num { font-size: 32px; }
  .dist-row { grid-template-columns: 78px minmax(0, 1fr) 38px; }
  .ctx-sel { max-width: 86px; }
}

/* A drawer is anchored bottom-right and so are the toasts — without this the
   toast stack sits on top of the drawer's action buttons. */
body:has(.drawer) .toast-host { right: calc(min(580px, 100vw) + 16px); }
@media (max-width: 640px) {
  body:has(.drawer) .toast-host { right: 12px; bottom: auto; top: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* Compliance panel in the designer — čl. 11 of the consumer-protection act
   lists exactly what a shelf label must carry, so it is checked while the
   layout is being drawn rather than after a shelf is already wrong. */
.legal-check {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 14px; padding: 11px 13px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--surface-2);
  font-size: 12.5px; line-height: 1.5;
}
.legal-check i { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 1px; }
.legal-check div { display: flex; flex-direction: column; gap: 3px; }
.legal-check b { font-weight: 650; }
.legal-check span { color: var(--muted); }
.legal-check em { font-style: normal; opacity: .72; font-family: var(--sans); font-size: 11px; }
.legal-check.ok { border-color: #bfe3c9; background: #f2fbf5; }
.legal-check.ok i { color: #1c7a3e; }
.legal-check.warn { border-color: #f0d9a8; background: #fdf8ec; }
.legal-check.warn i { color: #a8730c; }

/* ── custom select ─────────────────────────────────────────────────────────
   The native popup is drawn by the OS and cannot be styled or given a preview,
   which is why picking a panel used to be a wall of numbers on a grey sheet. */
.dd { position: relative; display: block; }
.dd-native {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none; appearance: none; border: 0;
}
.dd-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 11px; text-align: left;
  font-family: var(--sans); font-size: 13.5px; font-weight: 500; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  cursor: pointer; transition: border-color .14s, box-shadow .14s, background .14s;
}
.dd-btn:hover:not(:disabled) { border-color: #adb7c6; }
.dd-btn:disabled { opacity: .55; cursor: default; }
.dd-btn.dd-open { border-color: var(--info); box-shadow: 0 0 0 3px rgba(37, 99, 235, .13); }
.dd-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-caret { width: 15px; height: 15px; flex: 0 0 auto; color: var(--muted); transition: transform .16s; }
.dd-btn.dd-open .dd-caret { transform: rotate(180deg); }
.dd.sm .dd-btn { padding: 6px 9px; font-size: 12.5px; }

.dd-pop {
  position: fixed; z-index: 400;
  background: var(--panel); border: 1px solid var(--line-2);
  border-radius: 12px; box-shadow: var(--shadow-lg);
  overflow: hidden; animation: ddIn .13s ease-out;
}
@keyframes ddIn { from { opacity: 0; transform: translateY(-4px) scale(.985); } to { opacity: 1; transform: none; } }
.dd-search { padding: 8px; border-bottom: 1px solid var(--line); }
.dd-search input {
  width: 100%; padding: 7px 10px; font-family: var(--sans); font-size: 13px;
  border: 1px solid var(--line-2); border-radius: 8px; background: var(--panel-2); color: var(--ink);
}
.dd-search input:focus { outline: none; border-color: var(--info); background: var(--panel); }
.dd-list { max-height: 320px; overflow-y: auto; padding: 6px; }
.dd-group {
  padding: 9px 9px 5px; font-size: 11.5px; font-weight: 600; color: var(--muted-2);
}
.dd-opt {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 9px; border: 0; border-radius: 9px; background: transparent;
  font-family: var(--sans); font-size: 13.5px; color: var(--ink); text-align: left; cursor: pointer;
}
.dd-opt:hover, .dd-opt.cur { background: var(--panel-3); }
.dd-opt.on { color: var(--ink); font-weight: 600; }
.dd-opt.off { opacity: .42; cursor: default; }
.dd-opt-txt { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-tick { width: 15px; height: 15px; flex: 0 0 auto; color: var(--info); opacity: 0; }
.dd-opt.on .dd-tick { opacity: 1; }
.dd-empty { padding: 14px; text-align: center; color: var(--muted-2); font-size: 13px; }

/* panel preview — the shape and proportion of the actual tag, drawn to scale */
.dd-thumb { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; }
.dd-panel {
  position: relative; display: block; background: #fff;
  border: 1px solid #b8c0cc; border-radius: 2px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(13, 17, 23, .12);
}
.dd-p-bar { position: absolute; left: 0; right: 0; top: 0; height: 26%; background: #131820; }
.dd-p-price { position: absolute; right: 8%; bottom: 12%; width: 46%; height: 30%; background: #131820; border-radius: 1px; }
.dd-p-price.red { background: #e5262c; }
.dd-p-dot { position: absolute; left: 8%; bottom: 14%; width: 16%; height: 16%; background: #f2c00d; border-radius: 50%; }
.dd-pop-panel .dd-opt { gap: 12px; padding: 7px 9px; }
.dd-pop-panel .dd-opt-txt { font-variant-numeric: tabular-nums; }

/* An unbound tag has nothing to preview. Drawing the demo product here showed a
   price and a barcode the tag will never display. */
.preview-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; width: 260px; min-height: 132px; padding: 20px 16px; text-align: center;
  border: 1.5px dashed var(--line-2); border-radius: var(--radius);
  background: repeating-linear-gradient(45deg, var(--panel-2), var(--panel-2) 9px, var(--panel-3) 9px, var(--panel-3) 18px);
  color: var(--muted);
}
.preview-empty svg.lucide { width: 22px; height: 22px; color: var(--muted-2); }
.preview-empty span { font-weight: 600; font-size: 13px; color: var(--ink-2); }
.preview-empty small { font-size: 12px; line-height: 1.5; max-width: 22ch; }

/* Language picker on the sign-in card — sits top-right of the card so it does
   not compete with the form. */
.login-lang { position: absolute; top: 14px; right: 14px; }
.login-card { position: relative; }
.login-card > h3 { margin-bottom: 6px; padding-right: 84px; }
