/* ===================================================================
    - Job Scheduler
   ===================================================================

   DESIGN NOTES

   The brand is the lightning bolt: a blue-to-violet gradient on near-black
   navy. Everything here is derived from that, not bolted onto it.

   The signature device is the switchboard. A sparky reads a breaker panel
   every working day: a row of modules on a DIN rail, each with a toggle
   position and an indicator LED you can scan in a dark plant room without
   reading a word. Job status uses that same language - the toggle position
   AND the LED colour both carry the state, so it survives being glanced at
   on a phone in the sun. The rail motif (a 2px gradient edge) marks what's
   active. That's the one place boldness is spent; everything else stays
   quiet so dense job/costing data keeps the attention.

   TOKENS
   --ink / --ink-2      base backgrounds, near-black navy
   --panel / --panel-2  raised surfaces (cards, sidebar) and their hover
   --panel-line         hairline borders on dark surfaces
   --paper / --muted    primary and secondary text
   --blue / --blue-2    the bolt gradient - signature accent
   --live / --alert     circuit live (green) / fault (red)
   --warn               scheduled-but-not-started amber

   TYPE
   Inter          UI, labels, prose
   JetBrains Mono job numbers, money, times, breaker labels - the
                  meter-readout vernacular, and it keeps figures aligned.

   NOTE ON --amber: an earlier theme was amber-accented. The variable was
   later repointed to the brand blue but hard-coded rgba(245,166,35) values
   were left behind, so "scheduled" rendered as blue text on an orange tint.
   --amber is kept as an alias of --blue so nothing breaks, and --warn is
   the real amber for scheduled states.
   =================================================================== */

@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600;700;800&display=swap');

