/* LAK Portal — palette matched to the public site (dark + teal #1a6c7a). */

:root {
  --accent:        #1a6c7a;
  --accent-hover:  rgba(26,108,122,.78);
  --bg-dark:       #1a1a1a;
  --bg-darker:     #0d0d0d;
  --bg-mid:        #2a2a2a;
  --bg-card:       #1f1f1f;
  --text:          #fff;
  --text-muted:    rgba(255,255,255,.6);
  --text-dim:      rgba(255,255,255,.4);
  --border:        rgba(255,255,255,.12);
  --border-strong: rgba(255,255,255,.22);
  --red:           #D44A2E;
  --green:         #3DAA6B;
  --gold:          #C9A84C;  /* still used for price/status pills */
  /* Six rules already asked for var(--bg) and nothing ever defined it, so those
     six had no background at all. Invisible where they sit on a panel of the
     same colour; obvious the moment one of them floats over text, which is how
     the "Lisa fraas" menu came out see-through. It follows --bg-card, so every
     theme gets it. */
  --bg:            var(--bg-card);
}

/* Medium theme — warm grey paper. Cards lift off the background; text is
   near-black for proper daylight contrast (WCAG-ish), accents stay teal. */
:root[data-theme="medium"] {
  --bg-dark:       #cfd3d8;   /* page background */
  --bg-darker:     #b9bec5;   /* topbar / strong areas */
  --bg-mid:        #ffffff;
  --bg-card:       #f4f5f7;   /* cards lifted from page bg */
  --text:          #1a1f26;
  --text-muted:    rgba(20,25,30,.72);
  --text-dim:      rgba(20,25,30,.48);
  --border:        rgba(0,0,0,.18);
  --border-strong: rgba(0,0,0,.30);
}
:root[data-theme="medium"] .row-chip:not(.service-pill):not(.ledger-pos):not(.ledger-neg):not(.accent):not(.good),
:root[data-theme="medium"] .meta-item { background: rgba(0,0,0,.07); }
:root[data-theme="medium"] .ledger-pos,
:root[data-theme="medium"] .row-chip.good { background: rgba(61,170,107,.18); color: #1a5a3a; }
:root[data-theme="medium"] .ledger-neg { background: rgba(212,74,46,.18); color: #8a2a18; }

/* Light theme — daylight mode */
:root[data-theme="light"] {
  --bg-dark:       #f4f5f7;
  --bg-darker:     #e7e9ee;
  --bg-mid:        #ffffff;
  --bg-card:       #ffffff;
  --text:          #1a1a1a;
  --text-muted:    rgba(0,0,0,.62);
  --text-dim:      rgba(0,0,0,.42);
  --border:        rgba(0,0,0,.12);
  --border-strong: rgba(0,0,0,.22);
}
:root[data-theme="light"] .pp-cup.sel { color: #fff; }
:root[data-theme="light"] .row-chip:not(.service-pill):not(.ledger-pos):not(.ledger-neg):not(.accent):not(.good),
:root[data-theme="light"] .meta-item { background: rgba(0,0,0,.05); }
:root[data-theme="light"] .ledger-pos,
:root[data-theme="light"] .row-chip.good { background: rgba(61,170,107,.18); color: #1a5a3a; }
:root[data-theme="light"] .ledger-neg { background: rgba(212,74,46,.18); color: #8a2a18; }

* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: 'DM Sans', sans-serif;
  background: var(--bg-dark);
  color: var(--text);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; transition: .15s; }
a:hover { color: var(--accent-hover); }

/* ── Login screen ─────────────────────────────── */
.login-screen {
  position: fixed; inset: 0;
  background: linear-gradient(180deg, var(--bg-darker) 0%, var(--bg-dark) 100%);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  z-index: 1000; gap: 20px; padding: 24px;
}
.lcard {
  background: rgba(255,255,255,.04);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 34px 30px;
  width: 100%; max-width: 420px;
  display: flex; flex-direction: column; gap: 13px;
  box-shadow: 0 20px 60px rgba(0,0,0,.5);
}
.ltitle {
  color: var(--text);
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 300; font-size: 24px;
  letter-spacing: 6px; text-transform: uppercase;
  text-align: center;
}
.lsub {
  color: var(--text-dim);
  font-size: 11px; letter-spacing: 4px;
  text-align: center; margin-top: -6px;
}
.role-btns {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px;
  margin-top: 8px;
}
.rbtn {
  padding: 10px 4px;
  border: 1.5px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-family: 'DM Sans', sans-serif;
  font-size: 11px; font-weight: 500;
  letter-spacing: 1.5px; text-transform: uppercase;
  cursor: pointer; transition: .15s;
}
.rbtn:hover { border-color: var(--border-strong); }
.rbtn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text);
  font-weight: 700;
}
.lin {
  width: 100%;
  padding: 12px 14px;
  border-radius: 8px;
  border: 1.5px solid var(--border);
  background: rgba(255,255,255,.04);
  color: var(--text);
  font: 14px 'DM Sans', sans-serif;
  outline: none; transition: .15s;
}
.lin::placeholder { color: var(--text-dim); }
.lin:focus { border-color: var(--accent); background: rgba(255,255,255,.06); }
.lbtn {
  width: 100%;
  padding: 13px;
  background: var(--accent);
  color: var(--text);
  border: none; border-radius: 8px;
  font: 600 12px 'DM Sans', sans-serif;
  letter-spacing: 2px; text-transform: uppercase;
  cursor: pointer; transition: .15s;
}
.lbtn:hover     { background: var(--accent-hover); }
.lbtn:disabled  { opacity: .5; cursor: wait; }
.lerr {
  color: #ff7a6b;
  font-size: 12px; text-align: center;
  min-height: 16px;
}

/* ── Signed-in shell ───────────────────────────── */
/* The header scrolls sideways rather than overflowing the page.
   Erik, 2026-09-26: on a narrow screen the five things in here did not fit,
   and because nothing could scroll they pushed the DOCUMENT wider than the
   viewport. Everything else then kept the old width and left a band of empty
   space down the right — it read as the page having gone narrow, but the page
   was fine; the header was too wide. Same treatment as .apptabs below. */
.topbar {
  background: var(--bg-darker);
  padding: 10px 14px;
  display: flex; align-items: center; gap: 12px;
  position: sticky; top: 0; z-index: 100;
  border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none;
}
.topbar::-webkit-scrollbar { display: none; }
/* Nothing in the bar may be squeezed: shrinking is what turned the role badge
   into two cramped lines before the row gave up and overflowed anyway. */
.topbar > * { flex: 0 0 auto; }
.topbar-title {
  color: var(--text);
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 300; font-size: 18px;
  letter-spacing: 4px; text-transform: uppercase;
  /* Grows to push the rest right on a wide screen, keeps its own width on a
     narrow one and lets the bar scroll instead. */
  flex: 1 0 auto;
}
.role-badge, .logout-btn, .ask-btn, .lang-switcher { white-space: nowrap; }
.role-badge {
  background: rgba(255,255,255,.06);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 4px 11px;
  font-size: 10px; font-weight: 600;
  letter-spacing: 1px; text-transform: uppercase;
}
.logout-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 7px;
  padding: 6px 12px;
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: .5px;
  cursor: pointer; transition: .15s;
}
.logout-btn:hover { border-color: var(--red); color: var(--red); }

/* "Ask" — the customer's one way to start a conversation, on every tab.
   Shaped like the sign-out button so the header keeps one visual language,
   but tinted to the accent: it is the thing we WANT pressed. */
.ask-btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  border-radius: 7px;
  padding: 6px 12px;
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: .5px;
  cursor: pointer; transition: .15s;
}
.ask-btn:hover { background: var(--accent); color: var(--text); }
/* On a phone the header already carries five things. Keep the envelope, drop
   the word — the title attribute still says what it is. */
@media (max-width: 560px) {
  .ask-btn-text { display: none; }
  .ask-btn { padding: 6px 9px; }
}

/* Section tabs under the topbar */
.apptabs {
  background: var(--bg-darker);
  display: flex; overflow-x: auto; gap: 2px;
  padding: 0 8px;
  border-bottom: 1px solid var(--border);
  scrollbar-width: none;
}
.apptabs::-webkit-scrollbar { display: none; }
.tab {
  padding: 12px 14px;
  background: transparent; border: none;
  color: var(--text-dim);
  font: 500 12px 'DM Sans',sans-serif;
  letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer; white-space: nowrap;
  border-bottom: 3px solid transparent;
  transition: .15s;
}
.tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.tab:hover:not(.active) { color: var(--text-muted); }

.main {
  padding: 18px;
  max-width: 1200px;
  margin: 0 auto;
}
.section { display: none; }
.section.active { display: block; }

.section-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px; flex-wrap: wrap; gap: 8px;
}
.section-title {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 300; font-size: 24px;
  letter-spacing: 4px; text-transform: uppercase;
}
.section-count {
  color: var(--text-dim);
  font-size: 12px;
  letter-spacing: 1px;
}

/* Generic card (used for the empty-state shell) */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 10px;
}
.card-header {
  padding: 10px 14px;
  background: rgba(255,255,255,.04);
  border-bottom: 1px solid var(--border);
  font-weight: 600; font-size: 12px;
  letter-spacing: 1px; text-transform: uppercase;
  color: var(--text-muted);
}
.card-body {
  padding: 16px;
  color: var(--text-muted);
  font-size: 14px; line-height: 1.5;
}
.card-body strong { color: var(--text); }
.card-body code {
  background: rgba(255,255,255,.06);
  padding: 2px 6px; border-radius: 4px;
  font: 12px 'DM Mono', monospace;
  color: var(--accent);
}
.card-body p { margin-top: 10px; }

/* ── List rows (clients, orders, etc.) ──────────── */
.search-bar {
  display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap;
}
.search-input {
  flex: 1; min-width: 160px;
  padding: 9px 12px;
  border: 1.5px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  color: var(--text);
  font: 13px 'DM Sans',sans-serif;
  outline: none; transition: .15s;
}
.search-input:focus { border-color: var(--accent); }

/* Copy-to-clipboard button on a client field (admin only). Sits in the field's
   bottom-right corner rather than beside the input, so adding it does not
   re-flow a form that was laid out without it. */
/* The wrapper is the input's own box, so the button cannot drift away from it
   however the field around it grows or shifts. */
.copy-wrap { position: relative; display: block; width: 100%; min-width: 0; }
.copy-wrap > input, .copy-wrap > textarea { width: 100%; }
.copy-btn {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  background: transparent; border: 1px solid var(--border); color: var(--text-dim);
  border-radius: 5px; width: 24px; height: 24px; line-height: 1;
  font-size: 13px; cursor: pointer; transition: .12s; padding: 0;
}
/* Every button on the same right edge, including the datalist ones — Erik
   asked for the column to line up. It sits over the arrow the browser draws
   there; tapping anywhere else in the field still opens the suggestions, so
   the arrow was never the only way in. */
/* A textarea is tall; centred would put the button in the middle of the text. */
.copy-wrap.is-area > .copy-btn { top: auto; bottom: 8px; transform: none; }
/* Keep the typed text out from under the button. */
.copy-wrap > input, .copy-wrap > textarea { padding-right: 36px; }
.copy-btn:hover { border-color: var(--accent); color: var(--accent); }
.copy-btn.ok { border-color: var(--green); color: var(--green); }
.copy-btn.ok::after { content: ' ✓'; }

/* On a narrow screen the text box gets a line of its own and the dropdowns
   pair up underneath it. Erik, 2026-09-27: the search box was too narrow to
   use — it was sharing a line with a 130-200px select and keeping whatever
   was left.
   `!important` is not decoration here: every one of these controls carries an
   inline `min-width` in index.php (about thirty of them), and an inline style
   beats a stylesheet rule. Overriding at the one place that knows the screen
   is narrow is better than editing thirty tags. */
@media (max-width: 620px) {
  .search-bar > .search-input        { min-width: 0 !important; }
  /* 0 0, not 1 1: a 100% basis still shares a line when the item is allowed to
     shrink, which left the box NARROWER than before (208px → 169px). Refusing
     to shrink is what actually puts it on a line of its own. */
  .search-bar > input.search-input   { flex: 0 0 100% !important; max-width: none !important; }
  .search-bar > select.search-input  { flex: 1 0 calc(50% - 3px) !important; }
}

.row-list { display: flex; flex-direction: column; gap: 6px; }
/* The end of a paged list. Centred and quiet — it is a way onward, not a row. */
.list-more { display: flex; gap: 8px; justify-content: center; padding: 10px 0 2px; }

/* Arved → Ostud. Receipts are read by looking at them, so the picture leads and
   the controls sit beside it rather than under a row of text. */
.doc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 10px; }
.doc-card {
  display: flex; gap: 10px; padding: 8px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px;
}
.doc-card > a { flex: 0 0 92px; display: block; }
.doc-card img {
  width: 92px; height: 112px; object-fit: cover; display: block;
  border-radius: 7px; background: var(--bg-mid);
}
.doc-pdf {
  width: 92px; height: 112px; display: flex; align-items: center; justify-content: center;
  font-size: 30px; border-radius: 7px; background: var(--bg-mid); color: var(--text-dim);
}
.doc-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.doc-top  { display: flex; flex-wrap: wrap; gap: 4px; }
.doc-note {
  width: 100%; background: var(--bg-mid); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; font-size: 12.5px;
}
.doc-acts { display: flex; gap: 6px; align-items: center; margin-top: auto; flex-wrap: wrap; }
.doc-acts .doc-move {
  flex: 1 1 auto; min-width: 0; background: var(--bg-mid); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 5px 6px; font-size: 12px;
}
.doc-acts .btn-ghost { font-size: 12px; padding: 5px 9px; }

/* One nav inside another. Lighter than the Shop bar above it, so the eye reads
   the hierarchy without a border round everything. */
/* The language control, above the Settings subtabs. Quiet: it is changed once
   and then never again, so it must be findable without being loud. */