:root {
  --ink: #F3F4F9;
  --ink-2: #EBEDF5;
  --panel: #FFFFFF;
  --panel-2: #F5F6FB;
  --panel-line: #DEE1EC;
  --panel-line-soft: #E8EAF3;
  --paper: #12142A;
  --muted: #676C87;
  --muted-2: #9498AC;

  --blue: #0A84D9;
  --blue-2: #3CC0EE;
  --blue-dim: rgba(10, 132, 217, 0.08);
  --blue-glow: rgba(10, 132, 217, 0.25);
  --bolt: linear-gradient(135deg, #0A84D9 0%, #3CC0EE 100%);

  --live: #278A65;
  --alert: #D33A40;
  --warn: #B87B0E;

  --amber: #0A84D9;
  --amber-dim: rgba(10, 132, 217, 0.08);

  --shadow-1: 0 1px 2px rgba(20, 24, 50, 0.08);
  --shadow-2: 0 4px 16px rgba(20, 24, 50, 0.10);
  --shadow-3: 0 18px 50px rgba(20, 24, 50, 0.16);
  --hover-line: #B8BDD4;
  --ghost-hover-bg: #EAECF5;
}

/* ===== Light theme =====
   Toggled from Settings (see settings.js) - sets data-theme="light" on
   <html>. The brand blue stays exactly the same in both themes (that's
   the one colour that should always read as "SparkPro" regardless of
   theme); everything else inverts. A few colours (green/red/amber) are
   nudged a shade darker than their dark-theme versions, since a colour
   that reads clearly on near-black can look washed out on white - same
   colour family, just tuned for the background it's actually sitting on. */
html[data-theme="dark"] {
  --ink: #090D1E;
  --ink-2: #0C1024;
  --panel: #141931;
  --panel-2: #1B2140;
  --panel-line: #262C4A;
  --panel-line-soft: #1E2440;
  --paper: #F2F3F8;
  --muted: #8B90AD;
  --muted-2: #656A85;

  --blue: #0A84D9;
  --blue-2: #3CC0EE;
  --blue-dim: rgba(10, 132, 217, 0.12);
  --blue-glow: rgba(10, 132, 217, 0.35);
  --bolt: linear-gradient(135deg, #0A84D9 0%, #3CC0EE 100%);

  --live: #3FB68B;
  --alert: #E5484D;
  --warn: #E8A33D;

  /* compatibility alias - see note above */
  --amber: #0A84D9;
  --amber-dim: rgba(10, 132, 217, 0.12);

  --radius: 10px;
  --radius-sm: 7px;
  --radius-lg: 14px;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-2: 0 4px 16px rgba(0, 0, 0, 0.35);
  --shadow-3: 0 18px 50px rgba(0, 0, 0, 0.5);
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --hover-line: #39406B;
  --ghost-hover-bg: #232A4E;
}

html[data-theme="light"] {
  --ink: #F3F4F9;
  --ink-2: #EBEDF5;
  --panel: #FFFFFF;
  --panel-2: #F5F6FB;
  --panel-line: #DEE1EC;
  --panel-line-soft: #E8EAF3;
  --paper: #12142A;
  --muted: #676C87;
  --muted-2: #9498AC;

  --blue: #0A84D9;
  --blue-2: #3CC0EE;
  --blue-dim: rgba(10, 132, 217, 0.08);
  --blue-glow: rgba(10, 132, 217, 0.25);
  --bolt: linear-gradient(135deg, #0A84D9 0%, #3CC0EE 100%);

  --live: #278A65;
  --alert: #D33A40;
  --warn: #B87B0E;

  --amber: #0A84D9;
  --amber-dim: rgba(10, 132, 217, 0.08);

  --shadow-1: 0 1px 2px rgba(20, 24, 50, 0.08);
  --shadow-2: 0 4px 16px rgba(20, 24, 50, 0.10);
  --shadow-3: 0 18px 50px rgba(20, 24, 50, 0.16);
  --hover-line: #B8BDD4;
  --ghost-hover-bg: #EAECF5;
}

* { box-sizing: border-box; }

/* Two more blanket safety nets, cheap and universally safe: an image
   dropped in without explicit sizing shouldn't be able to force the page
   wider than the screen, and a long unbroken string (a URL, a long SKU,
   anything with no natural word-break point) should wrap rather than push
   its container wide - overflow-wrap handles this without affecting any
   text that already wraps normally at spaces. */
img { max-width: 100%; height: auto; }
body { overflow-wrap: break-word; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Nothing on the page should ever force the whole window to scroll or
     zoom out sideways - if something inside overflows, it should clip or
     scroll within its own bounded region (like a wide table inside its
     card), never widen the page itself. */
  overflow-x: hidden;
  max-width: 100vw;
}

a { color: inherit; }

.mono, .num {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  letter-spacing: 0.01em;
  /* figures line up column-to-column - this app is full of money */
  font-variant-numeric: tabular-nums;
}

/* One visible focus ring for the whole app, keyboard only. */
:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: 4px;
}

::selection { background: var(--blue); color: #fff; }

/* Scrollbars, so they stop being bright white on a dark app */
* { scrollbar-color: var(--panel-line) transparent; scrollbar-width: thin; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--panel-line); border-radius: 6px; border: 2px solid var(--ink); }
*::-webkit-scrollbar-thumb:hover { background: #333A5E; }

/* ---------- App shell ---------- */

.app-shell {
  display: grid;
  grid-template-columns: 232px 1fr;
  min-height: 100vh;
}

.sidebar {
  background: linear-gradient(180deg, var(--panel) 0%, var(--ink-2) 100%);
  border-right: 1px solid var(--panel-line);
  padding: 20px 14px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.brand {
  display: block;
  text-decoration: none;
  padding: 4px 6px 14px;
  border-bottom: 1px solid var(--panel-line-soft);
}
.brand-logo-full { width: 100%; max-width: 168px; height: auto; display: block; }
.brand-logo-icon { display: none; width: 34px; height: 34px; border-radius: 8px; }

.nav { display: flex; flex-direction: column; gap: 2px; }

.nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.nav a svg { width: 19px; height: 19px; flex-shrink: 0; }

.nav a:hover { background: var(--blue-dim); color: var(--paper); }

/* The rail: active nav carries the bolt gradient, like the live module
   on a switchboard. */
.nav a.active {
  color: var(--paper);
  background: var(--blue-dim);
  font-weight: 600;
}
.nav a.active::before {
  content: '';
  position: absolute;
  left: 0; top: 6px; bottom: 6px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--bolt);
  box-shadow: 0 0 10px var(--blue-glow);
}

.main {
  padding: 30px 34px 72px;
  max-width: 1140px;
  min-width: 0;
}

/* ---------- Page header ---------- */

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}
.page-header h1 {
  font-size: 25px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}
.page-header p { margin: 4px 0 0; color: var(--muted); font-size: 13.5px; }

.panel-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 14px;
}

/* ---------- Cards ---------- */

.card {
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  overflow-x: auto;
  box-shadow: var(--shadow-1);
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font-family: 'Inter', sans-serif;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1;
  padding: 10px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 0.08s var(--ease), background 0.15s var(--ease),
              border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

.btn-primary {
  background: var(--bolt);
  color: #fff;
  box-shadow: 0 2px 12px rgba(10, 132, 217, 0.3);
}
.btn-primary:hover:not(:disabled) {
  box-shadow: 0 4px 20px rgba(10, 132, 217, 0.45);
}

.btn-ghost {
  background: var(--panel-2);
  border-color: var(--panel-line);
  color: var(--paper);
}
.btn-ghost:hover:not(:disabled) { background: var(--ghost-hover-bg); border-color: var(--hover-line); }

/* A quiet inline action inside a row - "restock", "remove", the star. */
.remove-btn {
  background: none;
  border: none;
  padding: 2px 5px;
  font-family: inherit;
  font-size: 12px;
  color: var(--muted);
  cursor: pointer;
  border-radius: 4px;
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
.remove-btn:hover { color: var(--paper); background: var(--panel-2); }

/* ---------- Forms ---------- */

.panel-form label,
.modal-backdrop label {
  font-size: 12.5px;
  color: var(--muted);
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 12px;
  font-weight: 500;
}

.panel-form input:not([type="checkbox"]):not([type="radio"]),
.panel-form select,
.panel-form textarea,
.modal-backdrop input:not([type="checkbox"]):not([type="radio"]),
.modal-backdrop select,
.modal-backdrop textarea {
  width: 100%;
}

.field-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

/* Job material/labour rows: an inline add form, not a stacked one. */
.add-line-form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 10px;
  padding-top: 12px;
  border-top: 1px dashed var(--panel-line);
}
.add-line-form input,
.add-line-form select { font-size: 13px; padding: 7px 9px; }
.add-line-form input[name="description"] { flex: 1; min-width: 150px; }
.add-line-form input[type="number"] { width: 84px; }

.status-select,
.lead-status-select,
.stage-status-select {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  padding: 5px 8px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.visually-hidden-input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* PIN entry: big, spaced, mono - it's a keypad, not a text field. */
.pin-input {
  font-family: 'JetBrains Mono', monospace !important;
  font-size: 26px !important;
  letter-spacing: 0.5em;
  text-align: center;
  padding: 14px 10px !important;
}

/* ---------- Filters ---------- */

.filter-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

.filter-chip {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 7px 12px;
  border-radius: 999px;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  color: var(--muted);
  cursor: pointer;
  transition: all 0.15s var(--ease);
}
.filter-chip:hover { color: var(--paper); border-color: var(--hover-line); }
.filter-chip.active {
  background: var(--blue-dim);
  border-color: var(--blue);
  color: var(--paper);
}

/* ---------- Tables ---------- */

.line-item-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.line-item-table th {
  text-align: left;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-2);
  padding: 0 10px 9px;
  border-bottom: 1px solid var(--panel-line);
  white-space: nowrap;
}
.line-item-table td {
  padding: 11px 10px;
  border-bottom: 1px solid var(--panel-line-soft);
  vertical-align: middle;
}
.line-item-table tbody tr { transition: background 0.12s var(--ease); }
.line-item-table tbody tr:hover { background: rgba(255, 255, 255, 0.02); }
.line-item-table tbody tr:last-child td { border-bottom: none; }
.line-item-table td.num,
.line-item-table th.num { text-align: right; }

tr.row-selected,
tr.row-selected:hover { background: var(--blue-dim); }
.row-check { cursor: pointer; accent-color: var(--blue); width: 15px; height: 15px; }

/* An empty table isn't a dead end - the copy tells you what to do next. */
.empty-state {
  text-align: center;
  padding: 34px 20px;
  color: var(--muted);
  font-size: 13.5px;
}
.empty-state strong {
  display: block;
  color: var(--paper);
  font-size: 14.5px;
  font-weight: 600;
  margin-bottom: 5px;
}

/* ---------- Status: breaker board (signature) ---------- */

.breaker-board { display: flex; flex-direction: column; gap: 9px; }

.breaker {
  display: grid;
  grid-template-columns: 34px 1fr;
  align-items: center;
  gap: 13px;
  padding: 11px 12px;
  background: var(--ink-2);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.breaker:hover { border-color: var(--hover-line); background: var(--panel-2); }

/* A moulded-case toggle: recessed housing, raised rocker, LED on the rocker. */
.switch {
  position: relative;
  width: 26px;
  height: 42px;
  background: #05070F;
  border-radius: 5px;
  border: 1px solid #000;
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.9),
              0 1px 0 rgba(255, 255, 255, 0.05);
}
.switch::after {
  content: '';
  position: absolute;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 3px;
  background: var(--muted);
  background-image: linear-gradient(180deg, rgba(255,255,255,0.22), rgba(0,0,0,0.22));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
  transition: top 0.22s var(--ease), background-color 0.22s var(--ease),
              box-shadow 0.22s var(--ease);
}

/* Toggle position AND colour both encode state, so it reads at a glance
   and still reads if you can't pick the colour apart in bright sun. */
.switch.state-quoted::after     { top: 3px;  background-color: var(--muted); }
.switch.state-scheduled::after  { top: 11px; background-color: var(--warn);
  box-shadow: 0 0 9px rgba(232, 163, 61, 0.55), 0 1px 3px rgba(0,0,0,0.6); }
.switch.state-progress::after   { top: 11px; background-color: var(--live);
  box-shadow: 0 0 11px rgba(63, 182, 139, 0.75), 0 1px 3px rgba(0,0,0,0.6); }
.switch.state-done::after       { top: 20px; background-color: var(--live); }
.switch.state-overdue::after    { top: 11px; background-color: var(--alert);
  box-shadow: 0 0 11px rgba(229, 72, 77, 0.75), 0 1px 3px rgba(0,0,0,0.6); }

.breaker-label { font-size: 13.5px; font-weight: 600; }
.breaker-sub {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--muted);
  margin-top: 2px;
}

.status-tag {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  padding: 3px 8px;
  border-radius: 999px;
  display: inline-block;
  border: 1px solid transparent;
}
.status-tag.quoted    { color: var(--muted); background: rgba(139,144,173,0.12); border-color: rgba(139,144,173,0.25); }
.status-tag.scheduled { color: var(--warn);  background: rgba(232,163,61,0.12); border-color: rgba(232,163,61,0.3); }
.status-tag.progress  { color: var(--live);  background: rgba(63,182,139,0.12); border-color: rgba(63,182,139,0.3); }
.status-tag.done      { color: var(--live);  background: rgba(63,182,139,0.12); border-color: rgba(63,182,139,0.3); }
.status-tag.overdue   { color: var(--alert); background: rgba(229,72,77,0.12); border-color: rgba(229,72,77,0.3); }
.status-tag.converted { color: var(--live);  background: rgba(63,182,139,0.12); border-color: rgba(63,182,139,0.3); }
.status-tag.lost      { color: var(--muted); background: rgba(139,144,173,0.12); border-color: rgba(139,144,173,0.25); }
.status-tag.pending   { color: var(--warn);  background: rgba(232,163,61,0.12); border-color: rgba(232,163,61,0.3); }
.status-tag.compliance{ color: var(--blue-2); background: var(--blue-dim); border-color: rgba(60,192,238,0.35); }

/* ---------- Job list ---------- */

.layout-split {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 20px;
  align-items: start;
}

.job-list { display: flex; flex-direction: column; gap: 10px; }

.job-card {
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.job-card:hover { border-color: var(--hover-line); box-shadow: var(--shadow-2); }

.job-summary {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 15px;
  cursor: pointer;
}
.job-summary:hover { background: rgba(255, 255, 255, 0.02); }

.job-name { font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em; }
.job-sub {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.job-due {
  margin-left: auto;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

/* Collapsed by default; toggleDetail() adds .open to expand the clicked job.
   Without the display:none here the panel rendered empty-but-present, so
   clicking a job appeared to do nothing. */
.job-detail {
  display: none;
  padding: 4px 15px 16px;
  border-top: 1px solid var(--panel-line);
  background: var(--ink-2);
}
.job-detail.open { display: block; }

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}

/* ---------- Totals ---------- */

.totals-box {
  margin-top: 14px;
  padding: 13px 15px;
  background: var(--ink);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.totals-box .row {
  display: flex;
  justify-content: space-between;
  padding: 3px 0;
  color: var(--muted);
}
.totals-box .row.grand {
  color: var(--paper);
  font-weight: 700;
  font-size: 15px;
  border-top: 1px solid var(--panel-line);
  margin-top: 7px;
  padding-top: 9px;
}

/* ---------- Purchase orders ---------- */

.po-summary {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 15px;
  cursor: pointer;
}
.po-number {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--paper);
}
.po-sub { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.po-total {
  margin-left: auto;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
/* Collapsed by default; the .open class expands it. Reused by purchase
   orders, quotes and the suppliers list - all three toggle .po-detail.open. */
.po-detail {
  display: none;
  padding: 14px 15px 16px;
  border-top: 1px solid var(--panel-line);
  background: var(--ink-2);
}
.po-detail.open { display: block; }
.po-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.recv-qty, .recv-cost { width: 80px !important; font-size: 13px !important; }

/* ---------- Modals ---------- */

.modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 16, 0.72);
  backdrop-filter: blur(3px);
  z-index: 100;
  padding: 20px;
  overflow-y: auto;
}
.modal-backdrop.open {
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.modal {
  width: 100%;
  max-width: 520px;
  margin: auto;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius-lg);
  padding: 22px 24px;
  box-shadow: var(--shadow-3);
  animation: modal-in 0.16s var(--ease);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 9px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--panel-line);
}

/* ---------- Drop zone ---------- */

.drop-zone {
  border: 2px dashed var(--panel-line);
  border-radius: var(--radius);
  padding: 34px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 13.5px;
  cursor: pointer;
  background: var(--ink-2);
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.drop-zone:hover { border-color: var(--hover-line); }
.drop-zone.dragover {
  border-color: var(--blue);
  background: var(--blue-dim);
  color: var(--paper);
}

/* ---------- Progress ---------- */

.progress-track {
  height: 6px;
  background: var(--ink);
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid var(--panel-line);
}
.progress-bar {
  height: 100%;
  background: var(--bolt);
  border-radius: 999px;
  transition: width 0.35s var(--ease);
}

/* ---------- Check-in ---------- */

.checkin-box {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 13px 15px;
  background: var(--ink);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  margin-bottom: 14px;
}
.checkin-timer {
  font-family: 'JetBrains Mono', monospace;
  font-size: 21px;
  font-weight: 700;
  color: var(--live);
  font-variant-numeric: tabular-nums;
}
.checkin-meta { font-size: 12px; color: var(--muted); }

/* ---------- Notes ---------- */

.notes-list { display: flex; flex-direction: column; gap: 8px; }
.note-row {
  padding: 9px 12px;
  background: var(--ink);
  border: 1px solid var(--panel-line-soft);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.note-time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--muted-2);
  margin-top: 3px;
}

/* ---------- Photos ---------- */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 8px;
}
.photo-thumb {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--panel-line);
  cursor: pointer;
  transition: transform 0.15s var(--ease), border-color 0.15s var(--ease);
}
.photo-thumb:hover { transform: scale(1.03); border-color: var(--blue); }

/* ---------- Kits ---------- */

.kit-item-desc { flex: 1; font-size: 13px; }
.kit-item-qty,
.kit-item-cost {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.item-text { font-size: 13.5px; }

/* ---------- Map ---------- */

.map-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
}

/* ---------- Auth pages ---------- */

body:has(.auth-card) {
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: 24px;
  /* the bolt, thrown across the backdrop */
  background:
    radial-gradient(900px 500px at 50% -10%, rgba(10, 132, 217, 0.16), transparent 70%),
    radial-gradient(600px 400px at 100% 100%, rgba(60, 192, 238, 0.10), transparent 70%),
    var(--ink);
}

.auth-card {
  width: 100%;
  max-width: 384px;
  margin: 40px auto;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: 16px;
  padding: 32px 30px;
  box-shadow: var(--shadow-3);
  text-align: center;
  position: relative;
  overflow: hidden;
}
/* live rail across the top of the card */
.auth-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--bolt);
}

.auth-logo { width: 156px; max-width: 70%; height: auto; margin: 4px auto 18px; display: block; }
.auth-title { font-size: 19px; font-weight: 700; margin: 0; letter-spacing: -0.02em; }
.auth-tagline { font-size: 11.5px; color: var(--muted-2, var(--muted)); margin: 3px 0 0; text-transform: uppercase; letter-spacing: 0.06em; }
.auth-sub { font-size: 13.5px; color: var(--muted); margin: 5px 0 22px; }