.lang-setting {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 9px;
}
.lang-setting label { color: var(--text-muted); font-size: 13px; }
.lang-setting select {
  background: var(--bg-mid); color: var(--text); border: 1px solid var(--border);
  border-radius: 7px; padding: 6px 9px; font: inherit; font-size: 13px;
}
.lang-setting .om-hint { padding: 0; font-size: 12px; }
.lang-setting input { font: inherit; font-size: 13px; }
/* Configured or not, in a word. Never the secret, never its length. */
.ostud-state { font-size: 12.5px; padding: 3px 9px; border-radius: 6px; white-space: nowrap; }
.ostud-state.on  { background: rgba(61,170,107,.18); color: #6fd39b; }
.ostud-state.off { background: rgba(201,168,76,.18); color: var(--gold); }

/* .pkg-nag — the header reminder — was removed 2026-10-04 along with its
   markup and its script. Daily automatic sending left it nothing to report. */

/* The package preview. Two columns of what is about to leave, so the
   wrong set is noticed before it is sent, not after. */
.pkg-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.pkg-col {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 9px; padding: 10px 12px; min-width: 0;
}
.pkg-col h4 {
  margin: 0 0 8px; font-size: 12px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-dim); font-weight: 600;
}
.pkg-col h4 span {
  margin-left: 6px; color: var(--text); background: rgba(128,128,128,.18);
  border-radius: 20px; padding: 1px 8px; font-size: 12px; letter-spacing: 0;
}
.pkg-col ul { list-style: none; margin: 0; padding: 0; max-height: 240px; overflow: auto; }
.pkg-col li {
  display: flex; gap: 8px; align-items: baseline;
  padding: 3px 0; font-size: 12.5px; border-bottom: 1px solid rgba(128,128,128,.10);
}
.pkg-col li:last-child { border-bottom: 0; }
.pkg-col li > span:last-child { margin-left: auto; white-space: nowrap; }
.pkg-dim { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pkg-empty { color: var(--text-dim); font-size: 13px; padding: 4px 0; }
.pkg-note {
  margin-top: 12px; padding: 10px 12px; border-radius: 8px; font-size: 13px;
  background: rgba(128,128,128,.10); color: var(--text-muted);
}
.pkg-note.ok { background: rgba(61,170,107,.16); color: #8fe0b4; }
@media (max-width: 560px) {
  .pkg-col ul { max-height: none; }
}

#arved-subtabs .subtab { font-size: 13px; }
.arved-panel { display: none; }
.arved-panel.active { display: block; }
.row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: .12s;
}
.row:hover { border-color: var(--border-strong); }
.row-id   { font: 500 11px 'DM Mono',monospace; color: var(--text-dim); min-width: 60px; }
.row-name { font-weight: 600; font-size: 14px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-meta { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.row-chip {
  background: rgba(255,255,255,.06);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 20px;
  padding: 2px 9px;
  font-size: 10px; font-weight: 600;
  letter-spacing: .5px; text-transform: uppercase;
}
.row-chip.accent      { background: var(--accent); border-color: var(--accent); color: var(--text); }
.row-chip.ledger-pos  { background: rgba(61,170,107,.15); border-color: rgba(61,170,107,.4); color: var(--green); font-family:'DM Mono',monospace; }
.row-chip.ledger-neg  { background: rgba(212,74,46,.15);  border-color: rgba(212,74,46,.4);  color: var(--red);   font-family:'DM Mono',monospace; }
.row-chip.good        { background: rgba(61,170,107,.15); border-color: rgba(61,170,107,.4); color: var(--green); }
.row-note {
  display: block; margin-top: 2px;
  font-size: 11px; color: var(--text-dim); font-weight: 400;
}

/* "How did it run?" — the client-side ask for rpm + speed, and the quick form
   behind it. Deliberately plain: the card has to read as a question, not as
   another list to scroll past. */
.dash-runs-lead {
  padding: 10px 14px 12px;
  font-size: 13px; line-height: 1.5; color: var(--text-muted);
}
.run-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.run-row-main { flex: 1 1 180px; min-width: 0; }
.run-best { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.run-pitch {
  font-family: 'DM Mono', monospace;
  font-size: 12px; font-weight: 500;
  color: var(--accent-text, var(--text-muted));
  opacity: .85; margin-left: 4px;
}
.run-odd  { color: var(--red); }

/* The AI packet's manual-copy fallback, for in-app browsers that refuse the
   clipboard API. Monospace so a stray line break is visible before pasting. */
.aip-open { font-size: 12px; color: var(--text-dim); }
.aip-open a {
  color: var(--accent); text-decoration: none; margin-left: 8px;
  border-bottom: 1px solid transparent;
}
.aip-open a:hover { border-bottom-color: var(--accent); }
.aip-text {
  width: 100%; font: 12px/1.45 'DM Mono', monospace;
  background: var(--bg-darker); color: var(--text-muted);
  border: 1px solid var(--border); border-radius: 8px; padding: 10px;
  resize: vertical;
}

/* My LAK — the customer's album. Square tiles because the cropper already
   makes every photo a square, so the grid never has a ragged edge. */
.gal-year { margin-top: 18px; }
.gal-year-head {
  display: flex; align-items: baseline; gap: 10px;
  font-size: 15px; font-weight: 600; letter-spacing: .5px;
  margin: 0 0 10px; padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.gal-year-n { font-size: 11px; color: var(--text-dim); font-weight: 400; }
.gal-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.gal-tile {
  position: relative; margin: 0; cursor: pointer;
  border-radius: 10px; overflow: hidden;
  background: var(--bg-darker); border: 1px solid var(--border);
}
.gal-tile img {
  display: block; width: 100%; aspect-ratio: 1/1; object-fit: cover;
}
.gal-tile figcaption {
  display: flex; flex-direction: column; gap: 3px;
  padding: 8px 10px 10px;
}
.gal-badge {
  align-self: flex-start;
  font-size: 9px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
  color: var(--text-dim);
}
.gal-cap  { font-size: 12px; line-height: 1.35; color: var(--text); }
.gal-prop { font-size: 11px; color: var(--text-dim); font-family: 'DM Mono', monospace; }
.gal-full {
  display: block; width: 100%; max-height: 52vh; object-fit: contain;
  border-radius: 8px; background: var(--bg-darker); margin-bottom: 14px;
}
.gal-cats { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.gal-cat input { position: absolute; opacity: 0; pointer-events: none; }
.gal-cat span {
  display: inline-block; padding: 6px 12px; border-radius: 20px;
  border: 1px solid var(--border); background: var(--bg-darker);
  font-size: 12px; color: var(--text-muted); cursor: pointer;
}
.gal-cat input:checked + span {
  border-color: var(--accent); color: var(--text); background: var(--accent);
}

/* Compare table. A table because the point is reading down a column — five
   props, one number each, differences visible without arithmetic. It scrolls
   sideways on a phone rather than squeezing the columns into unreadability. */
/* The "already in the comparison" pill, on the closed row between the serial
   and the name. Fixed size so it never eats the name's space. */
.cmp-pill { flex: 0 0 auto; }
.cmp-wrap  { overflow-x: auto; }
.cmp-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cmp-table th,
.cmp-table td {
  padding: 9px 12px; text-align: right; white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
.cmp-table th {
  font-size: 10px; font-weight: 600; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-dim); text-align: right;
}
.cmp-table th:first-child,
.cmp-table td:first-child { text-align: left; }
.cmp-table td { font-family: 'DM Mono', monospace; color: var(--text); }
.cmp-table td.cmp-name { font-family: inherit; font-weight: 600; }
.cmp-table tbody tr:last-child td { border-bottom: 0; }
.cmp-table td:last-child { width: 1%; padding-left: 4px; }
.btn-ghost.is-on { border-color: var(--accent); color: var(--accent); }
.req-spec {
  padding: 10px 12px; margin-bottom: 14px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-darker); font-size: 13px; line-height: 1.5;
}
.run-more { display: block; margin: 10px auto 12px; }
.run-pair { display: flex; gap: 10px; }
.run-pair > * { flex: 1 1 0; min-width: 0; }
.run-slip {
  margin: 4px 0 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-darker);
  font-size: 13px; color: var(--text-dim);
}
.run-slip.ok   { border-color: rgba(61,170,107,.45); color: var(--text); }
.run-slip.ok b { font-size: 20px; color: var(--green); font-family: 'DM Mono', monospace; }
.run-slip.warn { border-color: rgba(212,74,46,.45);  color: var(--red); }
.run-done { text-align: center; padding: 14px 0 20px; }
.run-done-big {
  font-family: 'DM Mono', monospace;
  font-size: 46px; line-height: 1.1; color: var(--green);
}
.run-done-cap {
  font-size: 12px; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-dim); margin-top: 4px;
}
.run-done p { margin-top: 16px; font-size: 14px; line-height: 1.55; color: var(--text-muted); }

/* Dashboard KPI tiles */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}
.kpi {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px 18px;
}
.kpi-label {
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  font-weight: 600;
}
.kpi-value {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 300;
  font-size: 38px;
  letter-spacing: 1px;
  line-height: 1.1;
  color: var(--text);
  margin-top: 6px;
}
.kpi-sub {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 3px;
  letter-spacing: .5px;
}
.kpi.accent { border-color: rgba(26,108,122,.5); background: linear-gradient(135deg, rgba(26,108,122,.18), var(--bg-card)); }
/* Worker Pay: the tiles are recomputed by the server when the worker filter
   changes, so they are briefly stale. Dimmed rather than blanked — a number
   fading for a moment reads as "updating", an empty tile reads as "zero". */
.kpi-busy { opacity: .45; transition: opacity .12s; pointer-events: none; }
.kpi.accent .kpi-value { color: var(--accent); }
.kpi.green  { border-color: rgba(61,170,107,.4); background: linear-gradient(135deg, rgba(61,170,107,.15), var(--bg-card)); }
.kpi.green  .kpi-value { color: var(--green); }
.kpi.danger { border-color: rgba(212,74,46,.45); background: linear-gradient(135deg, rgba(212,74,46,.15), var(--bg-card)); }
.kpi.danger .kpi-value { color: var(--red); }

/* ── Castings inventory ──────────────────────────────────────────────
   Dense on purpose: two dozen moulds across ten classes has to fit on one
   screen, or finding one means scrolling past the rest. */
#stock-availability { display: flex; flex-wrap: wrap; gap: 6px; }
.ov-class {
  display: flex; align-items: center; gap: 5px;
  padding: 5px 9px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-card);
}
.ov-name { font-weight: 700; font-size: 12px; margin-right: 3px; }
.ov-cell {
  font-size: 11px; padding: 2px 6px; border-radius: 5px;
  background: rgba(128,128,128,.12); white-space: nowrap;
}
.ov-cell b { font-weight: 700; margin-left: 2px; }
.ov-cell.ok   { background: rgba(61,170,107,.18);  color: var(--green); }
.ov-cell.low  { background: rgba(201,168,76,.20);  color: #c9a84c; }
.ov-cell.out  { background: rgba(212,74,46,.18);   color: var(--red); }
.ov-cell.na   { opacity: .55; }

/* Castings list: one row per mould, read as a chain — the mould and its shelf
   count, then the classes it builds, then the bore pile each of those draws
   from. .stock-row below is still used by the invoice list. */
.cast-row { display: flex; align-items: stretch; margin-bottom: 7px; cursor: pointer; }
.cast-row.is-off { opacity: .5; }
.cast-row:hover .cast-head { background: var(--bg-mid); border-color: var(--border-strong); }

.cast-head {
  flex: 0 0 186px; background: var(--bg-mid);
  border: 1px solid var(--border); border-right: none; border-radius: 9px 0 0 9px;
  padding: 7px 9px; display: flex; flex-direction: column; gap: 2px; justify-content: center;
}
.cast-name { font-size: 12.5px; font-weight: 600; line-height: 1.25; }
.cast-qty { font-size: 19px; font-weight: 700; line-height: 1.1; }
.cast-qty > i { font-style: normal; font-size: 11px; font-weight: 500; color: var(--text-dim); margin-left: 5px; }
.cast-qty.zero { color: var(--text-dim); }
.cast-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.cast-tags:empty { display: none; }
.cast-tags .tag { font-size: 10px; padding: 1px 5px; border-radius: 4px;
  background: rgba(128,128,128,.18); color: var(--text-muted); }
.cast-tags .tag.part { background: rgba(26,108,122,.30); color: #7fd0dd; }
.cast-tags .tag.off  { background: rgba(212,74,46,.16);  color: var(--red); }
.cast-tags .tag.low  { background: rgba(201,168,76,.20); color: var(--gold); }
.cast-actions { display: flex; gap: 3px; margin-top: 3px; }
.cast-actions .btn-ghost { padding: 1px 7px; font-size: 12px; }

/* The connector between the two boxes. */
.cast-join {
  flex: 0 0 16px; position: relative; background: var(--bg-mid);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.cast-join::after {
  content: ''; position: absolute; top: 50%; left: 0; right: 0;
  height: 1px; background: var(--border-strong);
}

.cast-body {
  flex: 1; min-width: 0; background: var(--bg-card);
  border: 1px solid var(--border); border-radius: 0 9px 9px 0;
  padding: 4px 8px; display: flex; flex-direction: column; justify-content: center; gap: 2px;
}
.lane { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.lane + .lane { border-top: 1px dashed var(--border); padding-top: 2px; }
.lane-classes { display: flex; flex-wrap: wrap; gap: 4px; flex: 1; min-width: 0; }
.lane-classes .cls { font-size: 11px; padding: 1px 6px; border-radius: 5px;
  background: rgba(128,128,128,.14); white-space: nowrap; }
.lane-classes .cls b { font-weight: 700; color: var(--text-muted); margin-left: 3px; }
.lane-arrow { color: var(--text-dim); font-size: 12px; flex: 0 0 auto; }
.lane-none { font-size: 11px; color: var(--text-dim); font-style: italic; flex: 1; }
.pile { font-size: 11px; padding: 2px 7px; border-radius: 5px; white-space: nowrap;
  background: rgba(61,170,107,.15); color: var(--green); flex: 0 0 auto; }
.pile > i { font-style: normal; opacity: .75; }
.pile > b { font-weight: 700; font-size: 12px; margin-left: 4px; }
.pile.zero { background: rgba(212,74,46,.15); color: var(--red); }

@media (max-width: 720px) {
  .cast-row { flex-direction: column; }
  .cast-head { flex: none; border-right: 1px solid var(--border); border-bottom: none;
    border-radius: 9px 9px 0 0; }
  .cast-join { flex: none; height: 9px; border: none;
    border-left: 1px solid var(--border); border-right: 1px solid var(--border); }
  .cast-join::after { top: 0; bottom: 0; left: 50%; right: auto; width: 1px; height: auto; }
  .cast-body { border-radius: 0 0 9px 9px; }
}

/* The invoice rows under Arved → Müügid.
 *
 * This did not fit a narrow screen and the arithmetic says why: column 1 had a
 * 150px floor for a number that needs ~70, and columns 3 and 4 were `auto`,
 * which sizes to content and does NOT shrink — four chips that would not wrap
 * (~290px) and five buttons (~360px). The row could not go below ~950px no
 * matter how little space it was given, so it simply overflowed.
 *
 * Erik, 2026-10-04: "arvete kaardid on liiga laiad ja ei skaleeru korralikult
 * kitsale ekraanile." Three of those five buttons are mine, so is most of this.
 *
 * Fixed by giving every column somewhere to go: a realistic floor on the
 * number, chips that wrap, and a stacked layout below 720px.
 */
.stock-row {
  display: grid; grid-template-columns: minmax(92px, 1fr) minmax(0, 2fr) auto auto;
  align-items: center; gap: 8px;
  padding: 5px 6px; border-radius: 6px; cursor: pointer;
}
.stock-row:hover { background: rgba(128,128,128,.10); }
.stock-row.is-off { opacity: .55; }
.stock-name { font-size: 12.5px; font-weight: 600; }
.stock-specs { display: flex; flex-wrap: wrap; gap: 4px; }
.stock-spec, .stock-bore {
  font-size: 11px; padding: 1px 6px; border-radius: 5px;
  background: rgba(61,170,107,.15); color: var(--green); white-space: nowrap;
}
.stock-spec b, .stock-bore b { font-weight: 700; }
.stock-spec.zero, .stock-bore.empty { background: rgba(128,128,128,.14); color: inherit; opacity: .65; }
.stock-bore i { font-style: normal; opacity: .7; margin-right: 4px; }
.stock-flags { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.stock-actions { display: flex; gap: 3px; flex-wrap: wrap; opacity: 0; transition: opacity .12s; }
.stock-row:hover .stock-actions, .stock-row:focus-within .stock-actions { opacity: 1; }
.stock-actions .btn-ghost { padding: 2px 8px; font-size: 12px; white-space: nowrap; }

/* On a touch screen there is no hover, so buttons hidden until hover can never
   be reached at all — they were invisible AND still taking their full width.
   This is the right question to ask: can this device hover, not how wide is it. */
@media (hover: none) {
  .stock-actions { opacity: 1; }
}

/* Narrow: stop pretending four columns fit. Number and buyer on the first
   line, chips and buttons on their own lines underneath, each free to wrap. */
@media (max-width: 720px) {
  .stock-row {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 6px; padding: 8px;
    border: 1px solid var(--border); border-radius: 8px; margin-bottom: 6px;
  }
  .stock-name   { grid-column: 1; }
  .stock-specs  { grid-column: 2; justify-content: flex-end; }
  .stock-flags  { grid-column: 1 / -1; justify-content: flex-start; }
  .stock-actions{ grid-column: 1 / -1; opacity: 1; }
  .stock-actions .btn-ghost { flex: 0 1 auto; }
}

/* A serial already in use by another prop. Amber, not red: it is sometimes
   deliberate, so this warns rather than blocks. */
input.serial-dup { border-color: rgba(201,168,76,.8) !important; background: rgba(201,168,76,.10); }
.serial-warn { color: #c9a84c; font-weight: 600; }

/* A field whose value the system no longer uses — greyed, but still readable,
   so it is obvious the number is there and equally obvious it is not in play. */
input.is-overridden{opacity:.5;font-style:italic;cursor:not-allowed}

/* Transport price list in Shop → Settings. */
.ship-methods{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:4px}
@media(max-width:820px){.ship-methods{grid-template-columns:1fr}}
.ship-method{border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg-card)}
.ship-method-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
.ship-name{flex:1;min-width:120px;font-weight:600}
.ship-rates{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.ship-rate,.ship-rate-head{display:grid;grid-template-columns:1fr 74px 74px 74px auto;gap:6px;align-items:center}
.ship-rate-head{margin-bottom:4px}
.ship-rate-head span{font-size:10px;letter-spacing:1px;text-transform:uppercase;opacity:.6}
.ship-rate .btn-ghost{padding:2px 9px}
@media(max-width:1100px){
  .ship-rate,.ship-rate-head{grid-template-columns:1fr 60px 60px 60px auto}
}

/* Admin housekeeping bar on an expanded client card. */
.cd-admin {
  display: flex; gap: 6px; flex-wrap: wrap;
  padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--border);
}
.cd-admin .btn-ghost { font-size: 12px; padding: 4px 10px; }

/* Selling a propeller out of a rental box: one name, asked in place, rather
   than a second modal stacked on the one already open. */
.rmc-sell-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border);
}
.rmc-sell-row input { flex: 1 1 180px; min-width: 0; }
.rmc-sell-row .btn-ghost { flex: 0 0 auto; font-size: 12px; padding: 4px 10px; }
.rmc-sell-msg { flex: 1 1 100%; }
.rmc-sell-btn { font-size: 12px; padding: 4px 10px; }

/* Shop purchases on a client card. The purchase is an issued invoice and keeps
   the details it was sent to; where those disagree with the record, the card
   says so rather than silently preferring one of them. */
.cd-shop { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }
.cd-shop-row { padding: 8px 11px; border-radius: 7px; font-size: 12.5px;
  border: 1px solid var(--border); background: var(--bg-darker); }
.cd-shop-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.cd-shop-date, .cd-shop-total { color: var(--text-muted); font-size: 12px; }
.cd-shop-total { margin-left: auto; font-weight: 600; color: var(--text); }
.cd-shop-addr { margin-top: 3px; color: var(--text-muted); }
.cd-shop-diff, .cd-shop-fill { margin-top: 6px; padding: 6px 9px; border-radius: 5px;
  font-size: 12px; line-height: 1.5; }
.cd-shop-diff { background: rgba(214,138,42,.12); border: 1px solid rgba(214,138,42,.35);
  color: #e7b168; }
/* Each mismatch on its own line — run together they read as one sentence and
   it stops being obvious how many fields actually disagree. */
.cd-shop-diff span { display: block; }
.cd-shop-diff b, .cd-shop-fill b { color: var(--text); font-weight: 600; }
.cd-shop-diff i { font-style: normal; color: #ffd79a; }
.cd-shop-fill { background: rgba(26,108,122,.12); border: 1px solid rgba(26,108,122,.35);
  color: var(--text-muted); }
.cd-admin-danger { color: var(--red); }
.cd-admin-danger:hover { border-color: rgba(212,74,46,.5); }

/* ── Manual invoice ──────────────────────────────────────────────────
   Propellers are picked off the orders list rather than retyped. */
.inv-pick { border: 1px solid var(--border); border-radius: 10px; padding: 8px; margin-bottom: 12px; }
.inv-pick-head { display: flex; gap: 10px; align-items: center; margin-bottom: 6px; flex-wrap: wrap; }
.inv-pick-head .search-input { flex: 1; min-width: 180px; }
.inv-pick-list { max-height: 260px; overflow-y: auto; }
.inv-cand {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 5px 7px; border-radius: 6px; cursor: pointer; font-size: 12.5px;
}
.inv-cand:hover { background: rgba(128,128,128,.10); }
.inv-cand.on { background: rgba(61,170,107,.14); }
.inv-cand-main { display: flex; gap: 8px; align-items: baseline; min-width: 0; }
.inv-cand-spec { opacity: .7; font-size: 11.5px; }
.inv-cand-meta { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.inv-cand-add { font-size: 11px; opacity: .6; min-width: 46px; text-align: right; }
.inv-cand.on .inv-cand-add { color: var(--green); opacity: 1; }

.inv-line {
  display: grid; grid-template-columns: 2fr 1fr .6fr .9fr auto;
  gap: 8px; margin-bottom: 6px; align-items: center;
}
.inv-line-src { grid-column: 1 / -1; font-size: 11px; opacity: .55; margin-top: -2px; }
.inv-totals { font-size: 13px; margin-left: auto; }

/* Shared with the storefront: a VAT number VIES confirmed turns the box green. */
.vat-status { font-size: 11px; line-height: 1.45; margin-top: 3px; display: none; }
.vat-status.checking, .vat-status.ok, .vat-status.warn { display: block; }
.vat-status.checking { opacity: .6; }
.vat-status.ok   { color: var(--green); }
.vat-status.warn { color: #c9a84c; }
input.is-valid   { border-color: rgba(61,170,107,.7) !important; background: rgba(61,170,107,.10); }
input.is-invalid { border-color: rgba(201,168,76,.7) !important; }
input.is-checking { border-color: var(--border) !important; }

@media (max-width: 720px) {
  .inv-line { grid-template-columns: 1fr 1fr auto; }
  .inv-cand { flex-direction: column; align-items: flex-start; gap: 3px; }
  .inv-cand-meta { justify-content: flex-start; }
}

/* "Used for" picker inside the casting editor: one row per class, tick the
   blade counts it is used for, pick the bore it draws on. */
.lk-filter { width: 100%; margin-bottom: 6px; }
.lk-grid {
  max-height: 260px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 8px; padding: 4px;
}
.lk-row {
  display: grid; grid-template-columns: 1fr auto auto;
  align-items: center; gap: 8px; padding: 3px 6px; border-radius: 6px;
}
/* Same trap as .psel-row: the grid above outranks the browser's
   `[hidden] { display: none }`, so the filter box in this modal set .hidden
   and nothing moved. Found 2026-09-27 while fixing the print picker. */
.lk-row[hidden] { display: none; }
.lk-row:hover { background: rgba(128,128,128,.10); }
.lk-row.on { background: rgba(61,170,107,.10); }
.lk-class { font-size: 12.5px; font-weight: 600; }
.lk-boxes { display: flex; gap: 4px; }
.lk-box {
  display: inline-flex; align-items: center; gap: 4px; cursor: pointer;
  font-size: 11px; padding: 2px 7px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--bg-card); user-select: none;
}
.lk-box input { margin: 0; }
.lk-box.on { border-color: rgba(61,170,107,.55); background: rgba(61,170,107,.18); color: var(--green); }
.lk-bore { font-size: 11px; padding: 2px 4px; min-width: 88px; }

/* Per-bore entry inside the casting editor. */
.bore-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; }
.bore-cell { display: flex; flex-direction: column; gap: 3px; }
.bore-cell > span { font-size: 11px; opacity: .7; }
.bore-cell input { width: 100%; }

@media (max-width: 720px) {
  .stock-row { grid-template-columns: 1fr auto; row-gap: 4px; }
  .stock-specs { grid-column: 1 / -1; }
  .stock-actions { opacity: 1; }
}

/* Design B zones inside the expanded detail */
.zone-b {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  background: rgba(0,0,0,.25);
  border-radius: 8px;
  padding: 6px;
}
.stat-cell {
  flex: 1 1 90px;
  min-width: 80px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  text-align: center;
}
.stat-cell.stat-price {
  background: rgba(61,170,107,.15);
  border-color: rgba(61,170,107,.4);
}
.stat-cell.stat-price .stat-value { color: var(--green); }
.stat-label {
  font-size: 9px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 1px; font-weight: 600;
  margin-bottom: 2px;
}
.stat-value {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 600; font-size: 17px;
  color: var(--text);
  letter-spacing: .5px;
}

.zone-c {
  display: flex; flex-wrap: wrap;
  gap: 4px 14px;
  padding: 6px 4px;
  font-size: 12px;
  color: var(--text-muted);
}
.meta-item { white-space: nowrap; }
.meta-label { color: var(--text-dim); text-transform: uppercase; font-size: 9px; letter-spacing: 1px; }
.meta-item strong { color: var(--text); font-weight: 600; margin-left: 4px; }

/* Status button strip */
.status-strip {
  display: flex; gap: 4px;
  flex-wrap: wrap;
}
.status-btn {
  border: 1.5px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  border-radius: 6px;
  padding: 6px 10px;
  font: 600 10px 'DM Sans',sans-serif;
  letter-spacing: .8px; text-transform: uppercase;
  cursor: pointer; transition: .12s;
}
.status-btn:hover { border-color: var(--border-strong); color: var(--text); }
.status-btn.s-inprogress.active { background: #E65100; border-color: #E65100; color: #fff; }
.status-btn.s-done.active       { background: #2E7D32; border-color: #2E7D32; color: #fff; }
.status-btn.s-ready.active      { background: #3949AB; border-color: #3949AB; color: #fff; }
.status-btn.s-shipped.active    { background: #1565C0; border-color: #1565C0; color: #fff; }
.status-btn.s-sendclient.active { background: #1a6c7a; border-color: #1a6c7a; color: #fff; }
.status-btn.s-sendacct.active   { background: #5e35b1; border-color: #5e35b1; color: #fff; }

/* Half / Full toggle */
.ht-toggle { display: flex; gap: 0; }
.ht-btn {
  border: 1.5px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  padding: 6px 10px;
  font: 600 10px 'DM Sans',sans-serif;
  letter-spacing: .8px;
  cursor: pointer; transition: .12s;
}
.ht-btn:first-child { border-radius: 6px 0 0 6px; border-right-width: 0; }
.ht-btn:last-child  { border-radius: 0 6px 6px 0; }
.ht-btn:hover { color: var(--text); }
.ht-btn.active {
  background: var(--accent); border-color: var(--accent); color: var(--text);
}

/* Worker "Mark Done" prominent button */
.btn-mark-done {
  background: var(--green); color: #fff;
  border: none; border-radius: 6px;
  padding: 7px 14px;
  font: 700 11px 'DM Sans',sans-serif;
  letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer; transition: .12s;
}
.btn-mark-done:hover { background: #4ABF7B; }

/* ── It rains money when a propeller is finished ──────────────────────
   Erik, 2026-09-29. Pure decoration: nothing here may catch a click or
   affect layout, so the layer is fixed, full-screen and transparent to
   the pointer, and it deletes itself when the last note lands. */
.cash-rain {
  position: fixed; inset: 0; z-index: 9000;
  pointer-events: none; overflow: hidden;
}
.cash-note {
  position: absolute; top: -12vh;
  width: 54px; height: 30px;
  animation: cash-fall var(--dur) cubic-bezier(.35,.05,.6,1) var(--delay) both;
  will-change: transform;
}
/* The note itself. A euro-green bill with a lighter panel and a rule top and
   bottom — enough to read as money at the size it falls past. */
.cash-face {
  display: grid; place-items: center;
  width: 100%; height: 100%;
  border-radius: 3px;
  font: 700 15px/1 'DM Sans', sans-serif; font-style: normal;
  color: rgba(255,255,255,.92);
  background:
    linear-gradient(90deg, rgba(255,255,255,.22) 0 4px, transparent 4px calc(100% - 4px), rgba(255,255,255,.22) calc(100% - 4px) 100%),
    linear-gradient(180deg, #7fc98f 0%, #4f9f68 45%, #3d8a57 100%);
  box-shadow: 0 1px 3px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.28);
  animation: cash-flip var(--dur) linear var(--delay) both;
  will-change: transform;
}
/* Falls and drifts sideways; the flip is on the child so the two motions do
   not have to share one transform. */
@keyframes cash-fall {
  from { transform: translate3d(0, 0, 0) rotate(var(--tilt)) scale(var(--scale, 1)); opacity: 0; }
  8%   { opacity: 1; }
  85%  { opacity: 1; }
  to   { transform: translate3d(var(--drift), 118vh, 0) rotate(var(--tilt)) scale(var(--scale, 1)); opacity: 0; }
}
@keyframes cash-flip {
  from { transform: rotate3d(1, .35, 0, 0deg); }
  to   { transform: rotate3d(1, .35, 0, var(--spin)); }
}
/* Asked for less movement: the shower is skipped in JS as well, this is the
   belt to that pair of braces. */
@media (prefers-reduced-motion: reduce) {
  .cash-rain { display: none; }
}

/* Order row — clickable, expandable */
.row.order-row,
.row.hours-row,
.row.event-row,
.row.client-row,
.row.wp-row.admin { cursor: pointer; }
.row.hours-row:hover,
.row.event-row:hover,
.row.client-row:hover,
.row.wp-row.admin:hover { border-color: var(--border-strong); }
.row.client-row.expanded {
  border-color: var(--accent);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  background: rgba(26,108,122,.08);
}
.row.row-past { opacity: .55; }
.row.order-row.expanded {
  border-color: var(--accent);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  background: rgba(26,108,122,.08);
}
.row-detail {
  background: var(--bg-mid);
  border: 1px solid var(--accent);
  border-top: none;
  border-radius: 0 0 8px 8px;
  padding: 14px 18px 16px;
  margin-top: -7px;
  margin-bottom: 8px;
  display: flex; flex-direction: column; gap: 12px;
}
.row-detail-info {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px 18px;
}
.info-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.info-label {
  font-size: 9px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 1.2px; font-weight: 600;
}
.info-value {
  font-size: 13px; color: var(--text);
  font-family: 'DM Mono', monospace;
  word-break: break-word;
}
.row-detail-pitches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(56px, 1fr));
  gap: 5px;
  background: rgba(0,0,0,.3);
  border-radius: 8px;
  padding: 10px;
}
.pitch-cell {
  display: flex; flex-direction: column; align-items: center;
  padding: 6px 4px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.pitch-cell.empty { opacity: .35; }
.pitch-label { font-size: 9px; color: var(--text-dim); font-weight: 700; letter-spacing: .5px; }
.pitch-value { font-family: 'DM Mono',monospace; font-size: 11px; color: var(--text); margin-top: 2px; }
.info-block {
  background: rgba(255,255,255,.04);
  border-left: 3px solid var(--border);
  padding: 9px 12px;
  border-radius: 4px;
  font-size: 13px;
  color: var(--text);
}
.info-block.notes-prod { border-left-color: var(--gold); background: rgba(201,168,76,.08); }
.info-block.notes-fb   { border-left-color: var(--accent); background: rgba(26,108,122,.08); }
.info-block .info-label { margin-bottom: 4px; }
.info-block .info-block-body { line-height: 1.5; white-space: pre-wrap; }

/* Pricing table */
.pr-table {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.pr-row {
  display: grid;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
/* Per-worker total, in the group header now that the KPI strip below it is
   gone. Matters when an admin is looking at several workers at once. */
.wp-worker-total {
  margin-left: 10px; padding: 3px 10px; border-radius: var(--r-pill, 999px);
  font-size: 12.5px; font-weight: 700;
  background: rgba(26, 108, 122, .18); color: var(--accent, #4bb3c2);
}

/* ── Square image cropper ───────────────────────────────────────────────
   Opened FROM inside the product editor, so it has to outrank it. `.modal`
   and `.login-screen` both sit at z-index 1000; 400 put the cropper
   underneath the very modal that launched it. 2000 leaves headroom above
   both without starting a z-index arms race. */
.crop-overlay {
  position: fixed; inset: 0; z-index: 2000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, .78); padding: 16px;
  padding-top: calc(16px + env(safe-area-inset-top, 0px));
  padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
}
.crop-card {
  background: var(--panel, #1b1f21); border: 1px solid var(--line, #2b302f);
  border-radius: 12px; width: 100%; max-width: 420px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .7); overflow: hidden;
}
.crop-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--line, #2b302f);
  font-size: 12.5px; color: var(--muted, #9aa39c);
}
.crop-x {
  background: none; border: 0; color: var(--muted, #9aa39c);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 0 4px;
}
.crop-x:hover { color: var(--text, #eef1ee); }
.crop-stage { position: relative; display: flex; justify-content: center; padding: 16px; }
.crop-canvas {
  width: 360px; height: 360px; max-width: 100%; aspect-ratio: 1/1;
  display: block; border-radius: 6px; cursor: grab; touch-action: none;
}
.crop-canvas:active { cursor: grabbing; }
/* Frame echoing the product card's 1:1 box, so what you see is what ships. */
.crop-mask {
  position: absolute; inset: 16px; pointer-events: none;
  border: 2px solid rgba(255, 255, 255, .85); border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .5) inset;
}
.crop-tools { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 12px; }
.crop-zoom {
  display: flex; align-items: center; gap: 10px;
  font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--muted, #9aa39c);
}
.crop-zoom input { flex: 1; accent-color: var(--accent, #1a6c7a); }
.crop-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }

/* Order modal — is this client already on file?
   green = matched an existing client (the order will attach to them)
   blue  = no match, a new name that will save as free text
   Tinted background rather than only a border, so it reads at a glance while
   typing. Colour is not the only signal: the reseller tag and the serial hint
   next to the field both change too. */
#om-clientName.client-known {
  background: rgba(60, 170, 110, .14);
  border-color: rgba(60, 170, 110, .55);
}
#om-clientName.client-new {
  background: rgba(70, 140, 220, .14);
  border-color: rgba(70, 140, 220, .55);
}
#om-clientName.client-known:focus { border-color: rgba(60, 170, 110, .9); }
#om-clientName.client-new:focus   { border-color: rgba(70, 140, 220, .9); }

/* The word next to the label, carrying the same meaning as the field colour
   so it does not depend on colour vision alone. Reseller keeps the gold it
   already used, since that status outranks known/new. */
.om-client-badge {
  display: inline-block; margin-left: 6px;
  font-size: 9.5px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--r-pill, 999px); vertical-align: middle;
}
.om-client-badge.is-known    { background: rgba(60, 170, 110, .18); color: #4fbf8b; }
.om-client-badge.is-new      { background: rgba(70, 140, 220, .18); color: #6ba6e8; }
.om-client-badge.is-reseller { background: rgba(201, 168, 76, .18); color: #c9a84c; }

/* ── "Who is this order for?" client picker ─────────────────────────── */
.pick-buyer {
  padding: 12px 14px; border-bottom: 1px solid var(--line, #2b302f);
  background: rgba(255, 255, 255, .02);
}
.pick-buyer-name { font-size: 14px; font-weight: 600; color: var(--text, #eef1ee); }
.pick-buyer-meta { font-size: 11.5px; color: var(--muted, #9aa39c); margin-top: 3px; }
.pick-body { padding: 12px 14px; max-height: 46vh; overflow-y: auto; }
.pick-label {
  font-size: 10.5px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--muted, #9aa39c); margin-bottom: 6px;
}
.pick-row {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  width: 100%; text-align: left; cursor: pointer;
  padding: 9px 11px; margin-bottom: 5px;
  background: var(--panel, #1b1f21); border: 1px solid var(--line, #2b302f);
  border-radius: 7px; color: var(--text, #eef1ee); font: inherit;
}
.pick-row:hover { border-color: var(--accent, #1a6c7a); }

/* Checkout details against the client card. One row per field, old on the left
   and new on the right, so the difference is the thing the eye lands on rather
   than something to be worked out from two paragraphs. */
.cc-rows { display: flex; flex-direction: column; gap: 5px; }
.cc-row {
  display: grid;
  grid-template-columns: 18px minmax(96px, 1.1fr) minmax(0, 1fr) 14px minmax(0, 1fr);
  align-items: center; gap: 9px;
  padding: 8px 11px; border-radius: 7px; cursor: pointer;
  background: var(--panel, #1b1f21); border: 1px solid var(--line, #2b302f);
}
.cc-row input { accent-color: var(--accent, #1a6c7a); cursor: pointer; margin: 0; }
.cc-label { font-size: 12.5px; font-weight: 600; display: flex; flex-direction: column; gap: 1px; }
.cc-state { font-size: 10px; font-weight: 400; color: var(--muted, #9aa39c); letter-spacing: .04em; }
.cc-old, .cc-new {
  font-family: 'DM Mono', ui-monospace, monospace; font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cc-old   { color: var(--muted, #9aa39c); }
.cc-new   { color: var(--text, #eef1ee); }
.cc-arrow { color: var(--muted, #9aa39c); font-size: 11px; text-align: center; }
/* A real disagreement is the one worth looking at; a blank field being filled
   in for the first time is routine, and a value the checkout did not mention
   is not a change at all. */
.cc-row.cc-differs      { border-color: rgba(201,168,76,.45); }
.cc-row.cc-missing      { border-color: rgba(61,170,107,.35); }
.cc-row.cc-only_on_file { opacity: .55; cursor: default; }
.cc-same { margin-top: 9px; font-size: 11.5px; color: var(--muted, #9aa39c); }
@media (max-width: 560px) {
  .cc-row { grid-template-columns: 18px 1fr; row-gap: 3px; }
  .cc-old, .cc-arrow, .cc-new { grid-column: 2; }
  .cc-arrow { display: none; }
  .cc-old::before { content: 'kaardil: '; color: var(--muted, #9aa39c); }
  .cc-new::before { content: 'kassast: '; color: var(--muted, #9aa39c); }
}
.pick-name { font-size: 13.5px; font-weight: 600; }
.pick-meta { font-size: 11.5px; color: var(--muted, #9aa39c); }
/* Why this row was suggested — e-mail match is a far stronger signal than
   a name match, so the reason travels with the suggestion. */
.pick-why {
  margin-left: auto; font-size: 10px; letter-spacing: .5px; text-transform: uppercase;
  padding: 2px 8px; border-radius: var(--r-pill, 999px);
  background: rgba(26, 108, 122, .22); color: var(--accent, #4bb3c2);
}

/* A card whose controls are deliberately switched off (the demo account's
   PIN form). Dimmed, but still readable, so the feature is visibly present. */
.card.is-locked { opacity: .68; }
.card.is-locked input, .card.is-locked button { cursor: not-allowed; }

/* ── Täna ──────────────────────────────────────────────────────────────
   One screen, three blocks, in the order they demand attention. Every row
   carries the action that moves it forward, so nothing sends you elsewhere. */
.tday-blk { margin-bottom: 20px; }
.tday-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.tday-title { font: 700 11px/1 'DM Sans',sans-serif; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--accent); }
.tday-note { font-size: 11px; color: var(--text-dim); }

.tday-item { padding: 11px 12px; border-bottom: 1px solid var(--border); }
.tday-item:last-child { border-bottom: none; }
.tday-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.tday-who { font-weight: 650; font-size: 14px; }
.tday-when { margin-left: auto; font-size: 11px; color: var(--text-dim); white-space: nowrap; }
.tday-msg { color: var(--text-muted); font-size: 13px; margin: 4px 0 7px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tday-ctx { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }
.tday-ctx .chip, .tday-top .chip {
  font-size: 10.5px; padding: 2px 7px; border-radius: 5px; white-space: nowrap;
  background: rgba(128,128,128,.16); color: var(--text-muted); }
.tday-ctx .chip.spd { background: rgba(26,108,122,.24); color: #7fd0dd; font-weight: 700; }
.tday-top .chip.new, .tday-ctx .chip.new { background: rgba(201,168,76,.24); color: var(--gold); font-weight: 700; }
/* Where a prop stands, in the workshop's words. Ready is the one that wants
   acting on — it is only a parcel away — so it is the one that carries colour. */
.tday-ctx .chip.wrk  { background: rgba(128,128,128,.2); color: var(--text); }
.tday-ctx .chip.rdy  { background: rgba(61,170,107,.22); color: #6fd39b; font-weight: 700; }
.tday-ctx .chip.late { background: rgba(212,74,46,.22); color: #f0917c; font-weight: 700; }
.tday-ctx .chip.miss { background: rgba(212,74,46,.14); color: #e8a898; }
.tday-ctx .chip.pay  { background: rgba(201,168,76,.18); color: var(--gold); font-weight: 700; }
/* Money that has arrived. Green against the gold of money still owed, so the
   two read as opposite answers to one question rather than two notices. */
.tday-ctx .chip.paid { background: rgba(61,170,107,.20); color: #6fd39b; font-weight: 700; }
:root[data-theme="medium"] .tday-ctx .chip.paid,
:root[data-theme="light"]  .tday-ctx .chip.paid { background: rgba(61,170,107,.22) !important; color: #1a5a3a; }

/* Money in the action row: what comes in, what goes out. Sized to sit level
   with the status buttons rather than shout over them. */
.price-pill { font: 650 13px/1 inherit; padding: 7px 11px; border-radius: 7px;
  white-space: nowrap; align-self: center; }
.price-pill.p-in  { background: rgba(61,170,107,.18); color: #6fd39b; }
.price-pill.p-out { background: rgba(212,74,46,.16);  color: #f0917c; }
:root[data-theme="medium"] .price-pill.p-in,
:root[data-theme="light"]  .price-pill.p-in  { background: rgba(61,170,107,.20) !important; color: #1a5a3a; }
:root[data-theme="medium"] .price-pill.p-out,
:root[data-theme="light"]  .price-pill.p-out { background: rgba(212,74,46,.16) !important; color: #8a2a18; }
/* No worker rate on file. Amber, dashed and carrying a "?" — it has to read as
   a question nobody has answered, not as a figure and not as nothing. */
.price-pill.p-none {
  background: rgba(214,138,42,.12); color: #e7b168;
  border: 1px dashed rgba(214,138,42,.50); cursor: help;
}
:root[data-theme="medium"] .price-pill.p-none,
:root[data-theme="light"]  .price-pill.p-none { background: rgba(214,138,42,.16) !important; color: #7a4a06; }

/* Has LAK been paid. The same two colours wherever the answer is shown — as a
   price-pill beside the status strip, as a row-chip on a prop card — so it is
   one fact with one look and not a new badge to learn per page. */
.paid-yes  { background: rgba(61,170,107,.20); color: #6fd39b; font-weight: 700; }
.paid-wait { background: rgba(201,168,76,.18); color: var(--gold); font-weight: 700; }
:root[data-theme="medium"] .paid-yes,
:root[data-theme="light"]  .paid-yes  { background: rgba(61,170,107,.22) !important; color: #1a5a3a; }
:root[data-theme="medium"] .paid-wait,
:root[data-theme="light"]  .paid-wait { background: rgba(201,168,76,.22) !important; color: #6b5310; }

/* The repair description, written where the job is looked at. */
.job-note { padding: 10px 12px; }
.job-note-label { font: 700 9.5px/1 'DM Sans', sans-serif; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px; }
.job-note-box { width: 100%; min-height: 76px; resize: vertical; font: inherit;
  font-size: 13px; line-height: 1.5; padding: 9px 11px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text); }
.job-note-box:focus { outline: none; border-color: var(--accent); }

/* Money on an order card, on its own line rather than mixed in among the
   averages. What comes in and what goes out read differently on purpose. */
.row-money { display: flex; flex-wrap: wrap; gap: 8px; padding: 9px 12px;
  border-top: 1px solid var(--border); }
.rm-cell { display: flex; align-items: baseline; gap: 7px; padding: 5px 10px;
  border-radius: 7px; background: rgba(128,128,128,.10); }
.rm-label { font: 700 9.5px/1 'DM Sans', sans-serif; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--text-dim); }
.rm-value { font-size: 15px; font-weight: 650; color: var(--text); }
.rm-cell.m-sell .rm-value { color: #6fd39b; }
.rm-cell.m-cost .rm-value { color: var(--gold); }
:root[data-theme="medium"] .rm-cell, :root[data-theme="light"] .rm-cell {
  background: rgba(0,0,0,.05); }
:root[data-theme="medium"] .rm-cell.m-sell .rm-value,
:root[data-theme="light"]  .rm-cell.m-sell .rm-value { color: #1a5a3a; }
:root[data-theme="medium"] .rm-cell.m-cost .rm-value,
:root[data-theme="light"]  .rm-cell.m-cost .rm-value { color: #6b5313; }

/* Whose bench a prop is on. Unclaimed is the one worth spotting across a long
   list, so it is the one that carries colour. Defined for every theme,
   because the other two are not just the dark one with different paint. */
.assign-chip { font-weight: 600; }
.assign-chip.free  { background: rgba(201,168,76,.22); color: var(--gold); }
.assign-chip.mine  { background: rgba(26,108,122,.24); color: #7fd0dd; }
.assign-chip.taken { background: rgba(128,128,128,.18); color: var(--text-muted); }
:root[data-theme="medium"] .assign-chip.free,
:root[data-theme="light"]  .assign-chip.free  { background: rgba(201,168,76,.28) !important; color: #6b5313; }
:root[data-theme="medium"] .assign-chip.mine,
:root[data-theme="light"]  .assign-chip.mine  { background: rgba(26,108,122,.16) !important; color: #12525d; }
:root[data-theme="medium"] .assign-chip.taken,
:root[data-theme="light"]  .assign-chip.taken { background: rgba(0,0,0,.07) !important; color: rgba(20,25,30,.72); }
.tday-ctx .chip.off  { background: rgba(255,255,255,.05); color: var(--text-dim);
  border: 1px dashed var(--border); }

/* Two things worth having to hand while writing back: what he has already
   built for this person, and what has already been said to them. Both stay
   folded until asked for — the reply box is what the window is for. */
.thr-tools { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 10px; }
.thr-tools .btn-ghost.is-on { border-color: var(--gold); color: var(--gold); }
.btn-ghost.is-on { border-color: var(--gold); color: var(--gold); }

.thr-props { border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  margin-bottom: 11px; font-size: 12.5px; }
.thr-props-head, .thr-props-row {
  display: grid; grid-template-columns: minmax(0,1.6fr) 44px 58px 60px 52px minmax(0,72px);
  gap: 8px; align-items: center; padding: 6px 10px; }
.thr-props-head { font: 700 10px/1 'DM Sans', sans-serif; letter-spacing: .9px;
  text-transform: uppercase; color: var(--text-dim);
  background: rgba(128,128,128,.08); border-bottom: 1px solid var(--border); }
/* Each prop is a <details>: the browser keeps the open/closed state, so there
   is no handler that can fail to bind. The default disclosure triangle is
   replaced by a chevron drawn at the end of the row, where there is space. */
.thr-prop-item { border-bottom: 1px solid var(--border); }
.thr-prop-item:last-child { border-bottom: none; }
.thr-props-row { cursor: pointer; list-style: none; position: relative;
  padding-right: 22px; }
.thr-props-row::-webkit-details-marker { display: none; }
.thr-props-row::marker { content: ''; }
.thr-props-row::after { content: '⌄'; position: absolute; right: 8px; top: 3px;
  color: var(--text-dim); font-size: 13px; line-height: 1; transition: transform .12s; }
.thr-props-row:hover { background: rgba(255,255,255,.04); }
.thr-props-row:hover::after { color: var(--text); }
details[open] > .thr-props-row { background: rgba(201,168,76,.08); }
details[open] > .thr-props-row::after { transform: rotate(180deg); }
details[open] > .thr-props-row .thr-props-id b { color: var(--gold); }

/* One prop, radius by radius. Indented under its own row so it is obvious
   which propeller the numbers belong to. */
.thr-props-det { background: rgba(0,0,0,.18); }
.thr-rad { padding: 7px 10px 8px 22px; }
.thr-rad-head, .thr-rad-row {
  display: grid; grid-template-columns: 62px 64px 48px minmax(0,1fr);
  gap: 8px; align-items: center; padding: 3px 0; font-size: 12px; }
.thr-rad-head { font: 700 9.5px/1 'DM Sans', sans-serif; letter-spacing: .9px;
  text-transform: uppercase; color: var(--text-dim); padding-bottom: 5px; }
.thr-rad-r { color: var(--text-muted); }
.thr-rad-raw { color: var(--text-dim); font-size: 11px; }
.thr-rad-foot { margin-top: 7px; padding-top: 6px; border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-dim); }
.thr-props-id { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thr-props-id b { color: var(--text); font-weight: 600; }
.thr-props-id span { color: var(--text-muted); margin-left: 6px; }
.thr-props-st { color: var(--text-dim); font-size: 11px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 560px) {
  .thr-props-head, .thr-props-row { grid-template-columns: minmax(0,1.4fr) 38px 52px 48px 44px; }
  .thr-props-st { display: none; }
}

/* Other conversations with the same person, listed under this one inside the
   same fold — one place for "what has been said", not two. */
.thr-prev { border-top: 1px solid var(--border); }
.thr-prev-head { font: 700 9.5px/1 'DM Sans', sans-serif; letter-spacing: 1.1px;
  text-transform: uppercase; color: var(--text-dim); padding: 9px 9px 0; }
.thr-prev-list { display: flex; flex-direction: column; gap: 5px; padding: 8px 9px 9px; }
.thr-prev-row { display: flex; flex-direction: column; gap: 3px; text-align: left;
  padding: 8px 11px; border-radius: 7px; cursor: pointer; font-family: inherit;
  border: 1px solid var(--border); background: transparent; color: var(--text); }
.thr-prev-row:hover { border-color: var(--border-strong); background: rgba(255,255,255,.03); }
.thr-prev-top { display: flex; align-items: baseline; gap: 7px; font-size: 12.5px; }
.thr-prev-when { margin-left: auto; color: var(--text-dim); font-size: 11px; white-space: nowrap; }
.thr-prev-snip { color: var(--text-muted); font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Where a reply will actually land, when the thread arrived second-hand. */
.thr-via { font-size: 12.5px; color: var(--text-muted); margin: 0 0 10px;
  padding: 8px 11px; border-radius: 0 7px 7px 0;
  background: rgba(26,108,122,.10); border-left: 2px solid var(--accent); }
.thr-via b { color: var(--text); }

/* Whether this conversation is tied to a record in the database, said at the
   top where it is read before anything is written. Half the actions underneath
   need a linked client, and the only sign used to be that they were greyed. */
.thr-link { display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 7px 11px; border-radius: 7px; font-size: 12.5px;
  background: var(--bg-soft, rgba(127,127,127,.07)); border: 1px solid var(--border); }
.thr-link.is-on { background: rgba(61,170,107,.09); border-color: rgba(61,170,107,.30); }
.thr-link b { color: var(--text); }
.thr-link-badge { font: 700 10px/1 'DM Sans', sans-serif; letter-spacing: 1.1px;
  text-transform: uppercase; padding: 4px 7px; border-radius: 4px;
  background: rgba(61,170,107,.20); color: #6fd39b; white-space: nowrap; }
.thr-link-badge.off { background: rgba(214,138,42,.16); color: #e7b168; }
.thr-link-id { font-size: 11px; color: var(--text-muted); }
/* Pushes the button to the right edge on a wide modal, and lets it fall onto
   its own line on a phone rather than squeezing the name. */
.thr-link #thr-open-client { margin-left: auto; }
/* Unlinked: the hint gives way so the buttons that fix it get the room, and
   the whole bar wraps onto a second line rather than squeezing them. */
.thr-link .om-hint { flex: 1 1 200px; min-width: 0; }
.thr-link .btn-ghost.sm { flex: 0 0 auto; }

/* Controls on a prop row. Small, because the row is a summary that happens to
   be adjustable — not a form. */
.tday-prop-sel, .tday-prop-date {
  font: inherit; font-size: 11.5px; padding: 3px 6px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
  max-width: 100%; }
.tday-prop-sel:hover, .tday-prop-date:hover { border-color: var(--border-strong); }
.tday-prop-date[data-late="1"] { color: #f0917c; border-color: rgba(212,74,46,.45); }
.tday-prop-sel:disabled { opacity: .5; }
/* The action that moves money or a parcel — distinct from the neutral ghosts,
   so the one thing worth doing on this card is the one that stands out. */
.btn-go { background: rgba(61,170,107,.18); border: 1px solid rgba(61,170,107,.55);
  color: #6fd39b; font-weight: 600; border-radius: 7px; cursor: pointer;
  font-family: inherit; }
.btn-go:hover { background: rgba(61,170,107,.28); }
.btn-go[disabled] { opacity: .5; cursor: default; }

/* .tday-threads / .tday-thr styled the per-conversation pills on the case
   card. Removed 2026-09-30 with the markup: the thread window now shows every
   conversation with that person on one timeline, so the card no longer needs
   to list them. */

/* Props folded out of the card. A grid so the columns line up down the list
   and the eye can run straight down the statuses. */
.tday-props { margin: 2px 0 9px; }
.tday-prop-list { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.tday-prop { display: grid; gap: 8px; align-items: center; padding: 7px 10px;
  grid-template-columns: minmax(0,1fr) auto auto auto auto;
  border-bottom: 1px solid var(--border); font-size: 12.5px; }
@media (max-width: 720px) { .tday-prop { grid-template-columns: minmax(0,1fr) auto auto; } }
.tday-prop:last-child { border-bottom: none; }
.tday-prop-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-muted); }
.tday-prop-name b { color: var(--text); font-weight: 600; margin-left: 5px; }
.tday-prop-st { font-size: 11px; padding: 2px 7px; border-radius: 5px; white-space: nowrap;
  background: rgba(128,128,128,.16); color: var(--text-muted); }
.tday-prop-st.st-ready { background: rgba(61,170,107,.22); color: #6fd39b; font-weight: 700; }
.tday-prop-due { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; }
.tday-prop-due.late { color: #f0917c; font-weight: 700; }
/* Invoice state on a prop row is a FACT, not a button — the invoice itself is
   made from the card, for the whole client at once. */
.tday-prop-inv { font-size: 11.5px; white-space: nowrap; color: var(--text-dim); }
.tday-prop-inv.done { color: #6fd39b; font-weight: 600; }
.tday-prop-inv.wait { color: var(--gold); }
.tday-prop-open { font-size: 11.5px; padding: 4px 8px; }
.tday-btn.is-on { border-color: var(--gold); color: var(--gold); }
.tday-btn.q { color: var(--text-muted); }
/* A guess at who this is. Marked, because pressing it changes a record. */
.tday-btn.sug { border-color: rgba(201,168,76,.5); color: var(--gold); }
@media (max-width: 560px) {
  .tday-prop { grid-template-columns: minmax(0,1fr) auto; }
  .tday-prop-date { display: none; }     /* the deadline has its own block */
}
.tday-acts { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.tday-btn { font-size: 12px; padding: 7px 11px; }

/* What the model made of the mail — one line on the card, the whole thing in
   the thread modal. Kept visually distinct from the customer's own words so
   it is never mistaken for something they wrote. */
.tday-ai { display: flex; align-items: baseline; gap: 6px; margin: 0 0 8px;
  font-size: 12.5px; color: var(--text); line-height: 1.4; }
.tday-ai .chip, .thr-ai .chip { font-size: 10.5px; padding: 2px 7px; border-radius: 5px;
  white-space: nowrap; font-weight: 700; flex: none;
  background: rgba(128,128,128,.16); color: var(--text-muted); }
.chip.ord { background: rgba(201,168,76,.24); color: var(--gold); }
.chip.qst { background: rgba(26,108,122,.24); color: #7fd0dd; }
.chip.cmp { background: rgba(190,70,60,.24); color: #e79a92; }
.chip.spm { background: rgba(128,128,128,.14); color: var(--text-muted); }
.chip.draft { background: rgba(26,108,122,.2); color: #7fd0dd; font-size: 10.5px;
  padding: 2px 7px; border-radius: 5px; font-weight: 700; }
/* Machine mail is on the board now, just quietly — loud enough to pick out and
   clear, faint enough not to compete with a customer. */
.chip.auto { background: rgba(128,128,128,.14); color: var(--text-muted); font-size: 10.5px;
  padding: 2px 7px; border-radius: 5px; font-weight: 700; }

.thr-ai { border: 1px solid var(--border); border-left: 3px solid var(--gold);
  border-radius: 8px; padding: 10px 12px; margin-bottom: 12px;
  background: rgba(128,128,128,.06); }
.thr-ai.err { border-left-color: #be463c; color: var(--text-muted); font-size: 13px; }
.thr-ai-head { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.thr-ai-head .btn-ghost { margin-left: auto; }
.btn-ghost.sm { font-size: 11.5px; padding: 5px 9px; }
.thr-ai-sum { font-size: 14px; line-height: 1.45; }
.thr-ai-fields { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 7px;
  font-size: 12.5px; color: var(--text-muted); }
.thr-ai-fields b { color: var(--text); font-weight: 600; }
.thr-ai-notes { margin-top: 7px; font-size: 12.5px; color: var(--text-muted); }
.thr-ai-model { font-size: 10.5px; color: var(--text-dim); margin-left: auto; }
/* What the mail creates besides a reply. Above the letter, because it is the
   part that changes something outside the portal. */
.thr-acts { display: flex; flex-direction: column; gap: 6px; margin-top: 9px; }
.thr-act { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.thr-act-why { font-size: 11.5px; color: var(--text-muted); }
.thr-act-done { font-size: 11px; color: #6fd39b; }
.thr-act button[disabled] { opacity: .45; cursor: not-allowed; }
/* The model dropped the sentence that answers the customer. Loud on purpose:
   the letter around it reads as finished, which is exactly the danger. */
.thr-ai-warn { margin-top: 9px; padding: 8px 11px; border-radius: 6px; font-size: 12.5px;
  background: rgba(214,138,42,.12); border: 1px solid rgba(214,138,42,.42); color: #e7b168; }
.thr-ai-warn b { color: #ffd79a; font-weight: 600; }
.thr-found { margin-top: 9px; padding: 9px 11px; border-radius: 6px;
  background: rgba(61,170,107,.09); border: 1px solid rgba(61,170,107,.28); }
.thr-found-head { font: 700 10.5px/1 'DM Sans', sans-serif; letter-spacing: 1.2px;
  text-transform: uppercase; color: #6fd39b; margin-bottom: 7px; }
.thr-found-row { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px;
  padding: 2px 0; cursor: pointer; }
/* A row that would replace something, rather than fill a blank. Unticked by
   default and marked, because the old value is about to be gone. */
.thr-found-row.over { background: rgba(214,138,42,.09); border-radius: 4px; }
.thr-found-row.over s { color: var(--text-dim); }
.thr-found-k { color: var(--text-muted); flex: 0 0 82px; }
.thr-found-v { color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.thr-found .btn-ghost { margin-top: 7px; }

.thr-ai-draft { margin-top: 9px; }
/* The conversation is already waiting on THEM. The draft is still here, but it
   has to be asked for — a finished letter sitting open invites sending an
   answer that has already gone. */
.thr-answered {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 11px; border-radius: 7px; font-size: 12.5px;
  background: rgba(26,108,122,.10); border: 1px solid rgba(26,108,122,.30);
  color: var(--text-muted);
}
.thr-answered span { flex: 1 1 auto; min-width: 0; }
/* A reading that predates the last message is a different thing from one that
   simply is not his move: amber, because the right action is to read again. */
.thr-answered.is-stale {
  background: rgba(214,138,42,.12); border-color: rgba(214,138,42,.40); color: #e7b168;
}

/* The newest thing this person said is in another subject. Said where he is
   about to type, not buried in the log. */
.thr-elsewhere {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 7px 11px; border-radius: 7px; font-size: 12.5px;
  background: rgba(214,138,42,.10); border: 1px solid rgba(214,138,42,.32);
  color: var(--text-muted);
}
.thr-elsewhere b { color: var(--text); }
.thr-elsewhere span { flex: 1 1 auto; min-width: 0; }
.thr-ai-draft-body { white-space: pre-wrap; font-size: 13px; line-height: 1.5;
  margin: 8px 0; padding: 9px 11px; border-radius: 6px;
  background: var(--bg); border: 1px solid var(--border); }
/* The parts that change when he picks differently. Marked so it is obvious
   which sentences are choices and which are simply the letter. */
.thr-ai-draft-body mark.slot { background: rgba(201,168,76,.18); color: inherit;
  border-bottom: 1px solid rgba(201,168,76,.5); border-radius: 2px; padding: 0 1px; }

/* The draft is now an editable letter whose choices live inside it — the block
   of option buttons underneath is gone, because the eye had to travel from the
   sentence to the buttons and back for every decision.

   `.dslot`, not `.slot` or `.sw`: app.css already owns `.sw` (the test
   logbook's stopwatch), and a mockup that reused that name inherited its card
   border and flex layout before anyone noticed. */
.thr-ai-draft-body[contenteditable] { cursor: text; min-height: 120px; }
.thr-ai-draft-body[contenteditable]:focus { outline: none; border-color: var(--accent); }
/* This box is also the one used when the AI wrote nothing, so it has to say
   what it is when empty. */
.thr-ai-draft-body[contenteditable]:empty::before { content: 'Kirjuta vastus…';
  color: var(--text-dim); pointer-events: none; }

.dslot { position: relative; display: inline-block; cursor: grab;
  background: rgba(201,168,76,.18); border-bottom: 1px solid rgba(201,168,76,.5);
  border-radius: 3px; padding: 1px 16px; margin: 0 1px;
  user-select: none; -webkit-user-select: none;
  /* pan-y so the modal still scrolls vertically under a finger. */
  touch-action: pan-y; transition: background .12s; }
.dslot:hover { background: rgba(201,168,76,.28); }
.dslot.dragging { cursor: grabbing; background: rgba(201,168,76,.34); }
.dslot::before, .dslot::after { position: absolute; top: 50%; transform: translateY(-50%);
  font-size: 10px; line-height: 1; color: var(--gold); opacity: .55; pointer-events: none; }
.dslot::before { content: '‹'; left: 5px; }
.dslot::after  { content: '›'; right: 5px; }
.dslot-t { display: inline-block; will-change: transform, opacity; }
/* Only while settling — during the drag the text tracks the finger with no
   easing at all, or it feels like rubber. */
.dslot-t.anim { transition: transform .16s cubic-bezier(.3,0,.2,1), opacity .16s linear; }
.dslot-n { display: inline-block; margin-left: 6px; font-size: 9px;
  font-family: 'DM Mono', monospace; color: var(--gold); opacity: .75; }
/* Settled: no longer a widget, just words in the letter. */
.dslot-done { animation: dslotset .5s ease-out; border-radius: 2px; }
@keyframes dslotset {
  0%   { background: rgba(61,170,107,.40); }
  100% { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .dslot-t, .dslot-t.anim { transition: none !important; }
  .dslot-done { animation: none; }
}
.thr-draft-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
/* Stock sentences, folded away until wanted. */
.thr-phr { position: relative; }
.thr-phr > summary { list-style: none; cursor: pointer; display: inline-block; }
.thr-phr > summary::-webkit-details-marker { display: none; }
.thr-phr-list { position: absolute; z-index: 5; top: calc(100% + 4px); left: 0;
  min-width: 230px; display: flex; flex-direction: column; gap: 1px; padding: 4px;
  border-radius: 6px; background: var(--bg-mid); border: 1px solid var(--border-strong);
  box-shadow: 0 10px 26px rgba(0,0,0,.34); }
.thr-phr-b { text-align: left; font-size: 12.5px; padding: 7px 9px; border: 0; border-radius: 4px;
  background: transparent; color: var(--text); cursor: pointer; }
.thr-phr-b:hover:not([disabled]) { background: rgba(201,168,76,.16); color: var(--gold); }
.thr-phr-b[disabled] { opacity: .4; cursor: not-allowed; }
.thr-phr-d { color: var(--text-dim); font-size: 11px; }
.thr-draft-left { font-size: 11px; color: var(--text-dim); }
.thr-draft-hint { font-size: 11px; color: var(--text-dim); margin-top: 6px; }

.thr-wiz { display: flex; flex-direction: column; gap: 10px; margin: 10px 0 9px;
  padding: 10px 11px; border-radius: 6px; background: rgba(128,128,128,.07); }
.thr-wiz-ask { font-size: 12.5px; color: var(--text-muted); margin-bottom: 5px; }
.thr-wiz-opts { display: flex; flex-wrap: wrap; gap: 5px; }
.wopt { font-size: 12px; padding: 5px 10px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
  font-family: inherit; line-height: 1.3; text-align: left; }
.wopt:hover { border-color: var(--gold); }
.wopt.is-on { border-color: var(--gold); background: rgba(201,168,76,.16);
  color: var(--gold); font-weight: 600; }
.wopt-free { font-style: italic; color: var(--text-muted); }
.thr-wiz-free { margin-top: 6px; width: 100%; font-family: inherit; font-size: 12.5px;
  padding: 7px 9px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--bg); color: var(--text); resize: vertical; }

.tday-due { display: flex; align-items: center; gap: 9px; padding: 8px 12px;
  border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.tday-due:last-child { border-bottom: none; }
.tday-flag { flex: 0 0 66px; font: 700 10px/1 'DM Sans'; letter-spacing: .5px; text-transform: uppercase; }
.tday-flag.late { color: var(--red); }
.tday-flag.soon { color: var(--gold); }
.tday-flag.none { color: var(--text-dim); }
.tday-due-who { flex: 1 1 130px; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 13px; }
.tday-due-what { flex: 0 0 auto; font-size: 11.5px; color: var(--text-muted); }
.tday-due-status { flex: 0 0 auto; font-size: 11px; color: var(--text-dim); }
.tday-due-date { flex: 0 0 auto; background: var(--bg-mid); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text); font-size: 12px; padding: 4px 7px; }

.tday-quiet { display: flex; align-items: center; gap: 9px; padding: 10px 12px;
  border-bottom: 1px solid var(--border); font-size: 13px; }
.tday-quiet:last-child { border-bottom: none; }
.tday-quiet-why { color: var(--text-dim); font-size: 11.5px; margin-left: auto; }

/* The conversation inside the thread modal. */
/* The conversation flows at full height. It used to be capped at 320px with
   its own scrollbar, which put a scroll area inside the modal's own scroll
   area — a narrow slit onto a long forwarded chain. One scrollbar is enough. */
/* Folded by default: the summary and the draft are what he reads first, and
   the conversation is what he refers back to. One press opens it. */
/* flex-shrink:0 is load-bearing: #modal-body is a column flex container, and
   `overflow: hidden` here sets this item's automatic minimum size to 0 — so
   the flex layout squashed the whole fold, summary included, to its 2px of
   border. It rendered as a bare line, not as a missing element. */
.thr-log-wrap { border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  flex-shrink: 0; }
/* display:block is deliberate: a <summary> defaults to display:list-item, and
   a stray `list-style` or marker rule elsewhere can collapse it to nothing —
   which is exactly how this fold once rendered as a bare 1px line. */
.thr-log-wrap > summary { display: block; cursor: pointer; padding: 9px 11px;
  font: 600 12.5px/1.3 inherit; color: var(--text); list-style: none;
  background: rgba(128,128,128,.10); min-height: 18px; }
.thr-log-wrap > summary::-webkit-details-marker { display: none; }
.thr-log-wrap > summary::marker { content: ''; }
.thr-log-wrap > summary::after { content: ' ⌄'; color: var(--text-dim); }
.thr-log-wrap[open] > summary { color: var(--text); border-bottom: 1px solid var(--border); }
.thr-log-wrap[open] > summary::after { content: ' ⌃'; }
/* Read as a conversation: the customer down the left, Erik down the right,
   in the order it happened. They used to be full-width blocks separated only
   by a faint tint, so telling who said what meant reading the small grey name
   on every one. Erik, 2026-09-27. The markup already carried .in / .out — this
   is only where they sit. */
.thr-log { display: flex; flex-direction: column; gap: 8px;
  background: rgba(0,0,0,.25); border-radius: 8px; padding: 9px; }
/* 25% black is a recessed tray on the dark theme and a heavy grey slab on the
   other two, where the bubbles are white. Same idea, lighter hand. */
:root[data-theme="medium"] .thr-log,
:root[data-theme="light"]  .thr-log { background: rgba(0,0,0,.05); }
.thr-msg { border-radius: 10px; padding: 8px 10px; background: var(--bg-mid);
  max-width: 84%; border: 1px solid var(--border); }
.thr-msg.in  { align-self: flex-start; border-bottom-left-radius: 3px; }
.thr-msg.out { align-self: flex-end;   border-bottom-right-radius: 3px;
  background: rgba(26,108,122,.16); border-color: rgba(26,108,122,.34); }
/* The line the forwarder wrote above the chain — usually a signature. It
   belongs to neither side, so it sits in the middle. */
.thr-msg.note { align-self: center; max-width: 94%;
  background: transparent; border: 1px dashed var(--border); opacity: .75; }
/* Below this there is no room for a 16% gutter — the bubbles go full width and
   the side they sit on is carried by the colour alone. */
@media (max-width: 480px) {
  .thr-msg { max-width: 100%; }
}
.thr-meta { font-size: 10.5px; color: var(--text-dim); display: flex; gap: 8px; margin-bottom: 4px; }
.thr-meta > span { margin-left: auto; }
.thr-body { font-size: 13px; white-space: pre-wrap; word-break: break-word; }

/* The copy of the older mail a client pastes under a reply. Folded away by
   default — on Hector's thread it was 106 lines under a one-line answer — but
   never dropped, so the whole mail is always one click away. */
.thr-quote { margin-top: 6px; }
.thr-quote > summary {
  cursor: pointer; list-style: none;
  font-size: 10.5px; letter-spacing: .4px; color: var(--text-dim);
  padding: 3px 7px; border-radius: 5px; display: inline-block;
  border: 1px dashed var(--border); user-select: none;
}
.thr-quote > summary::-webkit-details-marker { display: none; }
.thr-quote > summary:hover { color: var(--text-muted); border-color: var(--border-strong); }
.thr-quote[open] > summary { margin-bottom: 6px; }
/* No max-height: a scrolling box inside the modal's own scroll meant two
   wheels fighting over the same gesture. It is behind a fold already — if it
   is open, he asked for it, and the page can simply be longer. */
.thr-quote-body {
  font-size: 11.5px; line-height: 1.45; white-space: pre-wrap; word-break: break-word;
  color: var(--text-dim);
  padding: 7px 9px; border-radius: 6px;
  background: rgba(0,0,0,.18); border-left: 2px solid var(--border);
}
:root[data-theme="medium"] .thr-quote-body,
:root[data-theme="light"]  .thr-quote-body { background: rgba(0,0,0,.05); }

/* Where the conversation changes subject. The timeline carries every thread
   this person has, so without this an answer about a portal login sits flush
   against a propeller order with nothing saying they are different threads. */
.thr-subject {
  align-self: stretch; display: flex; align-items: center; gap: 9px;
  margin: 6px 0 2px; font-size: 10px; letter-spacing: 1.1px; text-transform: uppercase;
  color: var(--text-dim);
}
.thr-subject::before, .thr-subject::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.thr-subject span { flex: 0 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 560px) {
  .tday-due-what, .tday-due-status { display: none; }
  .tday-when { margin-left: 0; width: 100%; }
}

/* Demo props on the showcase client. Loud on purpose — a demo prop must never
   be read as work that was done. */
.demo-chip {
  background: rgba(201,168,76,.28) !important;
  color: var(--gold);
  font-weight: 700;
  letter-spacing: .8px;
}
:root[data-theme="medium"] .demo-chip { background: rgba(201,168,76,.26) !important; color: #6b5313; }

/* The theoretical speed is the one number a list of props gets scanned for,
   so it carries the accent rather than sitting in the grey run of chips. */
.speed-chip {
  background: rgba(26,108,122,.22) !important;
  color: var(--accent);
  font-weight: 700;
}
:root[data-theme="medium"] .speed-chip { background: rgba(26,108,122,.16) !important; color: #12525d; }

/* Speed estimate resting on an assumed slip rather than a measured one —
   dimmed and dashed so it never reads as a real figure. */
.row-chip-assumed {
  opacity: .72;
  border-style: dashed !important;
  font-style: italic;
}
.muted-warn { color: #c9a84c; }

/* Resellers view — archive controls */
.reseller-archive-toggle {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 8px; cursor: pointer; user-select: none;
  font-size: 12px; letter-spacing: .3px; color: var(--muted, #8b9398);
}
.reseller-archive-toggle input { cursor: pointer; margin: 0; }
.reseller-archive-toggle:hover { color: var(--text, #e8ecee); }
.reseller-archived-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  flex-wrap: wrap; margin-bottom: 14px; padding: 10px 14px;
  border: 1px solid rgba(201, 168, 76, .45);
  background: rgba(201, 168, 76, .10);
  border-radius: 8px; font-size: 12.5px; line-height: 1.5; color: #c9a84c;
}
.reseller-archived-banner button { flex-shrink: 0; }

.pr-row.pr-cols-7 { grid-template-columns: 1.3fr .6fr 1fr 1fr 1fr 1fr .9fr; }
.pr-row.pr-cols-6 { grid-template-columns: 1.4fr .7fr 1fr 1fr 1fr 1fr; }
.pr-row.pr-cols-5 { grid-template-columns: 1.4fr .7fr 1fr 1fr .9fr; }
.pr-row.pr-cols-4 { grid-template-columns: 1.4fr .7fr 1fr 1fr; }
.pr-row.pr-cols-3 { grid-template-columns: 1.4fr .7fr 1fr; }

/* Read-only shop reference column. Dimmed so it reads as context rather than
   another editable cell; amber when it disagrees with the direct price. */
.pr-shop { color: var(--muted, #8b9398); font-size: 12px; }
.pr-shop-none { opacity: .4; }
.pr-shop-diff {
  color: #c9a84c; font-weight: 600;
  background: rgba(201, 168, 76, .10); border-radius: 5px;
}
.pr-row:last-child { border-bottom: none; }
.pr-row.pr-editable { cursor: pointer; transition: .12s; }
.pr-row.pr-editable:hover { background: rgba(255,255,255,.04); }
.pr-edit { padding-left: 4px; }
.pr-input {
  width: 100%; max-width: 110px;
  padding: 5px 8px;
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 6px;
  font: 12px 'DM Mono', monospace;
  color: var(--text);
  text-align: right;
  outline: none;
  transition: border-color .15s, box-shadow .25s;
}
.pr-input::placeholder { color: var(--text-dim); font-style: italic; }
.pr-input:focus { border-color: var(--accent); }
.pr-input.pr-saved { border-color: var(--green); box-shadow: 0 0 0 2px rgba(61,170,107,.2); }
.pr-input.pr-error { border-color: var(--red);   box-shadow: 0 0 0 2px rgba(212,74,46,.2); }

.hint-row {
  margin-top: 12px;
  padding: 10px 14px;
  background: rgba(255,255,255,.04);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.5;
}
.pr-row.pr-head {
  background: rgba(255,255,255,.04);
  color: var(--text-muted);
  font-size: 10px; font-weight: 600;
  letter-spacing: 1.5px; text-transform: uppercase;
}
.pr-cls { font-weight: 600; }
.pr-bld { color: var(--text-muted); font-family: 'DM Mono',monospace; }
.pr-num { font-family: 'DM Mono',monospace; color: var(--text); text-align: right; }
.pr-row.pr-head .pr-num { text-align: right; }

/* Settings: sub-tabs + add button + clickable rows */
/* Scrolls sideways like the main tab row, instead of wrapping onto a second
   and third line. Wrapping pushed the content down on exactly the screens
   where there is least room for it. */
.subtabs {
  display: flex; flex-wrap: nowrap; gap: 4px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none;
}
.subtabs::-webkit-scrollbar { display: none; }
.subtabs > * { flex: 0 0 auto; }
.subtab {
  background: transparent; border: none;
  color: var(--text-dim);
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: 1.5px; text-transform: uppercase;
  padding: 10px 14px; white-space: nowrap;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: .15s;
}
.subtab.active   { color: var(--accent); border-bottom-color: var(--accent); }
.subtab:hover:not(.active) { color: var(--text-muted); }

.subsection { display: none; }
.subsection.active { display: block; }
.subsection-head {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 10px;
}
.subsection-count {
  color: var(--text-dim); font-size: 12px;
  letter-spacing: 1px; flex: 0 0 auto;
}
.btn-add {
  background: var(--accent); color: var(--text);
  border: none; border-radius: 8px;
  padding: 9px 16px;
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer; transition: .15s;
  margin-left: auto;
}
.btn-add:hover { background: var(--accent-hover); }

.row.settings-row { cursor: pointer; }
.row.settings-row:hover { border-color: var(--border-strong); background: rgba(255,255,255,.02); }

/* Modal */
.modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.6);
  backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000;
  padding: 20px;
}
.modal[hidden] { display: none; }
/* dvh = dynamic viewport height; respects mobile URL bar / bottom nav.
   safe-area insets keep header/footer out from under Android Chrome chrome. */
.modal {
  padding: 20px;
  padding-top: max(20px, env(safe-area-inset-top));
  padding-bottom: max(20px, env(safe-area-inset-bottom));
}
.modal-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  width: 100%; max-width: 520px;
  max-height: 90dvh;
  display: flex; flex-direction: column;
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(0,0,0,.6);
}
@supports not (height: 100dvh) {
  .modal-card { max-height: 90vh; }
}
.modal-head {
  background: var(--bg-darker);
  padding: 14px 18px;
  display: flex; align-items: center;
  border-bottom: 1px solid var(--border);
}
.modal-title {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 400; font-size: 16px;
  letter-spacing: 2px; text-transform: uppercase;
  flex: 1;
}
.modal-close {
  background: transparent; border: none;
  color: var(--text-dim);
  font-size: 24px; line-height: 1;
  cursor: pointer; padding: 0 4px;
  transition: .15s;
}
.modal-close:hover { color: var(--text); }
.modal-body {
  padding: 18px;
  display: flex; flex-direction: column; gap: 12px;
  overflow-y: auto;
  flex: 1;
}
.m-field {
  display: flex; flex-direction: column; gap: 5px;
}

/* A client record carries two addresses — where the invoice goes and where the
   parcel goes — and they are the same for most people. Tabs rather than one
   long form: the second address is there when it is needed and out of the way
   when it is not. Both panels stay in the DOM, so saving never depends on
   which one happens to be open. */
.m-divider { border: 0; border-top: 1px solid var(--border); margin: 4px 0 0; }
.ent-tabs { display: flex; gap: 4px; margin: -2px 0 2px; }
.ent-tab {
  font: 600 12px/1 'DM Sans', sans-serif; padding: 8px 13px;
  background: transparent; color: var(--text-dim);
  border: 1px solid transparent; border-bottom: 2px solid transparent;
  border-radius: 5px 5px 0 0; cursor: pointer;
}
.ent-tab:hover { color: var(--text); }
.ent-tab.active {
  color: var(--text); border-bottom-color: var(--accent);
}
/* Ticked and filled in — a quiet mark so the shipping tab announces itself
   without being opened. */
.ent-tab.on::after  { content: ' ●'; color: var(--green); font-size: 9px; vertical-align: 2px; }
/* Ticked and empty: the tab claims a separate address it does not have. */
.ent-tab.warn::after { content: ' ▲'; color: var(--gold); font-size: 9px; vertical-align: 1px; }
.ent-tab-panel { display: flex; flex-direction: column; gap: 12px; }
/* An author `display` rule beats the browser's own [hidden]{display:none}, so
   without this both panels render at once and the tabs do nothing. Every block
   below that sets `display` and is toggled with `hidden` needs the same line. */
.ent-tab-panel[hidden] { display: none; }
.m-field > span {
  font-size: 10px;
  color: var(--text-dim);
  letter-spacing: 1px; text-transform: uppercase; font-weight: 600;
}
/* `:not([type])` matters: an <input> with no type attribute behaves as text but
   does NOT match input[type="text"], because that tests the attribute and not
   the default. Nineteen inputs in this file are written without one — the
   client-name picker among them, which is why it came out shorter than the
   fields beside it. Erik, 2026-09-28. One line here beats nineteen edits, and
   the next typeless input is already handled. */
.m-field input:not([type]),
.m-field input[type="text"],
.m-field input[type="email"],
.m-field input[type="tel"],
.m-field input[type="number"],
.m-field input[type="password"],
.m-field textarea {
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 7px;
  padding: 9px 12px;
  color: var(--text);
  font: 13px 'DM Sans',sans-serif;
  outline: none; transition: .15s;
}
.m-field input:focus, .m-field textarea:focus { border-color: var(--accent); }
/* The black triangle Chrome draws on a `list=` input. These are type-ahead
   fields — the suggestions come up as you type — and the copy button now sits
   on that corner anyway, so the arrow was unreachable as well as unnecessary.
   Scoped to input[list] on purpose: the same pseudo-element is the picker
   button on <input type="date">, where it is the only way in. */
.m-field input[list]::-webkit-calendar-picker-indicator { display: none; }
.m-field.m-check {
  flex-direction: row;
  align-items: center;
  gap: 9px;
}
.m-field.m-check span {
  text-transform: none;
  font-size: 13px;
  color: var(--text);
  letter-spacing: 0;
  font-weight: 500;
}
.m-field.m-check input[type="checkbox"] {
  width: 18px; height: 18px;
  accent-color: var(--accent);
  cursor: pointer;
}
.radii-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
  gap: 6px;
  margin-top: 4px;
}
.radii-check {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 10px;
  border: 1.5px solid var(--border);
  border-radius: 7px;
  background: var(--bg-mid);
  font: 12px 'DM Mono', monospace;
  cursor: pointer; transition: .12s;
}
.radii-check input { accent-color: var(--accent); cursor: pointer; }
.radii-check:has(input:checked) { border-color: var(--accent); background: rgba(26,108,122,.12); }
.classes-panel { margin-bottom: 22px; }
.modal-foot {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
  padding: 12px 18px;
  background: var(--bg-darker);
  border-top: 1px solid var(--border);
}
/* The flex-1 spacer in modals (style="flex:1") loses its gap-to-zero on
   wrapped layouts — force minimum width so the right-side buttons stay
   pushed to the trailing edge until the row actually wraps. */
.modal-foot > [style*="flex:1"] { min-width: 0; }
@media (max-width: 620px) {
  .modal-foot { justify-content: flex-start; }
  .modal-foot > [style*="flex:1"] { display: none; }
}
.btn-primary, .btn-ghost, .btn-danger {
  border: none; border-radius: 7px;
  padding: 9px 16px;
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer; transition: .15s;
}
.btn-primary { background: var(--accent); color: var(--text); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:disabled { opacity: .5; cursor: wait; }
.btn-ghost { background: transparent; color: var(--text-muted); border: 1px solid var(--border); }
.btn-ghost:hover { color: var(--text); border-color: var(--border-strong); }
.btn-danger { background: transparent; color: var(--red); border: 1px solid rgba(212,74,46,.4); }
.btn-danger:hover { background: rgba(212,74,46,.15); border-color: var(--red); }
/* Stated rather than assumed. Twice now a [hidden] element stayed on screen
   because its own class set a display and beat the user-agent rule — the print
   picker's rows and the class-link rows. These set none, so hidden already
   works; this makes sure it keeps working if one ever gains a display. */
.btn-primary[hidden], .btn-ghost[hidden], .btn-danger[hidden] { display: none; }

/* ── Games ────────────────────────────────────────────────────────────
   One card per game now, but laid out as a grid so a second one costs no
   layout work. */
.game-list { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
/* Third time this exact trap has been sprung here (print picker rows, class
   links, now this): an author `display` ALWAYS outranks the user agent's
   `[hidden] { display: none }`, so setting .hidden in JS did nothing and the
   card sat on top of the running game. Anything given a display needs this. */
.game-list[hidden] { display: none; }
/* The card leads with a frame from the game itself. Padding belongs to the
   text block, not the card, or the picture would sit in a margin. */
.game-card {
  display: flex; flex-direction: column; text-align: left;
  padding: 0; border-radius: 12px; cursor: pointer; overflow: hidden;
  background: var(--bg-card); border: 1px solid var(--border);
  color: inherit; font: inherit; transition: .18s;
}
.game-card:hover { border-color: var(--accent); background: var(--bg-mid); }
.game-card:hover .game-shot img { transform: scale(1.04); }
.game-card:hover .game-go { color: var(--accent); }

.game-shot {
  display: block; aspect-ratio: 2 / 1; overflow: hidden;
  background: #0d1824;                 /* the game's own backdrop, so a slow
                                          image does not flash white */
  border-bottom: 1px solid var(--border);
}
.game-shot img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform .35s ease;
}
/* A card with no screenshot yet: the rule number on the game's own red, which
   reads as a start light rather than as a missing image. */
.game-shot-text {
  display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
  font-family: 'Anton','Montserrat',sans-serif; font-size: 30px; line-height: 1.05;
  letter-spacing: 2px; text-align: center; color: #fff;
  background: radial-gradient(circle at 50% 42%, #c0392b 0%, #7d1f16 58%, #3a0e0a 100%);
}
/* The quiz card gets the house teal instead of the start-light red. */
.game-shot-quiz {
  font-size: 56px; letter-spacing: 0;
  background: radial-gradient(circle at 50% 42%, #2aa3b8 0%, #14596b 58%, #07222b 100%);
}
.game-body { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px 16px; }
.game-name {
  font-family: 'Montserrat','DM Sans',sans-serif; font-size: 17px; font-weight: 600;
  letter-spacing: .4px;
}
.game-note { font-size: 12.5px; line-height: 1.5; color: var(--text-muted); }
.game-go {
  margin-top: 2px; font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase;
  font-weight: 600; color: var(--text-dim); transition: color .18s;
}
/* Someone who asked for less movement gets the card without the zoom. */
@media (prefers-reduced-motion: reduce) {
  .game-shot img, .game-card:hover .game-shot img { transition: none; transform: none; }
}

.game-stage[hidden] { display: none; }
.game-stage { display: flex; flex-direction: column; gap: 10px; }
.game-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.game-playing {
  font-family: 'Montserrat','DM Sans',sans-serif; font-size: 14px; letter-spacing: .6px;
}
/* The game draws a full-screen scene of its own, so it is given a tall frame
   rather than a letterbox — 76vh keeps the bar above it on screen while
   leaving the propeller room to turn. */
#game-frame {
  width: 100%; height: 76vh; min-height: 420px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-darker); display: block;
}
@media (max-width: 560px) {
  #game-frame { height: 68vh; min-height: 340px; }
}

/* Order edit modal — wider, multi-section, tabbed */
.modal-card.order-modal-card { max-width: 780px; }
.om-tabs {
  display: flex; gap: 2px;
  /* Hug the modal head — no gap above; pull left/right to the card edges. */
  margin: -18px -18px 14px;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-darker);
  position: sticky; top: 0;
  z-index: 2;
}
/* When the tabs strip is the first child of modal-body, it must sit flush
   against modal-head — kill the body's top padding above it. */
.modal-body:has(> .om-tabs:first-child) { padding-top: 0; }
.om-tab {
  background: transparent; border: 0;
  color: var(--text-dim);
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: 1.5px; text-transform: uppercase;
  padding: 12px 18px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: .15s;
}
.om-tab:hover:not(.active) { color: var(--text-muted); }
.om-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.om-tab-panel { display: none; }
.om-tab-panel.active { display: block; }
.om-section {
  display: flex; flex-direction: column;
  gap: 10px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.om-section:last-child { border-bottom: none; padding-bottom: 0; }
.om-section + .om-section { padding-top: 4px; }
.om-sec-title {
  font: 700 10px 'DM Sans',sans-serif;
  letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 2px;
}
.om-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px 14px;
}
.om-row .m-field { gap: 4px; }
/* The order modal's two addresses use the client form's tabs — same classes,
   same behaviour, so the two screens cannot drift apart. These panels hold
   .om-row grids rather than a plain column. */
.om-section .ent-tabs { margin: 8px 0 10px; }
.om-section .ent-tab-panel { gap: 10px; }
.om-section .m-check {
  flex-direction: row; align-items: center; gap: 9px; cursor: pointer;
}
.om-section .m-check input { accent-color: var(--accent); cursor: pointer; margin: 0; }
.om-section .m-check > span {
  font-size: 12px; font-weight: 600; letter-spacing: 0; text-transform: none;
  color: var(--text);
}
.om-hint {
  font: 11px 'DM Sans',sans-serif;
  color: var(--text-dim);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
.om-hint strong { color: var(--accent); font-weight: 600; }
.om-hint .link-btn { font-size: 11px; padding: 1px 6px; margin-left: 4px; }

/* Suggested prices on the order modal. Each chip names its own source, so it
   is always clear whether a figure came off the storefront or the rate list. */
.om-price-hint {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  background: rgba(0,0,0,.25); border-radius: 8px; padding: 7px 9px;
  font: 12px 'DM Sans',sans-serif;
}
.om-price-sug { display: inline-flex; align-items: baseline; gap: 5px; }
.om-price-sug > i { font-style: normal; color: var(--text-dim); }
.om-price-sug > b { font-weight: 500; font-size: 10.5px; color: var(--text-dim);
  background: rgba(128,128,128,.16); padding: 1px 5px; border-radius: 4px; }
.om-price-none { color: var(--text-dim); font-style: italic; }

/* "Blanks in stock" on the order modal — the summary the shop enforces, then
   one line per mould so it is clear which pile the number came off. */
.om-field-wide { grid-column: 1 / -1; }
.om-stock-hint {
  background: rgba(0,0,0,.25); border-radius: 8px;
  padding: 6px 8px; display: flex; flex-direction: column; gap: 2px;
}
.oms-note { font: 11px 'DM Sans',sans-serif; color: var(--text-dim); font-style: italic; }
.oms-sum { display: flex; flex-wrap: wrap; gap: 5px; padding-bottom: 4px; margin-bottom: 2px;
  border-bottom: 1px solid var(--border); }
.oms-sum-cell { font-size: 11px; padding: 2px 7px; border-radius: 5px;
  background: rgba(128,128,128,.14); white-space: nowrap; }
.oms-sum-cell b { font-weight: 700; margin-left: 3px; }
.oms-sum-cell.ok  { background: rgba(61,170,107,.18);  color: var(--green); }
.oms-sum-cell.low { background: rgba(201,168,76,.20);  color: var(--gold); }
.oms-sum-cell.out { background: rgba(212,74,46,.18);   color: var(--red); }
.oms-sum-cell.na  { opacity: .55; }
.oms-sum-cell.on  { outline: 1.5px solid var(--accent); outline-offset: 1px; }

.oms-row { display: flex; align-items: center; gap: 7px; font-size: 11.5px; }
.oms-row.zero { opacity: .55; }
.oms-name { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.oms-spec { flex: 0 0 auto; color: var(--text-dim); font-size: 10.5px; }
.oms-tag { flex: 0 0 auto; font-size: 9.5px; padding: 0 4px; border-radius: 3px;
  background: rgba(26,108,122,.30); color: #7fd0dd; }
.oms-tag.off { background: rgba(212,74,46,.16); color: var(--red); }
.oms-qty { flex: 0 0 30px; text-align: right; font-weight: 700; font-size: 13px; }
.oms-row:not(.zero) .oms-qty { color: var(--green); }
.oms-row.zero .oms-qty { color: var(--red); }
.om-pitch-grid {
  display: flex; flex-direction: column;
  gap: 6px;
  background: rgba(0,0,0,.25);
  border-radius: 8px;
  padding: 8px;
}
.pp-row {
  display: grid;
  grid-template-columns: 48px 1fr 120px;
  gap: 10px;
  align-items: stretch;
}
.pp-label {
  font: 700 12px 'DM Sans',sans-serif;
  color: var(--text-dim);
  letter-spacing: .5px;
  text-align: center;
  align-self: center;
}
.pp-picks-stack {
  display: flex; flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.pp-picks {
  display: flex; flex-wrap: wrap; gap: 4px;
  min-width: 0;
}
.pp-btn {
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 8px 14px;
  min-width: 48px;
  border-radius: 6px;
  font: 14px 'DM Mono',monospace;
  cursor: pointer;
  user-select: none;
  flex: 0 0 auto;
}
.pp-btn:hover { border-color: var(--accent); }
.pp-btn.sel {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.pp-cup { border-color: rgba(201,168,76,.6); }
.pp-cup.sel { background: #c9a84c; border-color: #c9a84c; color: #000; }
.pp-input {
  width: 100%;
  height: 100%;
  padding: 6px 8px;
  background: var(--bg-card);
  border: 1.5px solid var(--border);
  border-radius: 6px;
  font: 13px 'DM Mono',monospace;
  color: var(--text);
  text-align: center;
  outline: none;
  box-sizing: border-box;
  align-self: stretch;
}
.pp-input:focus { border-color: var(--accent); }
@media (max-width: 720px) {
  .pp-row { grid-template-columns: 40px 1fr 90px; gap: 6px; }
  .pp-btn { padding: 6px 10px; min-width: 38px; font-size: 12px; }
  .pp-input { font-size: 11px; }
}
.pitch-input {
  display: flex; flex-direction: column; gap: 2px;
  text-align: center;
}
.pitch-input span {
  font: 700 9px 'DM Sans',sans-serif;
  color: var(--text-dim);
  letter-spacing: .5px;
}
.pitch-input input {
  width: 100%;
  padding: 6px 4px;
  background: var(--bg-card);
  border: 1.5px solid var(--border);
  border-radius: 5px;
  font: 11px 'DM Mono',monospace;
  color: var(--text);
  text-align: center;
  outline: none;
}
.pitch-input input:focus { border-color: var(--accent); }

.row-detail-actions {
  display: flex; align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.row-detail-actions.row-detail-bottom {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.row-detail-build {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  margin: 8px 0;
}
.row-detail-build .zone-c { margin-bottom: 8px; }
.row-detail-build .row-detail-pitches,
.row-detail-build .row-detail-modifications {
  margin: 8px -4px;
}
.row-detail-build .zone-b { margin-top: 8px; }
.row-reseller-hint {
  font-size: 11px; color: var(--accent);
  font-weight: 500; font-style: normal;
  letter-spacing: .3px;
}
.quick-select {
  padding: 7px 10px;
  border: 1.5px solid var(--border);
  border-radius: 7px;
  background: var(--bg-card);
  color: var(--text);
  font: 12px 'DM Sans', sans-serif;
  outline: none;
  cursor: pointer;
  min-width: 130px;
}
.quick-select:hover { border-color: var(--border-strong); }
.quick-select:focus { border-color: var(--accent); }

.detail-head {
  display: flex; align-items: center; gap: 16px;
  margin-bottom: 18px;
}
.detail-title {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 300; font-size: 26px;
  letter-spacing: 3px; text-transform: uppercase;
}
.block-title {
  font: 700 10px 'DM Sans',sans-serif;
  letter-spacing: 2px; text-transform: uppercase;
  color: var(--text-muted);
  margin: 22px 0 8px;
}
.block-row {
  display: flex; align-items: center; gap: 10px;
  margin-top: 22px;
}
.block-row .block-title { margin: 0; flex: 1; }

/* Stats tab — simple CSS bar charts */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
}
.stat-block {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
}
.stat-block-title {
  font: 700 10px 'DM Sans',sans-serif;
  letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.stat-bars { display: flex; flex-direction: column; gap: 4px; }
.stat-bar-row {
  display: grid;
  grid-template-columns: 110px 1fr 40px;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.stat-bar-label { color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat-bar-track {
  height: 14px;
  background: rgba(255,255,255,.05);
  border-radius: 7px;
  overflow: hidden;
}
.stat-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-hover));
  border-radius: 7px;
  transition: width .4s ease-out;
}
.stat-bar-value {
  font-family: 'DM Mono',monospace;
  color: var(--text-muted);
  text-align: right;
}

/* Worker Pay per-worker KPI tiles — compact variant of the dashboard tiles */
.wp-worker-kpis {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px;
  padding: 12px;
  background: rgba(0,0,0,.18);
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}
.wp-worker-kpis .kpi { padding: 10px 12px; }
.wp-worker-kpis .kpi-value { font-size: 22px; }
.wp-worker-kpis .kpi-label { letter-spacing: 1px; }

/* Worker Pay — grouped completed list */
.wp-worker-group {
  margin-bottom: 18px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.wp-worker-header {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px;
  background: rgba(255,255,255,.04);
  border-bottom: 1px solid var(--border);
}
.wp-worker-name {
  font-family: 'Montserrat','DM Sans',sans-serif;
  font-weight: 400; font-size: 14px;
  letter-spacing: 2px; text-transform: uppercase;
  flex: 1;
}
.wp-worker-counts {
  color: var(--text-dim);
  font-size: 11px; letter-spacing: 1px;
}
.row.wp-comp-row {
  border-radius: 0;
  border: none;
  border-bottom: 1px solid var(--border);
  background: transparent;
}
.row.wp-comp-row:last-child { border-bottom: none; }

/* A payment or a credit sitting in the Work done timeline. It has to be
   impossible to mistake for another prop at a glance — it is the line you scan
   for when asking "what has he done since I last paid him" — so it gets a tinted
   band and a rule above it rather than the plain row treatment. */
.row.wp-money-row {
  border-top: 1px solid var(--border);
  background: var(--bg-mid);
}
.row.wp-money-row.is-payment { box-shadow: inset 3px 0 0 var(--gold); }
.row.wp-money-row.is-credit  { box-shadow: inset 3px 0 0 var(--accent); }

/* A row that opens. The whole line is the target — these are read on a phone
   in a workshop — and the editor is a button inside, so a mis-tap costs a tap
   back rather than putting a form over the ledger. */
/* ── Portal usage, on the Stats page ──────────────────────────────────────
   Four tiles, twelve weeks of bars, two ranked lists and a list of people.
   The chart is CSS: at twelve columns a charting library would be more code
   than the page it sits on, and this one prints fine on a phone. */
.usage-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.usage-tiles {
  display: grid; gap: 10px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.usage-tiles .stat-cell {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 14px; gap: 3px;
}
.usage-tiles .stat-cell.accent { border-color: var(--accent); }
.usage-tiles .stat-cell.warn   { border-color: var(--red); }
.usage-tiles .stat-value { font: 700 24px/1 'DM Mono', monospace; }
.usage-tiles .stat-sub   { font-size: 11px; color: var(--text-dim); }

.usage-chart {
  display: flex; align-items: flex-end; gap: 4px;
  height: 140px; padding: 10px 12px 0;
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 10px; margin-bottom: 14px;
}
.uz-col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; height: 100%; }
.uz-bar-wrap { flex: 1 1 auto; width: 100%; display: flex; align-items: flex-end; }
.uz-bar { width: 100%; border-radius: 3px 3px 0 0; background: var(--accent); min-height: 2px; }
.uz-ppl { font: 600 10px/1.6 'DM Mono', monospace; color: var(--text); }
.uz-wk  { font: 10px/1.6 'DM Mono', monospace; color: var(--text-dim); }

.usage-cols { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.usage-col {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 14px;
}
.usage-col h4, .usage-h4 {
  font-size: 10px; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--text-dim); margin: 0 0 8px;
}
.usage-h4 { margin: 18px 0 8px; }
.row.usage-row { cursor: pointer; }
.row.usage-row .row-id { min-width: 92px; }
.usage-note { font-size: 11.5px; color: var(--text-dim); margin: 12px 2px 0; line-height: 1.6; }

/* Picking which props move to another customer. A plain list of tick boxes:
   the serial is what Erik reads them by, so it leads. */
.mv-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.mv-list {
  max-height: 46vh; overflow: auto;
  border: 1px solid var(--border); border-radius: 8px;
  margin-bottom: 12px;
}
.mv-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.mv-row:last-child { border-bottom: none; }
.mv-row:hover { background: rgba(255,255,255,.03); }
.mv-row input { flex: 0 0 auto; width: 16px; height: 16px; accent-color: var(--accent); }
.mv-id   { font: 500 11px 'DM Mono',monospace; color: var(--text-dim); min-width: 62px; }
.mv-what { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600;
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mv-meta { font-size: 11px; color: var(--text-dim); white-space: nowrap; }

.row.wp-openable { cursor: pointer; }
.row.wp-openable.expanded { border-color: var(--accent); background: rgba(26,108,122,.08); }
.wp-detail .row-detail-actions { margin-bottom: 0; }
/* `.row-detail` sets display:flex, and an author rule beats the browser's own
   [hidden] { display:none } every time — so without this the panels were all
   open at once and the attribute did nothing. The older detail panels never hit
   it because they are built and thrown away rather than toggled. */
.wp-detail[hidden] { display: none; }

/* Inside a worker group the rows run flush and the group clips its own corners,
   so the shared .row-detail look — rounded, pulled up over the row above by its
   negative margin — has to be undone rather than inherited. In the payment
   history list, which is an ordinary gapped row-list, it is exactly right. */
.wp-worker-group .wp-detail {
  margin: 0;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: rgba(26,108,122,.07);
}
.wp-worker-group .row.wp-openable.expanded {
  background: rgba(26,108,122,.14);
  box-shadow: inset 3px 0 0 var(--accent);
}
.row.wp-money-row .row-name strong { font-weight: 600; letter-spacing: .02em; }

/* The balance restated inside the payment modal, so the amount being typed can
   be checked against it without closing the dialog. */
.wp-owed-note {
  font-size: 13px; color: var(--text-muted);
  padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg-mid);
}
.wp-owed-note strong { color: var(--text); font-size: 14px; }
/* Credit is the rare choice and the dangerous one — it raises what is owed —
   so it does not sit flush with the ordinary fields above it. */
.wp-kind { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border); }

/* .pay-pick styled the checkbox rows in the record-payment modal. Payments
   stopped being recorded against a list of props on 2026-10-05; kept because
   nothing else uses these names and removing them buys nothing. */
.pay-pick {
  display: grid;
  grid-template-columns: 24px 100px 1fr;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-bottom: 4px;
  background: var(--bg-mid);
  cursor: pointer;
}
.pay-pick:has(input:checked) {
  border-color: var(--accent);
  background: rgba(26,108,122,.08);
}
.pay-pick input { accent-color: var(--accent); cursor: pointer; }
.pp-id  { font-family: 'DM Mono',monospace; font-size: 11px; color: var(--text); }
.pp-meta { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Mobile polish — tighten layouts on narrow screens */
@media (max-width: 640px) {
  .row { padding: 9px 11px; gap: 8px; }
  .row-name { font-size: 13px; }
  .stat-bar-row { grid-template-columns: 90px 1fr 36px; font-size: 11px; }
  .topbar-title { font-size: 16px; letter-spacing: 3px; }
  .section-title { font-size: 20px; letter-spacing: 3px; }
  .pr-row { padding: 8px 10px; font-size: 12px; }
  .pr-row.pr-cols-7 { grid-template-columns: .9fr .45fr .65fr .65fr .7fr .7fr .6fr; }
  .pr-row.pr-cols-6 { grid-template-columns: 1fr .5fr .7fr .7fr .8fr .8fr; }
  .pr-row.pr-cols-5 { grid-template-columns: 1fr .5fr .8fr .8fr .7fr; }
  .pr-row.pr-cols-4 { grid-template-columns: 1fr .5fr .9fr .9fr; }
  .pr-input { max-width: 80px; padding: 4px 6px; font-size: 11px; }
  .om-pitch-grid { grid-template-columns: repeat(auto-fit, minmax(50px, 1fr)); }
  .pitch-input input { font-size: 10px; }
  .row-detail-pitches { grid-template-columns: repeat(auto-fit, minmax(48px, 1fr)); }
  .kpi-value { font-size: 30px; }
  .stat-cell { flex: 1 1 70px; }
  .stat-value { font-size: 15px; }
  .modal { padding: 0;
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .modal-card { max-width: 100%; max-height: 100dvh; border-radius: 0; }
  @supports not (height: 100dvh) {
    .modal-card { max-height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom)); }
  }
  .modal-card.order-modal-card { max-width: 100%; }
}

/* Drag handle for re-orderable client rows */
.drag-handle {
  cursor: grab;
  color: var(--text-dim);
  font-size: 14px;
  letter-spacing: -2px;
  padding: 2px 6px;
  user-select: none;
}
.drag-handle:active { cursor: grabbing; }
.row.dragging {
  opacity: .5;
  border-color: var(--accent) !important;
  background: rgba(26,108,122,.08) !important;
}

/* Inline × delete button on payment rows (admin only) */
.row-del-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 22px; height: 22px;
  border-radius: 50%;
  font-size: 14px;
  line-height: 18px;
  padding: 0;
  cursor: pointer;
  margin-left: 6px;
}
.row-del-btn:hover {
  background: rgba(220, 64, 64, .12);
  border-color: #c44;
  color: #f88;
}
.row-del-btn:disabled { opacity: .4; cursor: wait; }

/* ── Calendar (Events tab) ───────────────────────────────────── */
.cal-toolbar {
  display: flex; align-items: center; gap: 10px;
  margin: 8px 0 12px;
}
.cal-nav {
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  width: 32px; height: 32px;
  border-radius: 8px;
  font: 700 18px 'DM Sans',sans-serif;
  cursor: pointer;
  line-height: 1;
}
.cal-nav:hover { border-color: var(--accent); color: var(--accent); }
.cal-title {
  font: 700 16px 'DM Sans',sans-serif;
  letter-spacing: .3px;
  min-width: 180px;
  text-align: center;
}
.cal-grid {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.cal-dow-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: rgba(0,0,0,.2);
}
.cal-dow {
  padding: 8px 6px;
  font: 700 10px 'DM Sans',sans-serif;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
  text-align: center;
  border-right: 1px solid var(--border);
}
.cal-dow:last-child { border-right: none; }
.cal-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(96px, 1fr);
}
.cal-day {
  border-right: 1px solid var(--border);
  border-top: 1px solid var(--border);
  padding: 4px 4px 6px;
  display: flex; flex-direction: column;
  gap: 3px;
  cursor: pointer;
  position: relative;
  min-height: 0;
}
.cal-day:hover { background: rgba(26,108,122,.06); }
.cal-day:nth-child(7n) { border-right: none; }
.cal-day-off {
  color: var(--text-dim);
  background: rgba(0,0,0,.12);
}
.cal-day-off .cal-daynum { opacity: .5; }
.cal-day-today {
  background: rgba(26,108,122,.08);
}
.cal-day-today .cal-daynum {
  background: var(--accent);
  color: #fff;
  width: 22px; height: 22px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.cal-daynum {
  font: 700 12px 'DM Sans',sans-serif;
  color: var(--text);
  align-self: flex-end;
  padding: 0 2px;
}
.cal-events {
  display: flex; flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.cal-evt {
  background: var(--accent);
  color: #fff;
  padding: 2px 6px;
  border-radius: 4px;
  font: 600 10px 'DM Sans',sans-serif;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.cal-evt:hover { background: #2487a0; }
.cal-evt-more {
  font: 700 9px 'DM Sans',sans-serif;
  color: var(--text-dim);
  text-align: right;
  padding: 0 2px;
}
.cal-list-head {
  margin: 18px 0 8px;
  font: 700 11px 'DM Sans',sans-serif;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent);
}
/* Calendar event chips with linked prop handovers get a gold accent */
.cal-evt-handover {
  background: #c9a84c !important;
  color: #000 !important;
}
.cal-evt-handover:hover { background: #d8b85e !important; }
.cal-handover-dot {
  font-size: 9px;
  margin-right: 3px;
  vertical-align: middle;
}
/* Special-agreement row + chip */
.special-paid-btn {
  margin-left: 8px;
  padding: 4px 10px;
  font-size: 11px;
  border: 1px solid var(--accent);
  color: var(--accent);
  background: transparent;
  border-radius: 6px;
  cursor: pointer;
}
.special-paid-btn:hover { background: var(--accent); color: #fff; }
.special-paid-btn:disabled { opacity: .5; cursor: wait; }
.special-flag {
  color: #c9a84c !important;
  font-weight: 700 !important;
}

/* Service pill — highlight order rows for service jobs (Modification, Transport, etc.) */
.row-chip.service-pill {
  background: linear-gradient(135deg, #9263a7, #6b4582) !important;
  color: #fff !important;
  font-weight: 700;
  letter-spacing: .4px;
  text-transform: uppercase;
  font-size: 10px;
  padding: 3px 9px;
  border: 1px solid #6b4582 !important;
  box-shadow: 0 0 0 1px rgba(146,99,167,.25);
}
/* Modification-changes block inside the order detail (replaces empty radii) */
.row-detail-modifications {
  margin: 10px 0;
  border-left: 3px solid #9263a7;
}

/* Motor-height stepper (Tools → Test logbook) */
.mh-wheel {
  display: flex; align-items: stretch; gap: 4px;
  background: var(--bg-card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  padding: 4px;
}
.mh-wheel .mh-step {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  width: 36px;
  border-radius: 6px;
  font: 700 16px 'DM Sans',sans-serif;
  cursor: pointer;
}
.mh-wheel .mh-step:hover { border-color: var(--accent); color: var(--accent); }
.mh-wheel input[type="number"] {
  flex: 1;
  text-align: center;
  font: 700 22px 'DM Mono',monospace;
  color: var(--accent);
  background: transparent;
  border: none;
  outline: none;
  -moz-appearance: textfield;
}
.mh-wheel input[type="number"]::-webkit-outer-spin-button,
.mh-wheel input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.mh-track {
  position: relative;
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(90deg,
    rgba(212,74,46,.30) 0%,
    rgba(0,0,0,.15) 50%,
    rgba(61,170,107,.30) 100%);
  margin-top: 6px;
}
.mh-track::before {
  /* zero tick */
  content: '';
  position: absolute;
  left: 50%; top: -3px;
  width: 1px; height: 12px;
  background: var(--text-dim);
}
.mh-marker {
  position: absolute;
  top: -22px;
  transform: translateX(-50%);
  background: var(--accent);
  color: #fff;
  font: 700 10px 'DM Mono',monospace;
  padding: 2px 6px;
  border-radius: 4px;
  white-space: nowrap;
}
.mh-marker::after {
  content: '';
  position: absolute;
  left: 50%; top: 100%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-top-color: var(--accent);
}

/* Test log row — 2-column: venue (bold) / date on left; prop, chips, notes right */
.tl-row {
  display: grid !important;
  grid-template-columns: 160px 1fr;
  gap: 14px;
  align-items: start;
}
.tl-when {
  display: flex; flex-direction: column;
  gap: 2px;
}
.tl-venue {
  font: 700 13px 'DM Sans',sans-serif;
  color: var(--text);
  word-break: break-word;
}
.tl-date {
  font: 500 12px 'DM Mono',monospace;
  color: var(--text-dim);
}
.tl-body {
  display: flex; flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.tl-head {
  display: flex; align-items: center; gap: 8px;
}
.tl-prop {
  font: 700 14px 'DM Sans',sans-serif;
  color: var(--text);
  flex: 1;
}
.tl-head .row-del-btn { margin-left: auto; }
.tl-chips {
  display: flex; flex-wrap: wrap; gap: 6px;
  align-items: center;
}
.tl-notes {
  font: 400 12px 'DM Sans',sans-serif;
  color: var(--text-dim);
  word-break: break-word;
}
.tl-laps {
  background: rgba(0,0,0,.18);
  border-radius: 6px;
  padding: 6px 10px;
  cursor: pointer;
  user-select: none;
}
.tl-laps-summary {
  display: flex; align-items: center; gap: 10px;
  font: 12px 'DM Mono',monospace;
}
.tl-lap-best {
  font-weight: 700;
  color: var(--green);
}
.tl-lap-count { color: var(--text-dim); }
.tl-laps-chevron {
  margin-left: auto;
  color: var(--text-dim);
  font-size: 14px;
  transition: transform .15s;
}
.tl-laps.expanded .tl-laps-chevron { transform: rotate(180deg); }
.tl-laps-all {
  display: none;
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  flex-direction: column;
  gap: 2px;
}
.tl-laps.expanded .tl-laps-all { display: flex; }
.tl-lap-row {
  display: flex; justify-content: space-between;
  font: 12px 'DM Mono',monospace;
  padding: 3px 4px;
  border-radius: 4px;
}
.tl-lap-row.best { background: rgba(61,170,107,.15); color: var(--green); font-weight: 700; }
.tl-lap-n { color: var(--text-dim); }
@media (max-width: 600px) {
  .tl-row { grid-template-columns: 110px 1fr; gap: 10px; }
  .tl-venue { font-size: 12px; }
  .tl-prop { font-size: 13px; }
}

/* Stopwatch widget (Test logbook → New entry) */
.sw {
  background: var(--bg-card);
  border: 1.5px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  display: flex; flex-direction: column;
  gap: 10px;
}
.sw-display {
  font: 700 36px 'DM Mono',monospace;
  letter-spacing: 1px;
  color: var(--accent);
  text-align: center;
  padding: 4px 0;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.sw-actions {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.sw-btn {
  padding: 14px 0;
  border: 1.5px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  font: 700 13px 'DM Sans',sans-serif;
  letter-spacing: .5px;
  text-transform: uppercase;
  border-radius: 8px;
  cursor: pointer;
  /* "none" prevents Chrome from interpreting touch as scroll/zoom and
     hijacking the pointer mid-press */
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
.sw-btn:active { transform: scale(.97); }
.sw-btn:disabled { opacity: .35; cursor: not-allowed; }
.sw-btn.sw-start { border-color: var(--green); color: var(--green); }
.sw-btn.sw-stop  { border-color: var(--red);   color: var(--red); }
.sw-btn.sw-lap   { border-color: var(--accent); color: var(--accent); }
.sw-btn.sw-reset { border-color: var(--text-dim); color: var(--text-muted); }
.sw-laps {
  display: flex; flex-direction: column;
  gap: 3px;
  max-height: 180px;
  overflow-y: auto;
}
.sw-lap-row {
  display: flex; justify-content: space-between;
  padding: 6px 10px;
  background: rgba(0,0,0,.15);
  border-radius: 5px;
  font: 12px 'DM Mono',monospace;
}
.sw-lap-row.best { background: rgba(61,170,107,.18); color: var(--green); font-weight: 700; }
.sw-lap-n { color: var(--text-dim); }
@media (max-width: 600px) {
  .sw-display { font-size: 30px; }
  .sw-btn { padding: 12px 0; font-size: 12px; }
}

/* Speed calculator unit toggle + result display */
.unit-toggle {
  margin-left: 6px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--accent);
  font: 700 10px 'DM Mono',monospace;
  padding: 2px 8px;
  border-radius: 4px;
  cursor: pointer;
  text-transform: lowercase;
  letter-spacing: .3px;
}
.unit-toggle:hover { border-color: var(--accent); }
.calc-out {
  font: 700 26px 'DM Mono',monospace;
  color: var(--accent);
  padding: 8px 0;
  letter-spacing: .5px;
}
/* Inline disclaimer block — used on the speed calculator props list */
.calc-disclaimer {
  display: flex; gap: 10px;
  margin: 10px 14px 6px;
  padding: 10px 12px;
  background: linear-gradient(135deg, rgba(26,108,122,.10), rgba(201,168,76,.08));
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  font: 12px 'DM Sans',sans-serif;
  color: var(--text-muted);
  line-height: 1.45;
}
.calc-disclaimer strong { color: var(--text); }
.calc-disclaimer-icon {
  font-size: 18px;
  color: var(--accent);
  line-height: 1;
  flex: 0 0 auto;
}

/* Two-number gear teeth input (pinion / driven) */
.gear-pair {
  display: flex; align-items: center; gap: 6px;
}
.gear-pair input {
  flex: 1;
  min-width: 0;
  text-align: center;
  font: 600 14px 'DM Mono',monospace;
}
.gear-sep {
  font: 700 18px 'DM Mono',monospace;
  color: var(--text-dim);
}
.special-group + .special-group { margin-top: 14px; }
.special-group-head {
  padding: 6px 10px;
  margin: 6px 0 4px;
  background: rgba(201,168,76,.10);
  border-left: 3px solid #c9a84c;
  border-radius: 4px;
  font: 13px 'DM Sans',sans-serif;
  color: var(--text);
}
.special-group-date {
  font-family: 'DM Mono',monospace;
  color: #c9a84c;
  font-weight: 700;
}
.special-group-none {
  background: rgba(0,0,0,.18);
  border-left-color: var(--text-dim);
}
.special-group-none .om-hint { color: var(--text-dim); }

/* ── Rental boxes ───────────────────────────────────────── */
.cal-rental-band {
  background: linear-gradient(90deg, rgba(146,99,167,.7), rgba(146,99,167,.55));
  color: #fff;
  font: 700 9px 'DM Sans',sans-serif;
  letter-spacing: .3px;
  padding: 2px 5px;
  margin: 1px 0;
  border-radius: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.cal-rental-band:hover { filter: brightness(1.15); }
.cal-rental-band.band-start { border-left: 3px solid #c9a84c; }
.cal-rental-band.band-end   { border-right: 3px solid #d04444; }
.rental-row {
  border-left: 3px solid var(--border);
}
.rental-row.rented { border-left-color: #9263a7; }
.rental-row.available { border-left-color: #4a8a4a; }
.rental-available-tag {
  color: #4a8a4a;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .5px;
  text-transform: uppercase;
}
.rental-send-btn,
.rental-return-btn {
  margin-left: 8px;
  padding: 4px 10px;
  font-size: 11px;
  border-radius: 6px;
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
}
.rental-send-btn:hover,
.rental-return-btn:hover { background: var(--accent); color: #fff; }
.rental-send-btn:disabled,
.rental-return-btn:disabled { opacity: .5; cursor: wait; }
.rental-prop-list {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px;
  background: rgba(0,0,0,.15);
}
.rental-prop-pick {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 6px;
  cursor: pointer;
  border-radius: 4px;
  font: 11px 'DM Mono',monospace;
  color: var(--text);
}
.rental-prop-pick:hover { background: rgba(26,108,122,.10); }
.rental-prop-pick input { margin: 0; }
.rental-box-preview {
  display: flex; flex-direction: column;
  gap: 8px;
}
.rental-mini-card {
  background: rgba(0,0,0,.20);
  border: 1px solid var(--border);
  border-left: 3px solid #9263a7;
  border-radius: 6px;
  padding: 8px 10px;
}
.rmc-head {
  font: 13px 'DM Mono',monospace;
  margin-bottom: 4px;
  display: flex; align-items: center; gap: 6px;
}
.rmc-head strong { color: var(--accent); }
.rmc-head .om-hint { color: var(--text-dim); font-size: 11px; }
.rmc-edit-btn {
  margin-left: auto;
  padding: 3px 8px;
  font-size: 10px;
  border-radius: 4px;
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
}
.rmc-edit-btn:hover { border-color: var(--accent); color: var(--accent); }

/* Theme toggle button in the header */
.theme-toggle {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  width: 32px; height: 32px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  margin-right: 8px;
  padding: 0;
  transition: .15s;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); }
/* ── Print picker ─────────────────────────────────
   Pick several propellers and print them as one PDF, a page each. The list
   sits beside the preview so the sheaf can be built while watching it.

   `psel-`, not `pp-`: the order modal's pitch picker already owns `.pp-row`
   and `.pp-btn`, and a second meaning for the same class is how the stopwatch
   once lent its border to a mock-up. */
/* Two columns when they fit, stacked when they do not — decided by WRAPPING,
   not by a viewport media query.
   Erik, 2026-09-30: "list väga katki arvutis". The shared modal card is 520px
   wide; the 100mm sheet takes 378 of them, which left the list about 88px for
   a five-column grid. The @media (max-width: 820px) below could never save it,
   because it asks how wide the WINDOW is and the thing running out of room is
   the modal. On a 1400px desktop it therefore stayed two-column and crushed.
   Both columns now carry a flex-basis they will not go under, so they wrap
   instead of squeezing, at any card width. */
.psel-wrap { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.psel-side { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
/* Basis, not `auto`: with auto the column sized itself to the longest line of
   the hint underneath the sheet and stole the width from the list. */
.psel-main { flex: 0 1 380px; min-width: 0; display: flex; flex-direction: column; gap: 10px;
  align-items: center; max-width: 100%; }
.psel-main > .om-hint { align-self: stretch; }
/* Shaped 100:150 so what is on screen is what comes out of the printer. */
#op-frame { width: 100mm; max-width: 100%; aspect-ratio: 100 / 150;
  border: 1px solid var(--border); border-radius: 6px; background: #fff; }
.psel-list { max-height: 52vh; overflow-y: auto; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 8px; background: var(--bg-card); }
.psel-row { display: grid;
  grid-template-columns: auto minmax(0,1fr) auto minmax(0,1.1fr) auto auto;
  gap: 8px; align-items: baseline; padding: 6px 9px; cursor: pointer; font-size: 12.5px;
  border-bottom: 1px solid var(--border); }
/* `display: grid` above beats the browser's own `[hidden] { display: none }`
   — an author rule always does — so setting .hidden in JS did nothing and the
   list showed all 805 rows however it was filtered. Anything with an explicit
   display needs this line to be hideable at all. */
.psel-row[hidden] { display: none; }
.psel-row:last-child { border-bottom: none; }
.psel-row:hover { background: rgba(128,128,128,.10); }
.psel-row:has(.psel-cb:checked) { background: rgba(26,108,122,.14); }
.psel-serial { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.psel-cls { color: var(--accent); font-size: 11.5px; white-space: nowrap; }
.psel-who { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.psel-date { color: var(--text-dim); font-size: 11px; white-space: nowrap; }
/* Already sent to the printer. Green and quiet — it answers "did I do this
   one?" at a glance without competing with the serial. */
.psel-printed { font-size: 10.5px; color: #6fd39b; white-space: nowrap; }
.psel-printed[hidden] { display: none; }
.psel-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.psel-count { font-size: 11.5px; color: var(--text-muted); margin-left: auto; }
.psel-allbox { display: flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 11.5px; color: var(--text-muted); }
.psel-empty { padding: 14px 10px; font-size: 12px; color: var(--text-dim); text-align: center; }
/* The print modal needs the room the shared 520px card does not have. Added to
   the card while this modal is open and taken off again on close. */
.modal-card.print-modal-card { max-width: 860px; }
/* On a phone the sheet and the list are stacked by the wrap above anyway; this
   only keeps the list from eating the screen. */
@media (max-width: 820px) {
  .psel-main { align-self: stretch; }
  .psel-list { max-height: 34vh; }
}


/* Language switcher (client + reseller only) */
.lang-switcher {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-muted);
  height: 32px;
  border-radius: 8px;
  font: 12px 'DM Sans',sans-serif;
  padding: 0 8px;
  margin-right: 8px;
  cursor: pointer;
  max-width: 140px;
}
.lang-switcher:hover { border-color: var(--accent); color: var(--accent); }
.lang-switcher option { color: #000; background: #fff; }
.rmc-meta {
  display: flex; flex-wrap: wrap; gap: 6px 10px;
  margin: 4px 0 6px;
  font-size: 11px;
}
.rmc-pitches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(54px, 1fr));
  gap: 3px;
}
.rmc-pitch-cell {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 4px;
  text-align: center;
}
.rmc-pitch-cell.empty { opacity: .35; }
.rmc-pitch-r {
  font: 700 8px 'DM Sans',sans-serif;
  letter-spacing: .5px;
  color: var(--text-dim);
}
.rmc-pitch-v {
  font: 11px 'DM Mono',monospace;
  color: var(--text);
}
@media (max-width: 720px) {
  .cal-days { grid-auto-rows: minmax(64px, 1fr); }
  .cal-daynum { font-size: 11px; }
  .cal-evt { font-size: 9px; padding: 1px 4px; }
  .cal-title { min-width: 120px; font-size: 14px; }
}

/* "Show more / Show less" toggle below collapsible lists */
.activity-toggle-wrap { display: flex; justify-content: center; padding: 8px 0 2px; }
.link-btn {
  background: transparent;
  border: none;
  color: var(--accent);
  font-size: 13px;
  cursor: pointer;
  padding: 4px 10px;
  border-radius: 6px;
}
.link-btn:hover { background: rgba(26,108,122,.12); color: var(--text); }

/* Modification history panel in order edit modal */
.mod-history {
  background: rgba(0,0,0,.25);
  border-radius: 8px;
  padding: 6px;
  max-height: 240px;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 3px;
}
.mod-row {
  display: grid;
  grid-template-columns: 110px 80px 100px 1fr 16px 1fr;
  gap: 8px;
  align-items: center;
  padding: 5px 8px;
  background: var(--bg-card);
  border-radius: 5px;
  font-size: 11px;
}
.mod-when  { font-family: 'DM Mono',monospace; color: var(--text-dim); }
.mod-who   { color: var(--text-muted); }
.mod-field { color: var(--accent); font-weight: 600; }
.mod-from  { color: var(--text-dim); text-decoration: line-through; font-family: 'DM Mono',monospace; }
.mod-arrow { color: var(--text-dim); text-align: center; }
.mod-to    { color: var(--text); font-family: 'DM Mono',monospace; }

/* Grouped mod-history (one entry per save, multiple changes inside) */
.mod-group {
  background: var(--bg-card);
  border-radius: 6px;
  padding: 6px 8px;
  display: flex; flex-direction: column;
  gap: 3px;
}
.mod-group-head {
  display: flex; gap: 10px;
  font-size: 10px;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 3px;
}
.mod-group-head .mod-count {
  margin-left: auto;
  color: var(--accent);
  font-weight: 600;
}
.mod-row-line {
  display: grid;
  grid-template-columns: 100px 1fr 16px 1fr;
  gap: 8px;
  align-items: center;
  font-size: 11px;
  padding: 2px 4px;
}

/* Client detail — rich prop cards */
.client-prop {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 6px;
}
.cp-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 6px;
}
.cp-title {
  font-family: 'DM Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
}
.cp-chips {
  display: flex; gap: 4px; flex-wrap: wrap;
  flex: 1;
}
.cp-meta {
  display: flex; flex-wrap: wrap;
  gap: 4px 14px;
  font-size: 12px;
  color: var(--text-muted);
}
.cp-rider {
  margin-top: 4px;
  font-size: 11px; color: var(--text-dim);
}
.btn-edit-prop,
.row-copy-btn {
  font-size: 10px !important;
  padding: 4px 8px !important;
  letter-spacing: 1px;
  margin-left: 4px;
}

.empty-state {
  padding: 60px 20px; text-align: center;
  color: var(--text-dim); font-size: 13px;
}
.spinner {
  display: inline-block; width: 16px; height: 16px;
  border: 2px solid var(--border); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .8s linear infinite;
  vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Shop tab ─────────────────────────────────────────────────── */
.row-main    { flex: 1 1 220px; min-width: 0; }
.row-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; flex-shrink: 0; }
/* Narrow screens: rows + sub-sub-tab heads stack instead of pushing content off-screen. */
@media (max-width: 780px) {
  .row { flex-wrap: wrap; }
  .row-actions { width: 100%; justify-content: flex-start; }
  .search-bar { flex-wrap: wrap; }
  .search-bar > .search-input { min-width: 0; }
}
.muted       { color: var(--text-dim); }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  border: 1px solid var(--border);
  background: rgba(255,255,255,.04);
  color: var(--text-muted);
}
.badge-ok    { background: rgba(61,170,107,.15); border-color: rgba(61,170,107,.4); color: var(--green); }
.badge-muted { background: rgba(255,255,255,.04); color: var(--text-dim); }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px 14px;
  align-items: end;
}
.form-grid label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--text-dim);
}
.form-grid label input,
.form-grid label select {
  background: var(--bg-card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 9px;
  font: 13px 'DM Sans',sans-serif;
  outline: none;
  transition: .15s;
}
.form-grid label input:focus,
.form-grid label select:focus { border-color: var(--accent); }

.inv-line input {
  background: var(--bg-card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 9px;
  font: 13px 'DM Sans',sans-serif;
}

/* Shop product editor modal */
.sp-tabs {
  display: flex; gap: 4px;
  border-bottom: 1px solid var(--border);
  margin: -10px -4px 14px;
  padding: 0 4px;
}
.sp-tab {
  background: transparent; border: 0; color: var(--text-muted);
  padding: 10px 16px;
  font: 600 11px 'DM Sans',sans-serif;
  letter-spacing: 1.5px; text-transform: uppercase;
  cursor: pointer; border-bottom: 2px solid transparent;
  transition: .15s;
}
.sp-tab:hover { color: var(--text); }
.sp-tab.active { color: var(--text); border-bottom-color: var(--accent); }
.sp-tab-panel[hidden] { display: none; }

.sp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px 14px;
  margin-bottom: 8px;
}
.sp-grid .m-field select {
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 7px;
  padding: 9px 12px;
  color: var(--text);
  font: 13px 'DM Sans',sans-serif;
  outline: none;
  cursor: pointer;
}
.sp-grid .m-field select:focus { border-color: var(--accent); }

.sp-options { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.sp-options-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
.sp-opt-group {
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 8px;
  background: var(--bg-darker);
  transition: .12s;
}
.sp-opt-group.on { border-color: rgba(26,108,122,.5); }
.sp-opt-toggle {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  font-weight: 600;
}
.sp-opt-toggle input { accent-color: var(--accent); cursor: pointer; }
.sp-opt-toggle .muted { font-weight: 400; font-size: 11px; }
.sp-opt-group-rm {
  margin-left: auto;
  background: transparent; border: 1px solid var(--border);
  color: var(--text-dim);
  padding: 4px 9px; font-size: 10px; letter-spacing: 1px;
  border-radius: 5px; cursor: pointer;
}
.sp-opt-group-rm:hover { color: #f88; border-color: #c44; }
.sp-opt-group.custom { border-color: rgba(252,167,38,.3); }
/* Why the propeller options are not on the list for this product. Reads as a
   sentence, not a warning: nothing is wrong, the product is just not a prop. */
.sp-opt-note {
  margin-bottom: 10px; padding: 9px 12px;
  border: 1px dashed var(--border); border-radius: 8px;
  font-size: 11.5px; line-height: 1.5;
}
.sp-opt-body {
  padding: 0 12px 12px;
  display: flex; flex-direction: column; gap: 8px;
}
.sp-unit-field { max-width: 130px; }
.sp-opt-rows { display: flex; flex-direction: column; gap: 5px; }
/* Flex rather than a grid: a row carries the value, optionally a price
   modifier, optionally a photo picker, then default + remove. Fixed columns
   would need a rule per combination and still overflow on a phone. */
.sp-opt-row {
  display: flex; flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.sp-opt-row .sp-opt-val { flex: 1 1 120px; min-width: 0; }
.sp-opt-row .sp-opt-mod { flex: 0 1 100px; min-width: 0; }
.sp-opt-row .sp-opt-default { flex: 0 0 auto; }
.sp-opt-row .sp-opt-rm { flex: 0 0 28px; margin-left: auto; }

/* Per-value gallery photo: thumbnail plus a picker listing the product's own
   images. Stores the url, so reordering the gallery cannot repoint it. */
.sp-opt-img { display: flex; align-items: center; gap: 5px; flex: 0 1 auto; }
.sp-opt-img > img,
.sp-opt-img > i {
  width: 28px; height: 28px; flex: 0 0 28px;
  border-radius: 5px; border: 1px solid var(--border);
  object-fit: cover; background: var(--bg-mid); display: block;
}
.sp-opt-img > select {
  background: var(--bg-mid); border: 1.5px solid var(--border);
  border-radius: 6px; padding: 6px 7px; color: var(--text);
  font-size: 12px; max-width: 120px; outline: none;
}
.sp-opt-img > select:focus { border-color: var(--accent); }
.sp-opt-img.gone > img, .sp-opt-img.gone > select { border-color: var(--red); }
.sp-opt-img.empty {
  font-size: 11px; color: var(--text-dim); font-style: italic;
  white-space: nowrap; align-self: center;
}

.sp-opt-row input[type="text"],
.sp-opt-row input[type="number"] {
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 6px;
  padding: 7px 10px;
  color: var(--text);
  font: 13px 'DM Mono', monospace;
  outline: none;
}
.sp-opt-row input:focus { border-color: var(--accent); }
.sp-opt-default {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--text-muted);
  letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer;
}
.sp-opt-default input { accent-color: var(--accent); cursor: pointer; }
.sp-opt-rm {
  background: transparent; border: 1px solid var(--border);
  color: var(--text-dim);
  width: 28px; height: 28px;
  border-radius: 6px;
  font-size: 16px; line-height: 1;
  cursor: pointer;
}
.sp-opt-rm:hover { border-color: #c44; color: #f88; }

.sp-image-row { display: flex; gap: 14px; align-items: stretch; }
.sp-image-preview {
  width: 140px; height: 140px;
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; flex-shrink: 0;
}
.sp-image-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.sp-image-empty { color: var(--text-dim); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; }
.sp-image-controls {
  display: flex; flex-direction: column; gap: 6px; flex: 1;
}
.sp-image-controls input[type="text"] {
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 7px;
  padding: 9px 12px;
  color: var(--text);
  font: 13px 'DM Sans',sans-serif;
  outline: none;
}
.sp-image-controls input[type="text"]:focus { border-color: var(--accent); }

/* Multi-image gallery */
.sp-gallery {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
}
.sp-gallery-empty { color: var(--text-dim); font-size: 12px; padding: 12px; grid-column: 1/-1; text-align: center; border: 1.5px dashed var(--border); border-radius: 8px; }
.sp-gallery-tile {
  position: relative; aspect-ratio: 1/1;
  background: var(--bg-mid); border: 1.5px solid var(--border); border-radius: 8px;
  overflow: hidden;
}
.sp-gallery-tile.cover { border-color: rgba(26,108,122,.6); }
.sp-gallery-tile img { width: 100%; height: 100%; object-fit: contain; }
.sp-gallery-badge {
  position: absolute; top: 4px; left: 4px;
  background: var(--accent); color: #fff;
  font-size: 9px; font-weight: 700; letter-spacing: 1px;
  padding: 2px 6px; border-radius: 3px;
}
.sp-gallery-tools {
  position: absolute; right: 4px; bottom: 4px;
  display: flex; gap: 3px; opacity: 0; transition: .12s;
}
.sp-gallery-tile:hover .sp-gallery-tools { opacity: 1; }
.sp-gallery-btn {
  background: rgba(0,0,0,.65); border: 0; color: #fff;
  width: 22px; height: 22px; font-size: 12px; line-height: 1;
  border-radius: 4px; cursor: pointer;
}
.sp-gallery-btn:hover:not(:disabled) { background: var(--accent); }
.sp-gallery-btn:disabled { opacity: .35; cursor: default; }

/* Variants editor */
.sp-variant-row {
  border: 1px solid var(--border); border-radius: 8px;
  padding: 12px; margin-bottom: 8px; background: var(--bg-darker);
  display: flex; flex-direction: column; gap: 8px;
}
.sp-variant-fields { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 10px; align-items: end; }
.sp-variant-fields .m-check { grid-column: 1/-1; }
.sp-variant-rm { align-self: flex-start; font-size: 10px; padding: 6px 10px; }
.sp-variant-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 6px;
}
.sp-variant-off { opacity: .55; }
.sp-variant-off .sp-variant-fields,
.sp-variant-off .sp-image-row { filter: saturate(.4); }

.row-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--text-muted); cursor: pointer;
  padding: 7px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  user-select: none; transition: .12s;
}
.row-toggle:hover { border-color: var(--accent); color: var(--text); }
.row-toggle input { accent-color: var(--accent); cursor: pointer; }
.row-toggle:has(input:checked) { border-color: rgba(26,108,122,.5); color: var(--text); }

.cat-thumb {
  width: 40px; height: 40px;
  border-radius: 6px; object-fit: cover;
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.cat-thumb-empty {
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-mid); color: var(--text-dim); font-size: 14px;
}
/* Category tree rows — depth colors + click-to-expand affordance. */
.cat-row {
  cursor: pointer;
  padding-left: calc(10px + var(--cat-depth, 0) * 18px);
  border-left: 3px solid;
}
.cat-row[data-depth="0"] { border-left-color: var(--accent); }
.cat-row[data-depth="1"] { border-left-color: rgba(26,108,122,.55); background: rgba(255,255,255,.015); }
.cat-row[data-depth="2"] { border-left-color: rgba(26,108,122,.35); background: rgba(255,255,255,.03);  }
.cat-row[data-depth="3"] { border-left-color: rgba(26,108,122,.2);  background: rgba(255,255,255,.045); }
.cat-chev {
  background: transparent; border: 0; cursor: pointer;
  color: var(--text-muted);
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px;
  transition: transform .15s;
  flex-shrink: 0; padding: 0;
}
.cat-chev.open { transform: rotate(90deg); color: var(--accent); }
.cat-chev:hover { color: var(--text); }
.cat-chev-spacer { cursor: default; opacity: 0; }

.rshop-lock { margin-right: 6px; opacity: .75; font-size: 13px; }
.btn-ghost[disabled] { opacity: .35; cursor: not-allowed; }

/* Expandable shop-order card. Allow the detail to wrap below the head row. */
.shop-order-row { flex-wrap: wrap; align-items: flex-start; }
.shop-order-row .row-main { flex: 1 1 60%; min-width: 0; }
.shop-order-row .row-actions { flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; }
.shop-order-row.open { background: var(--bg-darker); }
.shop-order-head { padding: 4px 0; }
.shop-order-detail {
  flex-basis: 100%;
  width: 100%;
  margin: 8px -14px -11px;       /* bleed to the card edges */
  padding: 12px 14px 14px;
  border-top: 1px solid var(--border);
  background: rgba(0,0,0,.18);
  font-size: 12px;
}
.shop-order-items {
  width: 100%; border-collapse: collapse;
  margin-bottom: 10px;
  font-family: 'DM Mono', monospace; font-size: 12px;
}
.shop-order-items th, .shop-order-items td {
  text-align: left; padding: 5px 9px;
  border-bottom: 1px solid var(--border);
}
.shop-order-items th {
  color: var(--text-dim); font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase;
  font-weight: 600; font-family: 'DM Sans', sans-serif;
}
.shop-order-buyer { color: var(--text-muted); line-height: 1.5; }
.shop-order-buyer strong { color: var(--text); }

.rshop-catalog-row { gap: 14px; }
.rshop-cat-thumb {
  width: 48px; height: 48px;
  background: var(--bg-mid);
  border: 1px solid var(--border);
  border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; flex-shrink: 0;
  color: var(--text-dim); font-size: 14px;
}
.rshop-cat-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.rshop-cat-controls { display: flex; align-items: center; gap: 14px; flex-shrink: 0; }
.rshop-cat-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; cursor: pointer; color: var(--text-muted); }
.rshop-cat-toggle input { accent-color: var(--accent); cursor: pointer; }
.rshop-cat-price { display: flex; flex-direction: column; gap: 3px; }
.rshop-cat-price > span { font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--text-dim); }
.rshop-cat-price input {
  background: var(--bg-mid);
  border: 1.5px solid var(--border);
  border-radius: 6px;
  padding: 6px 9px;
  color: var(--text);
  font: 12px 'DM Mono', monospace;
  outline: none;
  max-width: 100px;
}
.rshop-cat-price input:focus { border-color: var(--accent); }

/* ── Lab → Test analysis (AiM .xrk analyser) ───────────────────── */
.xrk-drop {
  display: block; cursor: pointer;
  border: 1.5px dashed var(--border-strong);
  border-radius: 10px; padding: 26px 14px; text-align: center;
  background: var(--bg-mid); transition: .15s;
}
.xrk-drop:hover, .xrk-drop.drag { border-color: var(--accent); background: var(--bg-card); }
.xrk-drop-title { font-weight: 600; font-size: 15px; }
.xrk-drop-title code { background: var(--bg-card); padding: 1px 6px; border-radius: 4px; }
.xrk-drop-sub { color: var(--text-muted); font-size: 12px; margin-top: 4px; }

.xrk-row { cursor: pointer; }
.xrk-row:hover { background: var(--bg-mid); }
.xrk-del {
  margin-left: 8px; padding: 2px 8px; line-height: 1.4;
  font-size: 12px; min-width: 0;
}

.xrk-canvas { width: 100%; display: block; }

.xrk-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 10px;
}
.xrk-stat {
  background: var(--bg-mid); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 12px; text-align: center;
}
.xrk-stat-v { font-size: 18px; font-weight: 700; }
.xrk-stat-k { font-size: 11px; color: var(--text-muted); margin-top: 2px; }

.xrk-venue { margin-bottom: 16px; }
.xrk-venue:last-child { margin-bottom: 0; }
.xrk-venue-head {
  display: flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 15px; margin-bottom: 8px;
}
.xrk-infer {
  font-size: 12px; color: var(--text-muted);
  padding: 8px 10px; margin-top: 6px;
  background: var(--bg-mid); border-radius: 6px;
  border-left: 3px solid var(--gold);
}

.xrk-prop-setup {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.xrk-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; }
.xrk-field > span:first-child { color: var(--text-muted); }
.xrk-field select, .xrk-field input {
  background: var(--bg-mid); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 7px 9px; font-size: 14px; width: 100%;
}
.xrk-field .gear-pair { display: flex; align-items: center; gap: 6px; }
.xrk-field .gear-pair input { width: 100%; }
.xrk-field .gear-sep { color: var(--text-muted); }
.xrk-field #xrk-pitch-unit { flex-shrink: 0; min-width: 42px; }

.xrk-controls {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  margin-top: 10px; font-size: 12px;
}
.xrk-ctl { display: flex; align-items: center; gap: 6px; color: var(--text-muted); }
.xrk-ctl select {
  background: var(--bg-mid); color: var(--text);
  border: 1px solid var(--border); border-radius: 6px; padding: 5px 8px; font-size: 13px;
}
.xrk-ctl-check { cursor: pointer; }
.xrk-sector-row { cursor: pointer; }
.xrk-sector-row:hover { background: var(--bg-mid); }

/* Lap list (left) + map (right) */
.xrk-maprow { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.xrk-laplist {
  flex: 0 0 132px; display: flex; flex-direction: column; gap: 5px;
  max-height: 600px; overflow-y: auto;
}
.xrk-mapwrap { flex: 1 1 420px; min-width: 0; }
.xrk-overlay-panel { display: flex; flex-direction: column; gap: 4px; margin: 8px 0 2px; max-height: 190px; overflow-y: auto; }
.xrk-overlay-panel:empty { display: none; }
.xrk-overlay-panel .xrk-ctl { gap: 6px; align-items: center; }
.xrk-ovrow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.xrk-lapchips { display: inline-flex; gap: 3px; flex-wrap: wrap; }
.xrk-lapchip { font: 11px system-ui; padding: 1px 6px; border-radius: 4px; border: 1px solid var(--border, #444); background: transparent; color: var(--text-muted, #999); cursor: pointer; }
.xrk-lapchip.on { background: var(--accent, #1a6c7a); color: #fff; border-color: var(--accent, #1a6c7a); }
.xrk-refbtn { font: 12px system-ui; padding: 0 5px; border-radius: 4px; border: 1px solid var(--border, #444); background: transparent; color: var(--text-muted, #999); cursor: pointer; flex: 0 0 auto; }
.xrk-refbtn.on { background: var(--accent, #1a6c7a); color: #fff; border-color: var(--accent, #1a6c7a); }
.xrk-ovrow.ovref { box-shadow: inset 0 0 0 1px var(--accent, #1a6c7a); border-radius: 6px; padding: 2px 4px; }
.xrk-ov-sw { display: inline-block; width: 12px; height: 12px; border-radius: 3px; flex: 0 0 auto; vertical-align: middle; }
.xrk-reco { font-size: 14px; padding: 8px 10px; border-radius: 8px; background: var(--bg-mid); border: 1px solid var(--border); }
.xrk-row-active { background: var(--bg-card); box-shadow: inset 0 0 0 2px var(--accent); border-radius: 7px; }
.xrk-name-input { flex:1; min-width:0; background:transparent; border:1px solid transparent; border-radius:6px; color:inherit; font:inherit; font-weight:600; padding:3px 6px; }
.xrk-name-input:hover { border-color:var(--border); }
.xrk-name-input:focus { outline:none; border-color:var(--accent); background:var(--bg-card); }
.xrk-name-input::placeholder { color:var(--text-muted,#888); font-weight:500; }
.xrk-lap-card {
  display: flex; justify-content: space-between; align-items: center; gap: 6px;
  padding: 6px 9px; border-radius: 7px; font-size: 13px;
  background: var(--bg-mid); border: 1px solid var(--border); opacity: .5;
}
.xrk-lap-card.flying { opacity: 1; cursor: pointer; }
.xrk-lap-card.flying:hover { border-color: var(--border-strong); }
.xrk-lap-card.selected { border-color: var(--accent); background: var(--bg-card); box-shadow: inset 0 0 0 1px var(--accent); }
.xrk-lap-n { color: var(--text-muted); }
.xrk-lap-t { font-weight: 600; }
@media (max-width: 560px) {
  .xrk-laplist { flex-basis: 100%; flex-direction: row; flex-wrap: wrap; max-height: none; }
  .xrk-lap-card { flex: 0 0 auto; }
}