.auth-form { text-align: left; }
.auth-form label {
  font-size: 12.5px;
  color: var(--muted);
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 13px;
  font-weight: 500;
}
.auth-form input { width: 100%; }

.auth-btn {
  width: 100%;
  margin-top: 8px;
  padding: 12px;
  font-family: 'Inter', sans-serif;
  font-size: 14.5px;
  font-weight: 600;
  color: #fff;
  background: var(--bolt);
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  box-shadow: 0 2px 14px rgba(10, 132, 217, 0.32);
  transition: box-shadow 0.15s var(--ease), transform 0.08s var(--ease);
}
.auth-btn:hover:not(:disabled) { box-shadow: 0 4px 22px rgba(10, 132, 217, 0.5); }
.auth-btn:active { transform: translateY(1px); }
.auth-btn:disabled { opacity: 0.55; cursor: not-allowed; }

.auth-links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
  font-size: 12.5px;
}
.auth-links a { color: var(--muted); text-decoration: none; }
.auth-links a:hover { color: var(--blue-2); }

.auth-footnote {
  font-size: 11.5px;
  color: var(--muted-2);
  margin: 20px 0 0;
  line-height: 1.45;
}

/* Errors state what happened, in the interface's voice. */
.auth-message {
  display: none;
  font-size: 12.5px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  text-align: left;
}
.auth-message.show { display: block; }
.auth-message.error {
  color: var(--alert);
  background: rgba(229, 72, 77, 0.1);
  border: 1px solid rgba(229, 72, 77, 0.3);
}
.auth-message.success {
  color: var(--live);
  background: rgba(63, 182, 139, 0.1);
  border: 1px solid rgba(63, 182, 139, 0.3);
}

/* ---------- Global form-control baseline ----------
   Inputs used to be styled only inside .modal-backdrop, so any field
   rendered anywhere else - the supplier edit form, the login page,
   anything injected into a card - fell back to the browser default: a
   white box with dark text on a dark panel.

   Colour/border/type only. Deliberately no width: several inputs (job
   material rows, filter dropdowns) size themselves and a blanket width
   would wreck those layouts. Modal and .panel-form fields get width:100%
   from their own rules. Checkboxes, radios and file inputs keep native
   rendering. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]),
select,
textarea {
  background: var(--ink);
  border: 1px solid var(--panel-line);
  color: var(--paper);
  border-radius: var(--radius-sm);
  padding: 9px 11px;
  font-size: 14px;
  font-family: 'Inter', sans-serif;
  box-sizing: border-box;
  max-width: 100%;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-dim);
}

input::placeholder,
textarea::placeholder { color: var(--muted-2); }

select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238B90AD' d='M6 8.5L2 4.5h8z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 30px;
}

/* ---------- Motion ---------- */

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

/* ---------- Schedule ---------- */

.day-strip {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.day-chip {
  flex: 0 0 auto;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  padding: 10px 14px;
  text-align: center;
  cursor: pointer;
  min-width: 58px;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.day-chip:hover { border-color: var(--hover-line); }
.day-chip .dow {
  font-size: 10.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 500;
}
.day-chip .num {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 16px;
  margin-top: 2px;
}
.day-chip.selected {
  border-color: var(--blue);
  background: var(--blue-dim);
  box-shadow: 0 0 0 1px var(--blue-dim);
}
.day-chip.selected .num { color: var(--blue-2); }

/* Today is marked by the type, not another colour - the selected chip
   already owns the accent, and two competing highlights read as noise. */
.day-chip.today .dow { color: var(--paper); font-weight: 700; }

.day-chip .dot {
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--live);
  margin: 4px auto 0;
  box-shadow: 0 0 5px rgba(63, 182, 139, 0.8);
}

.event-list { display: flex; flex-direction: column; gap: 2px; }

.event-row {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 14px;
  padding: 12px 8px;
  border-radius: var(--radius-sm);
  border-bottom: 1px solid var(--panel-line-soft);
  transition: background 0.12s var(--ease);
}
.event-row:hover { background: rgba(255, 255, 255, 0.02); }
.event-row:last-child { border-bottom: none; }

.event-time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}
.event-title { font-weight: 600; font-size: 14.5px; letter-spacing: -0.01em; }
.event-meta { font-size: 12.5px; color: var(--muted); margin-top: 3px; }

/* Tables inside a card need room before they start scrolling - but only
   above phone width. On a phone the table should shrink to fit instead
   (smaller font/padding, see the max-width:700px rule below), since
   forcing 480px on a 375px screen guarantees a sideways scroll every time. */
@media (min-width: 701px) {
  .card .line-item-table { min-width: 480px; }
}

/* ---------- Tablet / iPad portrait: icon rail, no labels ---------- */

@media (max-width: 900px) and (min-width: 641px) {
  .app-shell { grid-template-columns: 74px 1fr; }
  .sidebar { padding: 16px 10px; align-items: center; }
  .brand { padding: 0 0 12px; border-bottom: none; }
  .brand-logo-full { display: none; }
  .brand-logo-icon { display: block; margin: 0 auto; }
  .nav a { justify-content: center; padding: 12px; }
  .nav-label { display: none; }
  .main { padding: 24px 20px 60px; }
}

@media (max-width: 900px) {
  .layout-split { grid-template-columns: 1fr; }
}

/* ---------- Mobile: hamburger + slide-out sidebar ---------- */

.hamburger-btn {
  display: none;
  position: fixed;
  top: 12px; left: 12px;
  z-index: 70;
  width: 42px; height: 42px;
  align-items: center;
  justify-content: center;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius-sm);
  color: var(--paper);
  cursor: pointer;
  box-shadow: var(--shadow-2);
}
.hamburger-btn svg { width: 20px; height: 20px; }

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 16, 0.6);
  backdrop-filter: blur(2px);
  z-index: 55;
}
.sidebar-backdrop.open { display: block; }

@media (max-width: 640px) {
  body { font-size: 15px; }

  .app-shell { grid-template-columns: 1fr; display: block; }
  .hamburger-btn { display: flex; }

  .sidebar {
    position: fixed;
    top: 0; bottom: 0; left: 0;
    width: 250px;
    max-width: 80vw;
    height: 100vh;
    z-index: 60;
    transform: translateX(-100%);
    transition: transform 0.22s var(--ease);
    box-shadow: 6px 0 34px rgba(0, 0, 0, 0.5);
    overflow-y: auto;
  }
  .sidebar.mobile-open { transform: translateX(0); }

  .brand { padding: 44px 6px 14px; }
  .nav { flex-direction: column; gap: 2px; width: auto; }

  .main { padding: 64px 16px 48px; max-width: 100%; }

  .page-header h1 { font-size: 21px; }
  .layout-split { grid-template-columns: 1fr; gap: 16px; }
  .field-pair { grid-template-columns: 1fr; }

  .card { padding: 14px 14px; border-radius: var(--radius); }
  .modal { padding: 18px 16px; }
  .modal-backdrop { padding: 12px; }

  /* Touch targets: a thumb in a van, not a mouse. */
  .btn { padding: 11px 15px; }
  .po-actions .btn,
  .modal-actions .btn { flex: 1; }

  /* Tables: shrink to fit the screen instead of forcing a fixed minimum
     width (that guaranteed a sideways scroll on every table). Most 3-5
     column tables now fit without any scrolling at all; anything still too
     wide (lots of columns) scrolls within its own card, never the page. */
  .line-item-table { min-width: 0; width: 100%; font-size: 11.5px; }
  .line-item-table th { padding: 0 6px 7px; font-size: 8.5px; }
  .line-item-table td { padding: 8px 6px; }

  /* Any row of controls that was designed for a wide screen should wrap
     instead of overflowing - a blanket safety net for the many small
     toolbars/filter rows across the app that assumed desktop width. */
  .filter-row, .cal-toolbar, .add-line-form, .job-action-bar,
  .modal-actions { flex-wrap: wrap; }

  /* Several pages put their header action buttons in a plain inline
     "display:flex;gap:Npx" div with no wrap (Purchase Orders, Catalog,
     Invoices) - two buttons with real labels side by side are wider than
     a phone screen, so this was overflowing the page. Since these are
     unclassed inline styles, target them generically by attribute rather
     than hunting down every instance individually. */
  .page-header > div[style*="display:flex"],
  .page-header > div[style*="display: flex"] {
    flex-wrap: wrap;
  }
}

/* ---------- Selling: margin, sell price, supplier lookup ---------- */

/* Compact enough to sit inside a line-item row without bulking it out. */
.margin-select {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px !important;
  padding: 4px 22px 4px 7px !important;
  min-width: 96px;
  background-position: right 6px center;
}

/* The total is a field you can type in, but it should still read as the
   total - so it stays borderless until you interact with it. */
.total-edit-wrap { display: inline-flex; align-items: center; gap: 6px; }

.invoice-total-input {
  font-family: 'JetBrains Mono', monospace !important;
  font-size: 15px !important;
  font-weight: 700;
  text-align: right;
  width: 106px;
  padding: 3px 7px !important;
  background: transparent !important;
  border-color: transparent !important;
  color: var(--paper);
  font-variant-numeric: tabular-nums;
}
.invoice-total-input:hover { border-color: var(--panel-line) !important; }
.invoice-total-input:focus {
  background: var(--ink) !important;
  border-color: var(--blue) !important;
}
/* Spinners fight the right-alignment and nobody nudges a job total by 0.01. */
.invoice-total-input::-webkit-outer-spin-button,
.invoice-total-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.invoice-total-input { -moz-appearance: textfield; }

.supplier-link {
  text-decoration: none;
  color: var(--blue-2);
  font-size: 11px;
  padding: 1px 4px;
  border-radius: 3px;
  opacity: 0.75;
}
.supplier-link:hover { opacity: 1; background: var(--blue-dim); }

.webstore-panel {
  margin-top: 14px;
  padding: 13px 14px;
  background: var(--ink);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
}

/* .bq-margin is a JS hook for the quote builder's per-line margin selects;
   they take their appearance from .margin-select above. */

/* Schedule progress rows link to their job; make that obvious and keep
   the anchor from inheriting link underline/colour. */
a.breaker-link {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}
a.breaker-link:hover {
  border-color: var(--blue);
  background: var(--panel-2);
}

/* Inline job-edit form sits inside the open detail. */
.job-edit-form {
  border-top: 1px dashed var(--panel-line);
  padding-top: 6px;
  margin-top: 6px;
}

/* Count badge on a nav link (waiting supplier invoices on Purchase Orders). */
.nav-badge {
  margin-left: auto;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--alert);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  border-radius: 10px;
  box-shadow: 0 0 0 2px var(--ink);
}
/* When the sidebar is collapsed to icons, pin the badge to the icon corner. */
@media (max-width: 900px) {
  .nav a .nav-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    margin-left: 0;
    min-width: 16px;
    height: 16px;
    font-size: 10px;
    padding: 0 4px;
  }
}

/* Full-page modal variant - fills the screen like a dedicated page, giving
   room to work on big forms (quote builder, new job). Same modal markup,
   just roomier and edge-to-edge instead of a small centred card. */
.modal-backdrop.fullpage {
  padding: 0;
  background: var(--ink);
  backdrop-filter: none;
}
.modal-backdrop.fullpage.open {
  align-items: stretch;
}
.modal-backdrop.fullpage .modal {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
  border-radius: 0;
  border-left: 1px solid var(--panel-line);
  border-right: 1px solid var(--panel-line);
  min-height: 100vh;
  padding: 34px 40px 60px;
}
@media (max-width: 720px) {
  .modal-backdrop.fullpage .modal { padding: 22px 16px 50px; }
}

/* ===== Month calendar (Schedule) ===== */
.cal-grid-head {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: var(--panel);
  border-bottom: 1px solid var(--panel-line);
}
.cal-grid-head .cal-dow {
  padding: 10px 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  text-align: left;
  font-weight: 600;
}
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  /* A FIXED row height (not auto-growing) is what keeps every week the
     same size - previously a single busy day could force its whole row
     taller than the others, making the grid look stretched in some spots
     and squeezed in others. Every cell now clips at this height instead
     (see .cal-cell overflow below), relying on "+N more" for the rest. */
  grid-auto-rows: 120px;
}
.cal-cell {
  border-right: 1px solid var(--panel-line);
  border-bottom: 1px solid var(--panel-line);
  padding: 6px 7px;
  overflow: hidden;
  cursor: pointer;
  position: relative;
  transition: background 0.12s;
}
.cal-cell:nth-child(7n) { border-right: none; }
.cal-cell:hover { background: var(--panel); }
.cal-cell.other-month { opacity: 0.4; }
.cal-cell.today { background: rgba(10, 132, 217, 0.08); }
.cal-cell.selected { box-shadow: inset 0 0 0 2px var(--accent); }
.cal-cell .cal-daynum {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--paper);
  margin-bottom: 4px;
}
.cal-cell.today .cal-daynum { color: var(--accent); }
.cal-chip {
  display: block;
  font-size: 10.5px;
  padding: 2px 5px;
  border-radius: 4px;
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #fff;
}
.cal-chip.status-scheduled { background: #0A84D9; }
.cal-chip.status-progress { background: var(--warn); color: #1a1200; }
.cal-chip.status-done { background: #2E7D53; }
.cal-chip.status-overdue { background: var(--alert, #D94D4D); }
.cal-chip.status-quoted { background: #6E7482; }
.cal-more { font-size: 10px; color: var(--muted); margin-top: 1px; }
@media (max-width: 720px) {
  .cal-cell { min-height: 66px; padding: 4px; }
  .cal-chip { font-size: 9px; }
  .cal-grid-head .cal-dow { padding: 6px 4px; font-size: 9.5px; }
}

/* Scheduling mode/quick buttons (active state) */
.sched-mode-btn.active, .nj-sched-mode.active {
  background: var(--accent, #0A84D9);
  color: #fff;
  border-color: var(--accent, #0A84D9);
}
.job-schedule-btn { flex-shrink: 0; }

/* Editable calendar: add button, drag states */
.cal-daynum { display: flex; align-items: center; justify-content: space-between; }
.cal-add {
  opacity: 0;
  background: var(--accent, #0A84D9);
  color: #fff;
  border: none;
  border-radius: 4px;
  width: 18px; height: 18px;
  font-size: 13px; line-height: 1;
  cursor: pointer;
  transition: opacity 0.12s;
}
.cal-cell:hover .cal-add { opacity: 1; }
.cal-chip[draggable="true"] { cursor: grab; }
.cal-chip.dragging { opacity: 0.4; }
.cal-cell.drag-over { background: rgba(10, 132, 217, 0.18); box-shadow: inset 0 0 0 2px var(--accent, #0A84D9); }

/* ===== Mobile schedule views (Agenda / Month toggle) =====
   The 7-column month grid gets unreadable on a phone - each cell is too
   narrow for a job's time + client name. Below the breakpoint, offer three
   compact alternatives: a day-by-day agenda (default), a one-week-at-a-time
   version of the same, and a compact month grid that only shows the time
   (not the client name) per job. */
.cal-agenda { display: none; }
#calWeek { display: none; }
.cal-mobile-toggle { display: none; }
.cal-grid-mobile-card { display: none; }

@media (max-width: 700px) {
  #calGridCard { display: none; }
  .cal-mobile-toggle { display: flex; gap: 6px; margin-bottom: 12px; }
  #calAgenda { display: block; }        /* default mobile mode */
  #selectedDayCard { display: none; }   /* every mobile view already shows job info inline */

  /* JS toggles these by adding .mobile-mode-week / .mobile-mode-month to
     the page body. */
  body.mobile-mode-week #calAgenda { display: none; }
  body.mobile-mode-week #calWeek { display: block; }

  body.mobile-mode-month #calAgenda { display: none; }
  body.mobile-mode-month .cal-grid-mobile-card { display: block; }
}

.cal-mobile-toggle-btn {
  flex: 1;
  padding: 8px 0;
  border-radius: 8px;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.cal-mobile-toggle-btn.active {
  background: var(--accent, #0A84D9);
  border-color: var(--accent, #0A84D9);
  color: #fff;
}

/* Compact mobile month grid: same 7-column layout as the desktop grid, so
   the weekday header and the date cells line up exactly, but rows grow to
   fit their content instead of clipping, and each job is just a small
   coloured time badge rather than a full description. */
.cal-grid-mobile {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}
.cal-cell-mobile {
  border-right: 1px solid var(--panel-line);
  border-bottom: 1px solid var(--panel-line);
  padding: 4px 3px 6px;
  min-height: 44px;
  min-width: 0;    /* grid items default to min-width:auto, which lets long
                       badge text push a column wider than its 1fr share -
                       this is what was throwing the weekday header and the
                       date columns out of alignment. */
  overflow: hidden;
}
.cal-cell-mobile:nth-child(7n) { border-right: none; }
.cal-cell-mobile.other-month { opacity: 0.35; }
.cal-cell-mobile.today { background: rgba(10, 132, 217, 0.08); }
.cal-cell-mobile .cal-daynum-mobile {
  font-size: 11px;
  font-weight: 600;
  color: var(--paper);
  margin-bottom: 3px;
}
.cal-cell-mobile.today .cal-daynum-mobile { color: var(--accent); }
.time-badge {
  display: block;
  max-width: 100%;
  box-sizing: border-box;
  font-family: 'JetBrains Mono', monospace;
  font-size: 8.5px;
  line-height: 1.5;
  padding: 1px 3px;
  border-radius: 3px;
  margin-bottom: 2px;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.time-badge.status-scheduled { background: #0A84D9; }
.time-badge.status-progress { background: var(--warn); color: #1a1200; }
.time-badge.status-done { background: #2E7D53; }
.time-badge.status-overdue { background: var(--alert, #D94D4D); }
.time-badge.status-quoted { background: #6E7482; }

.agenda-day {
  border-bottom: 1px solid var(--panel-line);
  padding: 10px 14px;
}
.agenda-day:last-child { border-bottom: none; }
.agenda-day.today { background: rgba(10, 132, 217, 0.06); }
.agenda-day-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 2px;
}
.agenda-day.today .agenda-day-header { color: var(--accent); }
.agenda-day-header .agenda-add {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  padding: 2px 6px;
  cursor: pointer;
}
.agenda-empty {
  font-size: 11.5px;
  color: var(--muted-2);
  padding: 2px 0 4px;
}
.agenda-job {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 9px;
  border-radius: 7px;
  margin-top: 5px;
  background: var(--panel);
  font-size: 13px;
  cursor: pointer;
  border: 1px solid var(--panel-line);
}
.agenda-job:active { background: var(--ink); }
.agenda-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}
.agenda-dot.status-scheduled { background: #0A84D9; }
.agenda-dot.status-progress { background: var(--warn); }
.agenda-dot.status-done { background: #2E7D53; }
.agenda-dot.status-overdue { background: var(--alert, #D94D4D); }
.agenda-dot.status-quoted { background: #6E7482; }
.agenda-job-time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  color: var(--muted);
  flex-shrink: 0;
  min-width: 44px;
}
.agenda-job-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ===== Draft autosave restore banner ===== */
.draft-restore-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  background: rgba(232, 163, 23, 0.1);
  border: 1px solid rgba(232, 163, 23, 0.35);
  color: var(--paper);
  padding: 11px 14px;
  border-radius: 10px;
  font-size: 13.5px;
  margin-bottom: 16px;
}

/* ===== Dark/Light theme toggle (Settings) ===== */
.theme-toggle {
  display: flex;
  background: var(--ink-2);
  border: 1px solid var(--panel-line);
  border-radius: 10px;
  padding: 3px;
  gap: 3px;
}
.theme-toggle-btn {
  padding: 8px 16px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.theme-toggle-btn.active {
  background: var(--panel);
  color: var(--paper);
  box-shadow: var(--shadow-1);
}

/* ===== Device-native SMS fallback (desktop, no Messages app) ===== */
.sms-fallback-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.6);
  display: grid; place-items: center; z-index: 1000; padding: 20px;
}
.sms-fallback {
  background: var(--panel); border: 1px solid var(--panel-line);
  border-radius: 14px; padding: 20px; max-width: 460px; width: 100%;
}
.sms-fallback h3 { margin: 0 0 6px; font-size: 17px; }
.sms-fallback p { margin: 0 0 12px; font-size: 13px; color: var(--muted); }
.sms-fallback textarea {
  width: 100%; box-sizing: border-box; padding: 11px; font-size: 15px;
  background: var(--panel-2); color: var(--paper);
  border: 1px solid var(--panel-line); border-radius: 9px; resize: vertical;
}
.sms-fallback-actions {
  display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px;
}

/* ===== Texts to send panel ===== */
.msg-panel { margin-bottom: 18px; padding: 0; overflow: hidden; }
.msg-head { padding: 15px 16px 12px; border-bottom: 1px solid var(--panel-line); }
.msg-head h2 { margin: 0 0 3px; font-size: 15px; display: flex; align-items: center; gap: 9px; }
.msg-count {
  background: var(--blue); color: #fff; font-size: 11px; font-weight: 700;
  border-radius: 99px; padding: 2px 8px; min-width: 18px; text-align: center;
}
.msg-head p { margin: 0; font-size: 12.5px; color: var(--muted); }
.msg-row {
  padding: 13px 16px; border-bottom: 1px solid var(--panel-line);
  display: grid; gap: 8px; transition: opacity .3s;
}
.msg-row:last-child { border-bottom: none; }
.msg-row.msg-sent { opacity: .45; }
.msg-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px; }
.msg-label {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 8px; border-radius: 99px; border: 1px solid var(--panel-line); color: var(--muted);
}
/* --amber is aliased to blue in this codebase; real amber is --warn. */
.msg-appt .msg-label { color: var(--warn); border-color: rgba(232,163,23,.4); }
.msg-quote .msg-label { color: var(--blue); border-color: rgba(10,132,217,.4); }
.msg-invoice .msg-label { color: var(--alert, #ff5f6d); border-color: rgba(255,95,109,.4); }
.msg-contact { color: var(--muted); font-size: 12.5px; }
.msg-body {
  font-size: 13px; color: var(--muted); background: var(--panel-2);
  border: 1px solid var(--panel-line); border-radius: 8px; padding: 9px 11px; line-height: 1.45;
}
.msg-actions { display: flex; gap: 8px; justify-content: flex-end; }
@media (max-width: 640px) {
  .msg-actions { justify-content: stretch; }
  .msg-actions .btn { flex: 1; }
}

/* ===== Theme-aware wordmark =====
   The dark wordmark reads on the light default; the white one is swapped in
   only when dark mode is active. Done with a filter rather than two <img>
   tags so there is one request and no flash of the wrong mark. */
html[data-theme="dark"] img.theme-logo,
html[data-theme="dark"] img.auth-logo,
html[data-theme="dark"] img.setup-logo,
html[data-theme="dark"] img.brand-logo-full {
  filter: invert(1) hue-rotate(180deg);
}

/* The hidden attribute must beat any display rule. */
[hidden] { display: none !important; }

/* ===== Progress claims ===== */
.claims-setup { padding: 4px 0; }
.claims-setup p { margin: 0 0 8px; font-size: 13.5px; }
.claims-hint { font-size: 12.5px; color: var(--muted); margin: 4px 0 12px; }
.claims-setup-row { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.claims-setup-row label { font-size: 12.5px; color: var(--muted); flex: 1; min-width: 130px; }
.claims-setup-row input {
  display: block; width: 100%; margin-top: 5px; padding: 10px; font-size: 16px;
  box-sizing: border-box; background: var(--panel-2); color: var(--paper);
  border: 1px solid var(--panel-line); border-radius: 8px;
}

.claims-summary { margin-bottom: 16px; }
.claims-figures { display: flex; gap: 22px; flex-wrap: wrap; margin-bottom: 10px; }
.claims-figures > div { display: flex; flex-direction: column; }
.claims-figures span {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
}
.claims-figures strong { font-size: 17px; font-variant-numeric: tabular-nums; }
/* --amber is aliased to the brand blue here; real amber is --warn. */
.claims-figures .held strong { color: var(--warn); }
.claims-bar { height: 7px; border-radius: 99px; background: var(--panel-2); overflow: hidden; }
.claims-bar span { display: block; height: 100%; background: var(--blue); transition: width .3s; }

.claim-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 11px 0; border-bottom: 1px solid var(--panel-line);
}
.claim-row:last-child { border-bottom: none; }
.claim-row.status-void { opacity: .45; }
.claim-main { flex: 1; min-width: 170px; display: flex; flex-direction: column; gap: 2px; }
.claim-main strong { font-size: 13.5px; }
.claim-desc { font-size: 12.5px; color: var(--muted); }
.claim-money { text-align: right; font-variant-numeric: tabular-nums; }
.claim-money strong { display: block; font-size: 14.5px; }
.claim-ret { font-size: 11.5px; color: var(--warn); }
.claim-status {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 8px; border-radius: 99px; border: 1px solid var(--panel-line); color: var(--muted);
}
.claim-status.s-sent { color: var(--blue); border-color: var(--blue); }
.claim-status.s-paid { color: var(--live); border-color: var(--live); }
.claim-status.s-void { text-decoration: line-through; }
.claim-btns { display: flex; gap: 6px; }
.btn.sm { padding: 6px 10px; font-size: 12.5px; }

.claims-actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 14px; }
.claim-form {
  margin-top: 14px; padding: 14px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--panel-line);
}
.claim-form label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 10px; }
.claim-form input {
  display: block; width: 100%; margin-top: 5px; padding: 10px; font-size: 16px;
  box-sizing: border-box; background: var(--panel); color: var(--paper);
  border: 1px solid var(--panel-line); border-radius: 8px;
}
.claim-form-actions { display: flex; gap: 9px; justify-content: flex-end; }
.claims-empty, .claims-loading { color: var(--muted); font-size: 13.5px; padding: 12px 0; }

@media (max-width: 640px) {
  .claims-figures { gap: 14px; }
  .claim-row { align-items: flex-start; }
  .claim-btns { width: 100%; }
  .claims-actions .btn { flex: 1; }
}

/* ===== Sidebar global search (ported from PhilPro) =====
   Without this the raw SVG has no size constraint and renders enormous -
   the icon inherits the sidebar's width rather than its own. */
.sidebar-search-btn {
  display: flex; align-items: center; gap: 10px; width: 100%;
  margin: 4px 0 10px; padding: 9px 12px;
  background: var(--panel); border: 1px solid var(--panel-line);
  border-radius: var(--radius-sm, 9px); color: var(--muted);
  font-size: 13.5px; font-family: inherit; cursor: pointer; text-align: left;
  transition: border-color .15s, color .15s;
}
.sidebar-search-btn:hover { border-color: var(--blue); color: var(--paper); }
.sidebar-search-btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.sidebar-search-btn span:first-of-type { flex: 1; }
.sidebar-search-kbd {
  font-size: 10.5px; font-family: ui-monospace, monospace;
  color: var(--muted); background: var(--ink);
  border: 1px solid var(--panel-line); border-radius: 4px; padding: 1px 5px;
}
/* Collapsed sidebar: icon only. */
.sidebar.collapsed .sidebar-search-btn { justify-content: center; padding: 10px; }
.sidebar.collapsed .sidebar-search-btn span { display: none; }

/* Legal link in the app chrome. Present on every page because a customer
   should never have to hunt for the terms they agreed to. */
.app-legal-foot {
  padding: 20px; text-align: center; font-size: 12px;
  color: var(--muted); border-top: 1px solid var(--panel-line); margin-top: 28px;
}
.app-legal-foot a { color: var(--muted); text-decoration: none; }
.app-legal-foot a:hover { color: var(--blue); text-decoration: underline; }

/* Variations and staged billing on a job. Collapsed by default: most jobs
   need neither, and two always-open panels would bury the everyday fields. */
.job-extra {
  margin: 14px 0; border: 1px solid var(--panel-line);
  border-radius: 10px; background: var(--panel-2);
}
.job-extra > summary {
  padding: 12px 14px; cursor: pointer; font-size: 13.5px; font-weight: 600;
  list-style: none; display: flex; align-items: center; gap: 9px;
}
.job-extra > summary::-webkit-details-marker { display: none; }
.job-extra > summary::before { content: "▸"; color: var(--muted); font-size: 11px; }
.job-extra[open] > summary::before { content: "▾"; }
.job-extra > summary .extra-hint {
  font-weight: 400; font-size: 12px; color: var(--muted);
}
.job-extra > div { padding: 0 14px 14px; }

/* variations */
.var-total { margin-bottom: 12px; }
.var-total strong { display: block; font-size: 20px; font-weight: 700; }
.var-total span { font-size: 12.5px; color: var(--muted); }
.var-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 0; border-bottom: 1px solid var(--panel-line);
}
.var-row:last-child { border-bottom: none; }
.var-row.status-declined { opacity: .5; }
.var-main { flex: 1; min-width: 170px; display: flex; flex-direction: column; gap: 2px; }
.var-main strong { font-size: 13.5px; }
.var-desc { font-size: 12px; color: var(--muted); }
.var-value { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 14px; }
.var-status {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 8px; border-radius: 99px; border: 1px solid var(--panel-line); color: var(--muted);
}
.var-status.s-approved { color: var(--live, #2ecc71); border-color: var(--live, #2ecc71); }
.var-status.s-pending { color: var(--warn); border-color: rgba(232,163,23,.45); }
.var-btns { display: flex; gap: 6px; }
.var-form {
  margin-top: 14px; padding: 14px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--panel-line);
}
.var-form label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 10px; }
.var-form input {
  display: block; width: 100%; margin-top: 5px; padding: 9px; font-size: 16px;
  box-sizing: border-box; background: var(--panel-2); color: var(--paper);
  border: 1px solid var(--panel-line); border-radius: 8px;
}
.var-sub {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 14px 0 6px;
}
.line-row { display: grid; grid-template-columns: 1fr 70px 90px 28px; gap: 6px; margin-bottom: 6px; }
.line-row input { margin-top: 0; }
.line-row:has(.l-desc) { grid-template-columns: 1fr 90px 28px; }
.line-x {
  background: none; border: 1px solid var(--panel-line); border-radius: 7px;
  color: var(--muted); cursor: pointer; font-size: 16px; line-height: 1;
}
.var-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 14px; }
@media (max-width: 600px) {
  .line-row, .line-row:has(.l-desc) { grid-template-columns: 1fr 1fr 28px; }
}

/* Payments dialog on an invoice. */
.pay-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5);
  display: grid; place-items: center; z-index: 100; padding: 20px; }
.pay-box { background: var(--panel); border: 1px solid var(--panel-line);
  border-radius: 14px; padding: 22px; max-width: 520px; width: 100%;
  max-height: 88vh; overflow-y: auto; position: relative; }
.pay-close { position: absolute; top: 12px; right: 14px; background: none;
  border: none; color: var(--muted); font-size: 24px; line-height: 1; cursor: pointer; }
.pay-box h3 { margin: 0 0 14px; font-size: 17px; }
.pay-figures { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 16px; }
.pay-figures > div { display: flex; flex-direction: column; }
.pay-figures span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.pay-figures strong { font-size: 19px; font-variant-numeric: tabular-nums; }
.pay-figures .owing strong { color: var(--warn); }
.pay-figures .settled strong { color: var(--live, #2ecc71); }
.pay-row { display: flex; align-items: center; gap: 10px; padding: 9px 0;
  border-bottom: 1px solid var(--panel-line); font-size: 13px; }
.pay-row:last-child { border-bottom: none; }
.pay-row strong { margin-left: auto; font-variant-numeric: tabular-nums; }
.pay-method, .pay-ref { color: var(--muted); font-size: 12px; }
.pay-form { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--panel-line); }
.pay-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px; margin-bottom: 12px; }
.pay-fields label { font-size: 12.5px; color: var(--muted); }
.pay-fields input, .pay-fields select { display: block; width: 100%; margin-top: 5px;
  padding: 9px; font-size: 16px; box-sizing: border-box; background: var(--panel-2);
  color: var(--paper); border: 1px solid var(--panel-line); border-radius: 8px; }
.pay-done { color: var(--live, #2ecc71); font-size: 13px; margin-top: 14px; }
