:root {
  /* Neutral surfaces */
  --bg:        #f4f6f9;
  --surface:   #ffffff;
  --surface-2: #f8fafc;
  --border:    #e2e8f0;
  --border-strong: #cbd5e1;
  --text:      #1e293b;
  --text-dim:  #64748b;
  --text-faint:#94a3b8;

  /* Brand / accent */
  --accent:    #2563eb;
  --accent-dim:#dbeafe;

  /* Operation states */
  --queued:      #64748b;
  --queued-bg:   #f1f5f9;
  --active:      #d97706;
  --active-bg:   #fef3c7;
  --done:        #16a34a;
  --done-bg:     #dcfce7;
  --overdue:     #dc2626;
  --overdue-bg:  #fee2e2;
  --material:    #c2410c;
  --material-bg: #ffedd5;
  --ready:       #15803d;
  --ready-bg:    #dcfce7;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 10px 40px rgba(15, 23, 42, 0.18);
  /* Symbol fallbacks are deliberate: icon glyphs in buttons rendered as tofu boxes on
     machines whose text fonts lack the symbol blocks. Prefer well-covered codepoints too. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
          "Segoe UI Symbol", "Noto Sans Symbols 2", "DejaVu Sans", sans-serif;
}

/* ---------- Dark theme ---------- */
:root[data-theme="dark"] {
  --bg:        #0f172a;
  --surface:   #1e293b;
  --surface-2: #273548;
  --border:    #334155;
  --border-strong: #475569;
  --text:      #e5edf7;
  --text-dim:  #a3b2c7;
  --text-faint:#7688a0;
  --accent:    #60a5fa;
  --accent-dim:#1e3a5f;
  --queued:      #94a3b8;
  --queued-bg:   #334155;
  --active:      #fbbf24;
  --active-bg:   #422006;
  --done:        #4ade80;
  --done-bg:     #16341f;
  --overdue:     #f87171;
  --overdue-bg:  #4c1d1d;
  --material:    #fb923c;
  --material-bg: #45210b;
  --ready:       #4ade80;
  --ready-bg:    #16341f;
  --shadow: 0 1px 3px rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.35);
  --shadow-lg: 0 12px 40px rgba(0,0,0,0.6);
}
/* Overrides for the few hardcoded (light) backgrounds. */
:root[data-theme="dark"] .file-btn { background: #2563eb; }
:root[data-theme="dark"] .lang-btn.active { background: #2563eb; }
:root[data-theme="dark"] .type-badge.maskin { background: #1e2a52; color: #a5b4fc; }
:root[data-theme="dark"] .type-badge.lego   { background: #3a1140; color: #f0abfc; }
:root[data-theme="dark"] .type-badge.pool   { background: #0b3a44; color: #67e8f9; }
:root[data-theme="dark"] .status-pill.partial { background: #0c3a52; color: #7dd3fc; }
:root[data-theme="dark"] .op-card.active,
:root[data-theme="dark"] .tl-step.active .tl-body { background: #241f10; }
:root[data-theme="dark"] .op-card.overdue,
:root[data-theme="dark"] .tl-step.overdue .tl-body { background: #2a1414; }

* { box-sizing: border-box; }

body, .machine-card, .stat-card, .item-row, .drawer, .toolbar {
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.45;
}

/* ---------- Header ---------- */
.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
  flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand-mark {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  background: var(--accent); color: #fff;
  border-radius: 10px; font-size: 24px;
}
.brand h1 { font-size: 18px; margin: 0; font-weight: 650; }
.subtitle { margin: 0; font-size: 12px; color: var(--text-dim); }

.header-actions { display: flex; align-items: center; gap: 14px; }
.lang-toggle { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }
.lang-btn {
  border: none; background: var(--surface); color: var(--text-dim);
  padding: 7px 12px; font-size: 12px; font-weight: 700; cursor: pointer;
  transition: background .15s, color .15s;
}
.lang-btn + .lang-btn { border-left: 1px solid var(--border); }
.lang-btn:hover { background: var(--surface-2); color: var(--text); }
.lang-btn.active { background: var(--accent); color: #fff; }
.theme-toggle {
  width: 36px; height: 36px; border: 1px solid var(--border-strong);
  background: var(--surface); border-radius: var(--radius-sm);
  cursor: pointer; font-size: 16px; line-height: 1; display: grid; place-items: center;
  transition: background .15s, border-color .15s;
}
.theme-toggle:hover { background: var(--surface-2); border-color: var(--accent); }
.file-btn {
  display: inline-flex; align-items: center;
  background: var(--accent); color: #fff;
  padding: 9px 16px; border-radius: var(--radius-sm);
  font-weight: 600; font-size: 13px; cursor: pointer;
  transition: background .15s, transform .05s;
}
.file-btn:hover { background: #1d4ed8; }
.file-btn:active { transform: translateY(1px); }
.file-meta { font-size: 12px; color: var(--text-dim); }
.user-chip { display: inline-flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text-dim); }
.user-chip[hidden] { display: none; }
.user-chip #userName { font-weight: 600; color: var(--text); }
.logout-btn { border: 1px solid var(--border-strong); background: var(--surface); color: var(--text-dim); padding: 6px 12px; border-radius: var(--radius-sm); font-size: 12px; font-weight: 600; cursor: pointer; }
.logout-btn:hover { background: var(--surface-2); color: var(--text); }

/* Login */
.login-overlay { position: fixed; inset: 0; z-index: 200; background: var(--bg); display: grid; place-items: center; padding: 24px; }
.login-overlay[hidden] { display: none; }
.login-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 34px 32px; width: min(360px, 92vw); display: flex; flex-direction: column; align-items: stretch; gap: 12px; text-align: center; }
.login-card .brand-mark { margin: 0 auto; }
.login-card h2 { margin: 6px 0 0; font-size: 20px; }
.login-sub { margin: 0 0 8px; color: var(--text-dim); font-size: 13px; }
.login-input { padding: 11px 13px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); font-size: 14px; background: var(--surface); color: var(--text); }
.login-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.login-error { color: var(--overdue); font-size: 13px; }
.login-error[hidden] { display: none; }
.login-submit { margin-top: 4px; background: var(--accent); color: #fff; border: none; padding: 11px; border-radius: var(--radius-sm); font-size: 14px; font-weight: 650; cursor: pointer; }
.login-submit:hover { background: #1d4ed8; }

/* ---------- Full-window drop overlay ---------- */
.drop-overlay {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(37, 99, 235, 0.14);
  backdrop-filter: blur(2px);
  display: grid; place-items: center;
  padding: 24px;
}
/* Keep the `hidden` attribute authoritative — otherwise display:grid above would
   leave the invisible overlay covering (and intercepting clicks on) the page. */
.drop-overlay[hidden] { display: none; }
.drop-overlay-inner {
  border: 3px dashed var(--accent); border-radius: 18px;
  background: var(--surface);
  padding: 48px 64px; text-align: center;
  box-shadow: var(--shadow-lg); pointer-events: none;
}
.drop-overlay-inner .drop-icon { font-size: 56px; }
.drop-overlay-inner p { margin: 12px 0 0; font-size: 18px; font-weight: 600; color: var(--accent); }

/* ---------- Empty state ---------- */
.drop-icon { font-size: 48px; }
code { background: var(--surface-2); padding: 1px 6px; border-radius: 4px; font-size: .9em; }

/* ---------- App shell: sidebar + content ---------- */
.app-body { display: flex; align-items: flex-start; }
.sidebar {
  flex: 0 0 224px; width: 224px; box-sizing: border-box;
  position: sticky; top: var(--header-h, 68px);
  height: calc(100vh - var(--header-h, 68px));
  overflow-y: auto;
  background: var(--surface); border-right: 1px solid var(--border);
  padding: 18px 12px;
}
.nav-group { margin-bottom: 18px; }
.nav-group-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); padding: 0 10px 6px; }
.nav-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  border: none; background: none; text-align: left;
  padding: 9px 10px; border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 600; color: var(--text-dim); cursor: pointer;
}
.nav-item:hover { background: var(--surface-2); color: var(--text); }
.nav-item.active { background: var(--accent-dim); color: var(--accent); }
.nav-ico { width: 20px; text-align: center; font-size: 15px; flex: 0 0 auto; }
/* Collapse control at the foot of the sidebar; the collapsed sidebar is an
   icon rail: labels and group headings hide, each entry keeps its icon and
   gets its name as a tooltip (app.js sets the titles). Remembered per
   browser in localStorage like theme and language. */
.nav-collapse { display: flex; align-items: center; gap: 10px; width: 100%; margin-top: auto; border: none; background: none; text-align: left; padding: 9px 10px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; color: var(--text-faint); cursor: pointer; }
.nav-collapse:hover { background: var(--surface-2); color: var(--text); }
.sidebar { display: flex; flex-direction: column; }
.sidebar.collapsed { flex-basis: 56px; width: 56px; padding: 18px 6px; }
.sidebar.collapsed .nav-group-label { display: none; }
.sidebar.collapsed .nav-item > span:not(.nav-ico), .sidebar.collapsed .nav-collapse > span:not(.nav-ico) { display: none; }
.sidebar.collapsed .nav-item, .sidebar.collapsed .nav-collapse { justify-content: center; padding: 9px 0; }
.sidebar.collapsed .nav-collapse .nav-ico { transform: scaleX(-1); }
.nav-toggle { display: none; border: none; background: none; font-size: 22px; line-height: 1; cursor: pointer; color: var(--text); padding: 0; margin-right: 2px; }
.nav-scrim { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.4); z-index: 18; }

.content { flex: 1; min-width: 0; padding: 24px; max-width: 1400px; }

/* ---------- Home / overview ---------- */
.home-head { margin-bottom: 18px; }
.home-head h2 { margin: 0 0 4px; font-size: 22px; }
.home-plan { margin: 0; font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.home-summary { color: var(--text-faint); }
.home-sec { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); margin: 26px 0 12px; }
.home-links { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.home-link {
  display: flex; align-items: center; gap: 14px; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 15px 16px; cursor: pointer; box-shadow: var(--shadow);
}
.home-link:hover { border-color: var(--accent); }
.hl-ico { font-size: 24px; flex: 0 0 auto; }
.hl-txt { display: flex; flex-direction: column; min-width: 0; }
.hl-txt b { font-size: 15px; color: var(--text); }
.hl-txt small { font-size: 12px; color: var(--text-dim); }
.home-empty { max-width: 560px; margin: 56px auto; text-align: center; }
.home-empty h2 { margin: 12px 0 8px; font-size: 20px; }
.home-empty p { color: var(--text-dim); margin-bottom: 18px; }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px; margin-bottom: 22px;
}
.stat-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow);
}
.stat-card .value { font-size: 26px; font-weight: 700; line-height: 1; }
.stat-card .label { font-size: 12px; color: var(--text-dim); margin-top: 6px; }
.stat-card.accent .value { color: var(--accent); }
.stat-card.active .value { color: var(--active); }
.stat-card.done .value  { color: var(--done); }
.stat-card.queued .value{ color: var(--queued); }
.stat-card.overdue .value { color: var(--overdue); }
.stat-card.overdue { border-color: var(--overdue-bg); }
.stat-card.material .value { color: var(--material); }
.stat-card.material { border-color: var(--material-bg); }

.data-summary {
  margin: -8px 0 20px; font-size: 12px; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.data-summary.has-skipped { color: var(--overdue); font-weight: 600; }

.stat-card.clickable { cursor: pointer; transition: border-color .12s, box-shadow .12s; }
.stat-card.clickable:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }

.toolbar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  position: sticky; top: var(--header-h, 68px); z-index: 15;
  background: var(--bg); padding: 12px 0; margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.toolbar[hidden] { display: none; }
.clear-btn {
  margin-left: auto; border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-dim); padding: 7px 12px; border-radius: var(--radius-sm);
  font-size: 12px; font-weight: 600; cursor: pointer; white-space: nowrap;
  transition: background .15s, color .15s, border-color .15s;
}
.clear-btn:hover { background: var(--overdue-bg); color: var(--overdue); border-color: var(--overdue-bg); }
.clear-btn[hidden] { display: none; }
.search {
  flex: 1; min-width: 220px; max-width: 420px;
  padding: 10px 14px; border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); font-size: 14px;
  background: var(--surface); color: var(--text);
}
.search::placeholder { color: var(--text-faint); }
.search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.overdue-toggle {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 600; color: var(--text-dim);
  cursor: pointer; user-select: none; white-space: nowrap;
}
.overdue-toggle input { width: 15px; height: 15px; accent-color: var(--overdue); cursor: pointer; }
.overdue-toggle:hover { color: var(--overdue); }

.item-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.item-controls[hidden] { display: none; }
.ctrl { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--text-dim); }
.ctrl select {
  padding: 7px 10px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font-size: 13px; font-weight: 500; cursor: pointer;
}
.ctrl select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }

/* Multi-select (checkbox dropdown) */
.ms { position: relative; }
.ms-label { font-size: 12px; font-weight: 600; color: var(--text-dim); }
.ms-toggle {
  display: inline-flex; align-items: center; gap: 8px; min-width: 120px;
  padding: 7px 10px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font-size: 13px; font-weight: 500;
  cursor: pointer; justify-content: space-between;
}
.ms.has-selection .ms-toggle { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }
.ms-caret { font-size: 10px; color: var(--text-faint); }
.ms-summary { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; }
.ms-panel {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; min-width: 100%;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg); padding: 6px; display: flex; flex-direction: column; gap: 1px;
  white-space: nowrap;
}
.ms-panel[hidden] { display: none; }
.ms-opt {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  border-radius: 6px; font-size: 13px; cursor: pointer; color: var(--text);
}
.ms-opt:hover { background: var(--surface-2); }
.ms-opt input { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }

/* ---------- Machine grid ---------- */
.machine-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}
.machine-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow);
  cursor: pointer; transition: transform .1s, box-shadow .15s, border-color .15s;
}
.machine-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: var(--border-strong); }
.machine-card.has-overdue { border-left: 4px solid var(--overdue); }
.mc-badges { display: flex; align-items: center; gap: 6px; }
.overdue-badge {
  font-size: 11px; font-weight: 700; padding: 3px 7px; border-radius: 5px;
  background: var(--overdue-bg); color: var(--overdue); white-space: nowrap;
}
.machine-card .mc-top { display: flex; justify-content: space-between; align-items: start; gap: 8px; }
.machine-card h3 { margin: 0; font-size: 15px; font-weight: 650; }
.machine-card .mc-group { font-size: 11px; color: var(--text-faint); font-weight: 600; }
.type-badge {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .03em; padding: 3px 7px; border-radius: 5px;
  background: var(--surface-2); color: var(--text-dim); white-space: nowrap;
}
.type-badge.maskin { background: #eef2ff; color: #4338ca; }
.type-badge.lego   { background: #fdf4ff; color: #a21caf; }
.type-badge.pool   { background: #ecfeff; color: #0e7490; }

/* Load bar */
.load-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; margin: 14px 0 10px; background: var(--surface-2); }
.load-bar .seg { height: 100%; }
.seg.done   { background: var(--done); }
.seg.active { background: var(--active); }
.seg.queued { background: var(--queued); }

.mc-counts { display: flex; gap: 14px; font-size: 12px; }
.mc-counts .cnt { display: flex; align-items: center; gap: 5px; color: var(--text-dim); }
.dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.dot.queued { background: var(--queued); }
.dot.active { background: var(--active); }
.dot.done   { background: var(--done); }
.mc-current {
  margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border);
  font-size: 12px; color: var(--text-dim);
}
.mc-current strong { color: var(--active); }
.mc-ready { font-size: 12px; color: var(--ready); font-weight: 600; margin-top: 8px; }
.mc-ready .mc-blocked { color: var(--material); }
.mc-load { font-size: 11px; color: var(--text-faint); margin-top: 6px; }

/* ---------- Item list ---------- */
.item-list { display: flex; flex-direction: column; gap: 7px; }
.item-row {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 9px 16px; box-shadow: var(--shadow);
  cursor: pointer; display: grid;
  grid-template-columns: 104px minmax(180px, 1fr) 150px 108px minmax(150px, 210px);
  gap: 14px; align-items: center;
  transition: border-color .15s, box-shadow .15s;
}
.item-row:hover { border-color: var(--border-strong); box-shadow: var(--shadow-lg); }
.item-row.has-overdue { border-left: 4px solid var(--overdue); }
.io-pills { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }
.item-row .status-pill { font-size: 10px; padding: 2px 7px; }
.item-row .io-order { font-weight: 650; font-size: 13px; }
.item-row .io-order small { display: block; font-weight: 500; color: var(--text-faint); font-size: 11px; }
.item-row .io-article { font-size: 13px; line-height: 1.3; }
.item-row .io-article small { display: block; color: var(--text-faint); font-size: 11px; }
.item-row .io-loc { font-size: 12px; color: var(--text-dim); }
.item-row .io-loc small { display: block; color: var(--text-faint); }
.io-progress { display: flex; align-items: center; gap: 8px; }
.progress-track { flex: 1; height: 7px; background: var(--surface-2); border-radius: 4px; overflow: hidden; }
.progress-fill { height: 100%; background: var(--done); }
.progress-pct { font-size: 11px; color: var(--text-dim); width: 30px; text-align: right; }

.status-pill {
  font-size: 11px; font-weight: 650; padding: 3px 9px; border-radius: 20px;
  display: inline-block; white-space: nowrap;
}
.status-pill.done   { background: var(--done-bg); color: var(--done); }
.status-pill.active { background: var(--active-bg); color: var(--active); }
.status-pill.queued { background: var(--queued-bg); color: var(--queued); }
.status-pill.partial{ background: #e0f2fe; color: #0369a1; }
.status-pill.overdue{ background: var(--overdue-bg); color: var(--overdue); }
.status-pill.material{ background: var(--material-bg); color: var(--material); }
.status-pill.ready{ background: var(--ready-bg); color: var(--ready); }
.status-pill.waiting{ background: var(--queued-bg); color: var(--queued); }

.empty-msg { text-align: center; color: var(--text-faint); padding: 40px; }

/* ---------- Bottleneck view ---------- */
.bottleneck-intro { color: var(--text-dim); font-size: 13px; margin: 0 0 18px; max-width: 760px; }
.bottleneck-chart {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 18px; box-shadow: var(--shadow);
}
.bn-row {
  display: grid; grid-template-columns: 190px 1fr 150px; gap: 16px; align-items: center;
  padding: 9px 0; border-bottom: 1px solid var(--border); cursor: pointer;
}
.bn-row:last-child { border-bottom: none; }
.bn-row:hover { background: var(--surface-2); }
.bn-label { display: flex; flex-direction: column; overflow: hidden; }
.bn-name { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bn-group { font-size: 11px; color: var(--text-faint); }
.bn-track { display: flex; align-items: center; gap: 10px; }
.bn-bar {
  height: 20px; border-radius: 5px; background: var(--accent);
  min-width: 3px; position: relative; overflow: hidden; transition: width .3s;
}
.bn-bar-overdue { position: absolute; right: 0; top: 0; height: 100%; background: var(--overdue); }
.bn-value { font-size: 12px; font-weight: 600; color: var(--text-dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.bn-value .bn-overdue-h { color: var(--overdue); }
.bn-meta { font-size: 12px; color: var(--text-dim); display: flex; flex-direction: column; gap: 2px; text-align: right; }
.bn-overdue { color: var(--overdue); font-size: 11px; font-weight: 600; }

@media (max-width: 640px) {
  .bn-row { grid-template-columns: 110px 1fr; }
  .bn-meta { grid-column: 1 / -1; flex-direction: row; gap: 10px; text-align: left; }
}

/* ---------- Map view ---------- */
.map-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.map-zoom { display: inline-flex; gap: 6px; }
.map-btn {
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  padding: 7px 12px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.map-btn:hover { background: var(--surface-2); border-color: var(--accent); }
.map-btn.icon { min-width: 34px; padding: 7px 0; text-align: center; font-size: 16px; }
.map-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
:root[data-theme="dark"] .map-btn.active { background: #2563eb; }
.map-hint { font-size: 12px; color: var(--text-faint); }

.map-viewport {
  position: relative; height: 62vh; min-height: 360px; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  touch-action: none; cursor: grab;
  background-image: radial-gradient(var(--border) 1px, transparent 1px);
  background-size: 26px 26px;
}
.map-viewport.editing { cursor: default; }
.map-viewport:active { cursor: grabbing; }
.map-canvas { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
.map-bg { position: absolute; top: 0; left: 0; pointer-events: none; }
.map-bg svg, .map-bg img { display: block; width: 100%; height: 100%; }
.map-nodes { position: absolute; top: 0; left: 0; }
.map-edit-only { display: inline-flex; gap: 6px; }

.map-node {
  position: absolute; width: 156px; box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-left: 4px solid var(--queued); border-radius: var(--radius-sm);
  padding: 8px 10px; box-shadow: var(--shadow); cursor: pointer; user-select: none;
}
.map-node:hover { box-shadow: var(--shadow-lg); }
.map-viewport.editing .map-node { cursor: move; }
.map-node.st-overdue { border-left-color: var(--overdue); }
.map-node.st-blocked { border-left-color: var(--material); }
.map-node.st-ok      { border-left-color: var(--done); }
.map-node.st-idle    { border-left-color: var(--queued); opacity: .8; }
.mn-head { font-weight: 650; font-size: 12px; line-height: 1.2; }
.mn-group { color: var(--text-faint); font-weight: 600; font-size: 10px; }
.mn-stats { display: flex; align-items: center; gap: 10px; margin-top: 5px; font-size: 11px; color: var(--text-dim); }
.mn-cnt { display: inline-flex; align-items: center; gap: 4px; }
.mn-over { color: var(--overdue); font-weight: 700; }
.mn-load { font-size: 10px; color: var(--text-faint); margin-top: 3px; }
.mn-unmap {
  position: absolute; top: -8px; right: -8px; width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--overdue);
  font-size: 11px; line-height: 1; cursor: pointer; display: grid; place-items: center; box-shadow: var(--shadow);
}
.mn-unmap:hover { background: var(--overdue-bg); }

.map-unmapped { margin-top: 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 16px; box-shadow: var(--shadow); }
.um-head { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); font-weight: 700; display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.um-body { display: flex; flex-wrap: wrap; gap: 8px; }
.um-empty { color: var(--text-faint); font-size: 13px; }
.um-chip {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-left: 4px solid var(--queued); border-radius: var(--radius-sm); padding: 6px 8px 6px 10px; font-size: 12px;
}
.um-chip.st-overdue { border-left-color: var(--overdue); }
.um-chip.st-blocked { border-left-color: var(--material); }
.um-chip.st-ok      { border-left-color: var(--done); }
.um-name { font-weight: 650; }
.um-stats { display: inline-flex; gap: 8px; color: var(--text-dim); }
.um-place {
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--accent);
  width: 24px; height: 24px; border-radius: 6px; cursor: pointer; font-size: 15px; line-height: 1; display: grid; place-items: center;
}
.um-place:hover { background: var(--accent-dim); }

/* ---------- History view ---------- */
.hist-section { margin-bottom: 28px; }
.hist-h { font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); margin: 0 0 12px; display: flex; align-items: center; gap: 12px; }
.hist-sub { color: var(--text-dim); font-size: 13px; margin: 0 0 14px; }
.hist-empty { color: var(--text-faint); font-size: 14px; padding: 20px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }

.ch-group { background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--border-strong); border-radius: var(--radius-sm); padding: 12px 14px; margin-bottom: 10px; box-shadow: var(--shadow); }
.ch-group.good { border-left-color: var(--done); }
.ch-group.bad  { border-left-color: var(--overdue); }
.ch-group.warn { border-left-color: var(--material); }
.ch-group.new  { border-left-color: var(--accent); }
.ch-group.muted { border-left-color: var(--queued); }
.ch-head { font-size: 13px; font-weight: 650; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
.ch-list { display: flex; flex-wrap: wrap; gap: 6px; }
.ch-item { border: 1px solid var(--border); background: var(--surface-2); color: var(--text); border-radius: 6px; padding: 4px 9px; font-size: 12px; cursor: pointer; }
.ch-item:hover { border-color: var(--accent); }
.ch-no { font-weight: 700; }
.ch-more { font-size: 12px; color: var(--text-faint); align-self: center; }
.ch-extra { font-size: 12px; color: var(--text-dim); margin-top: 6px; }

.trend-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.trend-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow); }
.tc-label { font-size: 12px; color: var(--text-dim); }
.tc-row { display: flex; align-items: baseline; gap: 10px; margin: 4px 0 8px; }
.tc-value { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tc-delta { font-size: 12px; font-weight: 700; }
.tc-delta.up-good { color: var(--done); }
.tc-delta.up-bad  { color: var(--overdue); }
.tc-delta.flat    { color: var(--text-faint); }
.trend-card .spark { width: 100%; height: 32px; display: block; }

/* Admin-only list of the imports feeding the trend. Deliberately NOT in the
   .hist-* namespace: .hist-list/.hist-row/.hist-time belong to the schedule
   undo-history modal further down this file, and .hist-empty is defined twice
   with source order deciding the winner. */
.trend-imports { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.ti-row { display: grid; grid-template-columns: 130px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 6px 8px; border-radius: var(--radius-sm); font-size: 13px; }
.ti-row:nth-child(odd) { background: var(--surface-2); }
.ti-row.excluded .ti-name, .ti-row.excluded .ti-when { opacity: .5; text-decoration: line-through; }
.ti-when { font-variant-numeric: tabular-nums; color: var(--text-dim); }
.ti-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ti-tag { font-size: 11px; color: var(--text-faint); margin-left: 8px; }
.ti-btn { border: 1px solid var(--border); background: var(--surface); color: var(--text-dim); font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 6px; cursor: pointer; }
.ti-btn:hover { background: var(--overdue-bg); color: var(--overdue); border-color: var(--overdue-bg); }
.ti-row.excluded .ti-btn:hover { background: var(--surface-2); color: var(--accent); border-color: var(--border); }

/* ---------- Drawer ---------- */
.drawer-overlay {
  position: fixed; inset: 0; background: rgba(15,23,42,.35);
  z-index: 40; backdrop-filter: blur(1px);
}
.drawer {
  position: fixed; top: 0; right: 0; height: 100vh;
  width: min(560px, 94vw); background: var(--surface);
  z-index: 50; box-shadow: var(--shadow-lg);
  overflow-y: auto; padding: 24px 26px 60px;
  animation: slideIn .18s ease;
}
@keyframes slideIn { from { transform: translateX(30px); opacity: .4; } to { transform: none; opacity: 1; } }
.drawer-close {
  position: absolute; top: 16px; right: 16px;
  border: none; background: var(--surface-2); color: var(--text-dim);
  width: 32px; height: 32px; border-radius: 8px; cursor: pointer; font-size: 15px;
}
.drawer-close:hover { background: var(--border); color: var(--text); }

.drawer h2 { margin: 4px 40px 2px 0; font-size: 20px; }
.drawer .d-sub { color: var(--text-dim); font-size: 13px; margin: 0 0 18px; }
.copy-btn {
  border: none; background: none; cursor: pointer; padding: 2px;
  margin-left: 5px; color: var(--text-faint); vertical-align: middle;
  border-radius: 5px; line-height: 0; transition: color .15s, background .15s;
}
.copy-btn svg { width: 14px; height: 14px; display: block; }
.copy-btn:hover { color: var(--accent); background: var(--surface-2); }
.copy-btn.copied { color: var(--done); }

.d-section { margin-top: 24px; }
.d-section > h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-faint); margin: 0 0 10px; display: flex; align-items: center; gap: 8px;
}
.d-section .count-chip {
  background: var(--surface-2); color: var(--text-dim);
  border-radius: 20px; padding: 1px 8px; font-size: 11px; font-weight: 700;
}

/* Operation card (inside drawer) */
.op-card {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 11px 13px; margin-bottom: 8px; background: var(--surface);
  border-left: 4px solid var(--queued);
}
.op-card.active { border-left-color: var(--active); background: #fffdf7; }
.op-card.done   { border-left-color: var(--done); }
.op-card.overdue { border-left-color: var(--overdue); background: #fff6f6; }
.oc-meta .late, .tl-meta .late { color: var(--overdue); font-weight: 600; }
.oc-meta .mat, .tl-meta .mat { color: var(--material); font-weight: 600; }
.oc-meta .matok, .tl-meta .matok { color: var(--ready); font-weight: 600; }
.tl-meta .tl-art { background: var(--surface-2); color: var(--text-dim); padding: 0 6px; border-radius: 4px; font-weight: 600; }
.oc-meta .waitprev, .tl-meta .waitprev { color: var(--queued); font-weight: 600; }
.op-card .oc-top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.op-card .oc-title { font-weight: 600; font-size: 13px; }
.op-card.link { cursor: pointer; }
.op-card.link:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.op-card .oc-meta { font-size: 11px; color: var(--text-dim); margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px 12px; }
.op-card .oc-qty {
  font-weight: 700; font-size: 15px; color: var(--accent);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.op-num { font-variant-numeric: tabular-nums; color: var(--text-faint); font-weight: 700; }

/* Item routing timeline */
.timeline { position: relative; margin-left: 8px; }
.tl-step { position: relative; padding: 0 0 6px 28px; }
.tl-step::before {
  content: ''; position: absolute; left: 7px; top: 20px; bottom: -6px;
  width: 2px; background: var(--border);
}
.tl-step:last-child::before { display: none; }
.tl-node {
  position: absolute; left: 0; top: 4px; width: 16px; height: 16px;
  border-radius: 50%; border: 3px solid var(--surface); background: var(--queued);
  box-shadow: 0 0 0 2px var(--queued);
}
.tl-step.active .tl-node { background: var(--active); box-shadow: 0 0 0 2px var(--active); }
.tl-step.done .tl-node   { background: var(--done); box-shadow: 0 0 0 2px var(--done); }
.tl-step.overdue .tl-node { background: var(--overdue); box-shadow: 0 0 0 2px var(--overdue); }
.tl-step.overdue .tl-body { border-color: var(--overdue); background: #fff6f6; }
.tl-body {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 10px 12px; margin-bottom: 10px; background: var(--surface);
}
.tl-step.active .tl-body { border-color: var(--active); background: #fffdf7; }
.tl-head { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.tl-machine { font-weight: 650; font-size: 13px; cursor: pointer; }
.tl-machine:hover { color: var(--accent); text-decoration: underline; }
.tl-meta { font-size: 11px; color: var(--text-dim); margin-top: 4px; display: flex; flex-wrap: wrap; gap: 3px 12px; }

/* Meta grid for drawer header */
.meta-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px,1fr)); gap: 10px 16px; margin-top: 14px; }
.meta-grid .m-item .m-k { font-size: 11px; color: var(--text-faint); }
.meta-grid .m-item .m-v { font-size: 14px; font-weight: 600; }

@media (max-width: 640px) {
  .item-row { grid-template-columns: 1fr; gap: 8px; }
  .dashboard { padding: 16px; }
}

/* ---------- Team tab ---------- */
.team-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.team-intro { margin: 0; font-size: 13px; color: var(--text-dim); max-width: 70ch; line-height: 1.5; }
.cfg-subtitle { margin: 22px 0 4px; font-size: 15px; }
.btn-primary { background: var(--accent); color: #fff; border: none; padding: 9px 15px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.btn-primary:hover { filter: brightness(1.05); }
.btn-ghost { background: var(--surface); color: var(--text-dim); border: 1px solid var(--border-strong); padding: 9px 15px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; cursor: pointer; }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.team-error, .team-empty { padding: 40px 20px; text-align: center; color: var(--text-dim); background: var(--surface); border: 1px dashed var(--border-strong); border-radius: var(--radius); }
.team-error { color: var(--overdue); border-style: solid; }

.team-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
.team-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px; display: flex; flex-direction: column; gap: 14px; }
.team-card.archived { opacity: 0.62; }
.tc-top { display: flex; align-items: center; gap: 12px; }
.tc-avatar { width: 40px; height: 40px; flex: 0 0 auto; border-radius: 50%; color: #fff; font-weight: 700; font-size: 15px; display: grid; place-items: center; }
.tc-id { flex: 1; min-width: 0; }
.tc-name { font-weight: 700; font-size: 15px; color: var(--text); }
.tc-arch { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); border: 1px solid var(--border-strong); border-radius: 4px; padding: 1px 5px; margin-left: 4px; }
.tc-title { font-size: 12px; color: var(--text-dim); }
.tc-actions { display: flex; gap: 4px; }
.tc-actions button { width: 28px; height: 28px; border: 1px solid var(--border); background: var(--surface); border-radius: var(--radius-sm); cursor: pointer; font-size: 13px; color: var(--text-dim); }
.tc-actions button:hover { background: var(--surface-2); border-color: var(--accent); color: var(--text); }

.tc-skills { display: flex; flex-wrap: wrap; gap: 6px; }
.skill-tag { font-size: 11px; font-weight: 600; background: var(--accent-dim); color: var(--accent); border-radius: 20px; padding: 3px 10px; }
.skill-none { font-size: 12px; color: var(--text-faint); font-style: italic; }
.skill-more { font-size: 11px; font-weight: 600; background: none; border: 1px solid var(--border-strong); color: var(--text-dim); border-radius: 20px; padding: 3px 10px; cursor: pointer; }
.skill-more:hover { border-color: var(--accent); color: var(--accent); }

/* Qualification matrix (Team) */
.tc-quals { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.quals-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 4px 10px; }
.qual-opt { display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
.qual-opt input { accent-color: var(--accent); }

.tc-sec-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between; }
.tc-weektot { text-transform: none; letter-spacing: 0; color: var(--text-dim); font-weight: 600; }
.wk-bars { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; align-items: end; }
.wk-col { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.wk-bar-track { width: 100%; height: 42px; display: flex; align-items: flex-end; background: var(--surface-2); border-radius: 4px; overflow: hidden; }
.wk-bar { width: 100%; background: var(--accent); border-radius: 4px 4px 0 0; min-height: 2px; }
.wk-bar.off { background: transparent; }
.wk-d { font-size: 10px; color: var(--text-faint); font-weight: 600; }

.abs-add { text-transform: none; letter-spacing: 0; font-size: 11px; font-weight: 600; border: none; background: none; color: var(--accent); cursor: pointer; padding: 0; }
.abs-add:hover { text-decoration: underline; }
.abs-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.abs-none { font-size: 12px; color: var(--text-faint); font-style: italic; }
.abs-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; font-size: 12px; padding: 6px 8px; background: var(--surface-2); border-radius: var(--radius-sm); }
.abs-row.abs-past { opacity: 0.55; }
.abs-kind { font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 4px; }
.abs-kind.vacation { background: var(--accent-dim); color: var(--accent); }
.abs-kind.sick { background: var(--overdue-bg); color: var(--overdue); }
.abs-kind.other { background: var(--surface); color: var(--text-dim); border: 1px solid var(--border-strong); }
.abs-dates { color: var(--text); font-weight: 500; }
.abs-len { color: var(--text-faint); font-weight: 400; }
.abs-when { font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 4px; }
.abs-when.offNow { background: var(--active-bg); color: var(--active); }
.abs-when.upcoming { color: var(--text-dim); border: 1px solid var(--border-strong); }
.abs-note { color: var(--text-dim); width: 100%; }
.abs-del { margin-left: auto; border: none; background: none; color: var(--text-faint); cursor: pointer; font-size: 12px; padding: 0 2px; }
.abs-del:hover { color: var(--overdue); }

/* ---------- Modal (team forms) ---------- */
.modal-backdrop { position: fixed; inset: 0; z-index: 300; background: rgba(15, 23, 42, 0.5); display: grid; place-items: center; padding: 20px; }
.modal-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 22px 24px; width: min(440px, 94vw); max-height: 90vh; overflow-y: auto; }
.modal-title { margin: 0 0 4px; font-size: 17px; }
.modal-sub { margin: 0 0 14px; font-size: 13px; color: var(--text-dim); }
/* ---------- Allocation modal ---------- */
.sched-modal-host:empty { display: none; }
/* 1080px: the grid below asks for 200 + 2×5×60 + 84 = 884px for a weekday
   week and 1004px with both weekend days, plus this card's 48px of padding.
   The old 860px card could never show the Total column without a scrollbar. */
.am-card { width: min(1080px, 96vw); position: relative; }
.am-close { position: absolute; top: 12px; right: 12px; }
.am-coverage { margin: 6px 0 16px; }
.am-cov-bar { height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; }
.am-cov-fill { display: block; height: 100%; background: var(--active); }
/* Auto-plan preview modal (2c) */
.ap-card { max-width: 440px; }
.ap-summary { display: flex; gap: 14px; flex-wrap: wrap; font-weight: 600; margin: 10px 0 6px; }
.ap-badges { display: flex; gap: 12px; flex-wrap: wrap; font-size: 13px; margin-bottom: 8px; }
.ap-badges .ap-atrisk { color: var(--active); }
.ap-badges .ap-blocked { color: var(--text-dim); }
.ap-badges .ap-late { color: var(--overdue); }
.ap-note { font-size: 12px; color: var(--text-dim); margin: 2px 0; }
.ap-none { margin: 12px 0; }
/* Bump list: pinned evictions are the loudest thing in the preview. */
.ap-bumps { border-left: 3px solid var(--overdue); padding: 6px 10px; margin: 6px 0; font-size: 12px; }
.ap-bumps-title { font-weight: 700; color: var(--overdue); margin-bottom: 4px; }
.ap-bump { margin: 2px 0; }
.sc-autoplan { margin-left: 8px; }
.am-cov-fill.over { background: var(--overdue); }
.am-cov-label { margin-top: 6px; font-size: 12px; font-weight: 700; color: var(--text-dim); }
.am-empty { font-size: 13px; color: var(--text-faint); text-align: center; padding: 14px 4px; margin: 0; }
.am-footer { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.team-form { display: flex; flex-direction: column; gap: 12px; }
.team-form .fld { display: flex; flex-direction: column; gap: 5px; }
.team-form .fld > span { font-size: 12px; font-weight: 600; color: var(--text-dim); }
.team-form input[type=text], .team-form input:not([type]), .team-form input[type=date], .team-form input[type=number], .team-form select {
  padding: 9px 11px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); font-size: 14px; background: var(--surface); color: var(--text); width: 100%; }
.team-form input:focus, .team-form select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.fld-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.fld-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text); }
.fld-check input { width: 16px; height: 16px; }
.swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.swatch { width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.swatch.sel { border-color: var(--text); box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--text-faint); }
/* Weekly-hours editor: one row per weekday with AM + PM inputs (Build 1d-1). */
.hr-grid { display: flex; flex-direction: column; gap: 4px; }
.hr-in { display: grid; grid-template-columns: 3.5em 1fr 1fr; align-items: center; gap: 6px; }
.hr-in .hr-day { font-size: 12px; color: var(--text-dim); font-weight: 600; }
.hr-half { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-faint); }
.hr-half span { font-size: 10px; font-weight: 600; }
.hr-half input { width: 100%; padding: 6px 4px !important; text-align: center; font-size: 13px !important; }
.form-err { color: var(--overdue); font-size: 13px; }
.form-err[hidden] { display: none; }
.form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 4px; }

@media (max-width: 640px) {
  .team-head { flex-direction: column; }
}

/* ---------- Schedule tab ---------- */
/* The board wants the room: when Schedule is the active view, drop the 1400px
   content cap so it uses the full width. It never exceeds the window because
   .content is a flex:1 child of .app-body (bounded by window − sidebar). */
.content:has(#scheduleView:not([hidden])) { max-width: none; }
.sched-layout { display: flex; gap: 16px; align-items: flex-start; }
.sched-pool { flex: 0 0 300px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; display: flex; flex-direction: column; gap: 10px; max-height: 74vh; }
.sched-pool.drop-target { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.pool-head { display: flex; align-items: center; justify-content: space-between; }
.pool-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
.pool-search { padding: 8px 11px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); font-size: 13px; background: var(--surface); color: var(--text); }
.pool-search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.pool-center { padding: 8px 10px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); font-size: 13px; background: var(--surface); color: var(--text); }
.pool-center:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.pool-list { overflow-y: auto; display: flex; flex-direction: column; gap: 7px; padding-right: 2px; }
.pool-empty, .pool-capped { font-size: 12px; color: var(--text-faint); padding: 10px 4px; text-align: center; }
.pool-capped { border-top: 1px dashed var(--border); margin-top: 4px; }
.pool-filter { display: flex; gap: 4px; }
.pf-btn { flex: 1; font-size: 11px; font-weight: 600; border: 1px solid var(--border-strong); background: var(--surface); color: var(--text-dim); border-radius: var(--radius-sm); padding: 5px 6px; cursor: pointer; }
.pf-btn:hover { border-color: var(--accent); color: var(--text); }
.pf-btn.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.sc-progress { height: 4px; margin-top: 6px; background: var(--border); border-radius: 2px; overflow: hidden; }
.sc-progress-bar { display: block; height: 100%; background: var(--active); }
.sc-progress-bar.over { background: var(--overdue); }
.sc-cover { display: inline-block; margin-top: 4px; font-size: 10px; font-weight: 700; color: var(--text-faint); }
.sc-cover.over { color: var(--overdue); background: var(--overdue-bg); border-radius: 4px; padding: 0 5px; }
.sc-chunk { font-weight: 700; color: var(--text); }

.sc-card { background: var(--surface); border: 1px solid var(--border-strong); border-left: 3px solid var(--queued); border-radius: var(--radius-sm); padding: 7px 9px; font-size: 12px; cursor: grab; }
.sc-card[draggable="true"]:active { cursor: grabbing; }
.sc-card.dragging { opacity: 0.45; }
.pool-card { background: var(--surface-2); }
.pool-card.late, .cell-card.overrun { border-left-color: var(--overdue); }
.cell-card.active { border-left-color: var(--active); }
.cell-card.done { border-left-color: var(--done); opacity: 0.7; }
.sc-title { font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-meta { display: flex; flex-wrap: wrap; gap: 3px 8px; margin-top: 3px; color: var(--text-dim); font-size: 11px; }
.sc-mc { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sc-due.late { color: var(--overdue); font-weight: 600; }
.sc-overrun { margin-top: 5px; font-size: 11px; font-weight: 700; color: var(--overdue); background: var(--overdue-bg); border-radius: 4px; padding: 2px 6px; }
.sc-gone { font-weight: 400; font-size: 10px; color: var(--text-faint); }

/* App shell: the page never scrolls on this tab. --sched-fold is the document
   offset of .sched-layout's top edge, measured by schedule.js (setFold), so
   both columns are capped to the room below it and scroll inside themselves.
   .sched-main is a column so the toolbar and chips keep their natural height
   (however many rows the chips wrap to) and the board takes what is left.
   The caps are max-heights: a short roster renders short. */
.sched-main { flex: 1; min-width: 0; display: flex; flex-direction: column; max-height: calc(100vh - var(--sched-fold, 30vh) - 24px); }
.sched-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.sched-range { font-weight: 700; font-size: 14px; color: var(--text); }
.sc-nav, .sc-today { padding: 7px 12px; font-size: 13px; }
.sc-today { margin-left: auto; }

/* Qualification filter: a toolbar button whose popover holds the chips. The
   button is accent-filled while a filter narrows the board. The popover is
   absolute under its button (the page no longer scrolls on this tab) and
   layered above the board's sticky headers (z 2–3). Same skin as .tl-menu. */
.sched-qual { position: relative; display: inline-block; }
.sc-qual { padding: 7px 12px; font-size: 13px; }
.sc-qual.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.sched-skills { position: absolute; top: calc(100% + 6px); left: 0; z-index: 340; width: max-content; max-width: min(760px, 80vw);
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
.sched-skills[hidden] { display: none; }
.skill-chip { font-size: 12px; font-weight: 600; border: 1px solid var(--border-strong); background: var(--surface); color: var(--text-dim); border-radius: 20px; padding: 4px 11px; cursor: pointer; }
.skill-chip:hover { border-color: var(--accent); color: var(--text); }
.skill-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.skill-chip-all { font-weight: 700; }

.sched-boardwrap { overflow: auto; max-height: 74vh; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); }
.sched-grid { display: grid; width: 100%; }
.sched-grid > div { border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.sg-corner { position: sticky; left: 0; top: 0; z-index: 4; background: var(--surface-2); }
.sg-dayhead { position: sticky; top: 0; z-index: 3; background: var(--surface-2); padding: 8px 10px; text-align: center; font-size: 12px; color: var(--text); }
.sg-dayhead .sg-wd { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); }
.sg-dayhead.weekend { background: var(--bg); color: var(--text-dim); }
.sg-dayhead.today { box-shadow: inset 0 -3px 0 var(--accent); }
.sg-emp { position: sticky; left: 0; z-index: 2; background: var(--surface); display: flex; align-items: center; gap: 8px; padding: 8px 10px; }
.sg-emp.archived { opacity: 0.6; }
.sg-dot { width: 26px; height: 26px; flex: 0 0 auto; border-radius: 50%; color: #fff; font-weight: 700; font-size: 11px; display: grid; place-items: center; }
.sg-empname { font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.2; }
.sg-empname small { display: block; font-weight: 400; font-size: 10px; color: var(--text-faint); }
.sg-empload { font-weight: 600 !important; }
.sg-empload.over { color: var(--overdue) !important; }
.sg-cell { min-height: 74px; padding: 5px; background: var(--surface); display: flex; flex-direction: column; gap: 5px; }
.sg-cell.weekend { background: var(--surface-2); }
.sg-cell.today { background: color-mix(in srgb, var(--accent-dim) 40%, var(--surface)); }
.sg-cell.absent { background: repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 6px, var(--bg) 6px, var(--bg) 12px); }
.sg-cell.drop-target { outline: 2px dashed var(--accent); outline-offset: -3px; background: var(--accent-dim); }
.sg-cell.overbooked { box-shadow: inset 3px 0 0 var(--overdue); }
.sg-abs { align-self: flex-start; font-size: 9px; }
.sg-cellsum { margin-top: auto; align-self: flex-end; font-size: 10px; font-weight: 700; color: var(--text-faint); }
.sg-cellsum.over { color: var(--overdue); background: var(--overdue-bg); border-radius: 4px; padding: 0 5px; }
.sched-noemp { padding: 40px 20px; text-align: center; color: var(--text-dim); }

@media (max-width: 820px) {
  .sched-layout { flex-direction: column; }
  .sched-pool { flex: 1 1 auto; width: 100%; max-height: 40vh; }
  .sched-worklist { flex-basis: auto; width: 100%; max-height: none; }
  .sched-main { max-height: none; }
}

/* ---------- Users (admin) ---------- */
.users-wrap { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow-x: auto; }
.users-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.users-table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); font-weight: 700; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.users-table td { padding: 11px 16px; border-bottom: 1px solid var(--border); }
.users-table tr:last-child td { border-bottom: none; }
.u-name { font-weight: 600; color: var(--text); }
.u-you { font-size: 10px; font-weight: 700; text-transform: uppercase; color: var(--accent); background: var(--accent-dim); border-radius: 4px; padding: 1px 6px; margin-left: 4px; }
.role-badge { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 20px; }
.role-badge.admin { background: var(--overdue-bg); color: var(--overdue); }
.role-badge.planner { background: var(--accent-dim); color: var(--accent); }
.role-badge.viewer { background: var(--surface-2); color: var(--text-dim); }
.u-actions { text-align: right; white-space: nowrap; }
.u-actions button { width: 30px; height: 30px; border: 1px solid var(--border); background: var(--surface); border-radius: var(--radius-sm); cursor: pointer; font-size: 13px; color: var(--text-dim); margin-left: 4px; }
.u-actions button:hover:not(:disabled) { background: var(--surface-2); border-color: var(--accent); color: var(--text); }
.u-actions button:disabled { opacity: .35; cursor: not-allowed; }

/* Machine capacity config (reuses .users-wrap / .users-table) */
.m-name { font-weight: 600; color: var(--text); }
.m-group { color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.m-mode-same { color: var(--text-faint); font-size: 12px; }
.m-mode-select { padding: 6px 8px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 14px; }
.m-cap-input { width: 96px; padding: 6px 8px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 14px; }
.m-cap-input:disabled { opacity: .55; cursor: not-allowed; }
.m-actions { white-space: nowrap; }
.m-save { padding: 6px 14px; border: 1px solid var(--border-strong); background: var(--surface); border-radius: var(--radius-sm); cursor: pointer; font-size: 13px; color: var(--text-dim); }
.m-save:hover { background: var(--surface-2); border-color: var(--accent); color: var(--text); }
.m-status { margin-left: 10px; font-size: 12px; font-weight: 600; color: var(--text-dim); }
.m-status.ok { color: var(--accent); }
.m-status.err { color: var(--overdue); }
.m-empty { text-align: center; color: var(--text-dim); padding: 28px 16px; }

/* Off-canvas sidebar on narrow screens */
@media (max-width: 900px) {
  .nav-toggle { display: inline-block; }
  .sidebar {
    position: fixed; left: 0; top: var(--header-h, 68px); z-index: 19;
    transform: translateX(-100%); transition: transform .2s ease;
    box-shadow: var(--shadow-lg);
  }
  .sidebar.open { transform: translateX(0); }
  /* The drawer is either open or off-screen; a rail makes no sense here. */
  .sidebar.collapsed { flex-basis: 224px; width: 224px; padding: 18px 12px; }
  .sidebar.collapsed .nav-group-label, .sidebar.collapsed .nav-item > span:not(.nav-ico) { display: revert; }
  .sidebar.collapsed .nav-item { justify-content: flex-start; padding: 9px 10px; }
  .nav-collapse { display: none; }
  .content { max-width: none; padding: 18px; }
  .subtitle { display: none; }
}

/* ---- Schedule: KPI strip + priority worklist (Build 1b) ---- */
.sched-kpi { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 10px; }
.sched-kpi .kpi { font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 14px; background: var(--surface-2); color: var(--text); border: 1px solid var(--border); }
.sched-kpi .kpi.late { background: var(--overdue-bg); color: var(--overdue); border-color: var(--overdue); }
.sched-kpi .kpi.conflict { background: var(--overdue-bg); color: var(--overdue); border-color: var(--overdue); }
.sched-kpi .kpi.unsched { background: var(--accent-dim); color: var(--accent); border-color: var(--accent); }
.sched-kpi .kpi.atrisk { background: var(--active-bg); color: var(--active); border-color: var(--active); }
.sched-kpi .kpi[data-zero] { opacity: .5; background: var(--surface-2); color: var(--text-dim); border-color: var(--border); }

.sched-worklist { flex: 0 0 260px; max-height: calc(100vh - var(--sched-fold, 30vh) - 24px); overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); padding: 8px; }
/* Collapsed backlog: a rail, not a removal. The panel node stays in place and
   keeps its drop wiring, so unbooking by dropping still works at rail width. */
.sched-worklist.collapsed { flex-basis: 34px; width: 34px; padding: 8px 2px; overflow: hidden; }
.sched-worklist.collapsed > * { display: none; }
.sched-worklist.collapsed::after { content: attr(data-rail); display: block; writing-mode: vertical-rl;
  transform: rotate(180deg); margin: 4px auto; font-size: 11px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint); white-space: nowrap; }
.sched-backlog-toggle { margin-left: auto; }
/* A nav button counting down to a page turn under a live drag. */
.sc-nav.nav-dwell { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); }
/* Below the stacking breakpoint the backlog sits ABOVE the board, so collapsing
   buys no board width -- it would leave a 34px stub with a sideways label. These
   rules must come AFTER the .collapsed rules above: same specificity, so source
   order decides, and the earlier schedule media block loses. */
@media (max-width: 640px) {
  .sched-worklist.collapsed { flex-basis: auto; width: 100%; padding: 8px; overflow: visible; overflow-y: auto; }
  .sched-worklist.collapsed > * { display: revert; }
  .sched-worklist.collapsed::after { content: none; }
  .sched-backlog-toggle { display: none; }
}
.wl-head { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); margin-bottom: 6px; }
.wl-group { margin-bottom: 10px; }
.wl-group-label { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim); padding: 2px 0; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
/* Critical tier (2d): loudest thing in the worklist. */
.wl-group.critical .wl-group-label { color: var(--overdue); font-weight: 700; }
.wl-group.veryhigh .wl-group-label, .wl-group.high .wl-group-label { color: var(--overdue); }
.wl-order { border: 1px solid var(--border); border-radius: var(--radius-sm); margin-bottom: 5px; background: var(--surface-2); }
.wl-order-head { display: flex; align-items: center; gap: 6px; padding: 4px 6px; flex-wrap: wrap; }
.wl-order-no { font-weight: 700; font-size: 13px; }
/* min-width is a floor, not 0: the head is flex-wrap, and a zero floor let the name
   collapse to "S.." so the tier <select> could stay on line 1. Give the name a readable
   minimum and let the select wrap instead -- the name is the useful half. */
.wl-order-name { color: var(--text-dim); font-size: 12px; flex: 1; min-width: 7rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-tier { font-size: 11px; padding: 2px 4px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); }
.wl-order-ops { padding: 2px 4px 4px; }
.wl-op { display: flex; flex-direction: column; gap: 2px; padding: 4px; border-radius: var(--radius-sm); cursor: pointer; }
.wl-op:hover { background: var(--surface); outline: 1px solid var(--accent); }
.wl-op-main { display: flex; gap: 6px; font-size: 11px; color: var(--text-dim); flex-wrap: wrap; }
.wl-op-hrs { font-variant-numeric: tabular-nums; opacity: .85; }
.wl-op-art { display: block; font-size: 10px; color: var(--text-dim); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wl-op-cov { display: flex; align-items: center; gap: 6px; }
.wl-covbar { flex: 1; height: 6px; background: var(--surface); border-radius: 3px; overflow: hidden; }
.wl-covfill { display: block; height: 100%; background: var(--accent); }
.wl-covfill.ontime { background: var(--accent); }
.wl-covfill.partial { background: var(--active); }
.wl-covfill.late { background: var(--overdue); }
.wl-pill { font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 10px; white-space: nowrap; }
.wl-pill.unscheduled { background: var(--surface); color: var(--text-dim); border: 1px solid var(--border); }
.wl-pill.partial { background: var(--active-bg); color: var(--active); }
.wl-pill.ontime { background: var(--accent-dim); color: var(--accent); }
.wl-pill.late { background: var(--overdue-bg); color: var(--overdue); }
/* Engine risk line under an order head (2b, simulate-only) */
.wl-risk { font-size: 11px; padding: 1px 8px 3px; }
.wl-risk.atrisk { color: var(--active); }
.wl-risk.blocked { color: var(--text-dim); }
.wl-risk.late { color: var(--overdue); }
.wl-empty { color: var(--text-dim); font-size: 13px; padding: 16px 8px; text-align: center; }
/* Lifts the worklist's display cap (see CARD_CAP in js/schedule-worklist.js). */
.wl-more { display: block; width: 100%; margin: 6px 0 2px; padding: 7px 8px; font: inherit; font-size: 12px; font-weight: 600;
  color: var(--text-dim); background: var(--surface-2); border: 1px dashed var(--border); border-radius: var(--radius-sm); cursor: pointer; }
.wl-more:hover { color: var(--text); border-color: var(--accent); }

/* ---- Schedule: half-day timeline (Build 1c-a) ---- */
/* overflow in BOTH axes: the date and AM/PM headers below are sticky against
   this wrapper, and only a wrapper that scrolls vertically can hold them in
   place. flex/min-height let .sched-main's max-height shrink it. */
.sched-timelinewrap { flex: 1 1 auto; min-height: 0; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
/* min-content, NOT max-content: the tracks below are minmax(84px, 1fr), so
   min-content is the sum of those fixed 84px floors. Under max-content the
   widest bar LABEL sized every column instead (154px each, three days of a
   week visible); the bars already truncate, they just never got the chance.
   1fr still lets columns grow whenever the board has room to spare. */
.tl-grid { display: grid; min-width: min-content; font-size: 12px; position: relative; }
/* The rubber band is positioned against the grid, not the viewport, so it
   stays anchored to the board when the timeline is scrolled sideways. */
.tl-marquee { position: absolute; z-index: 3; pointer-events: none;
  border: 1px solid var(--accent); background: var(--accent-dim); opacity: .45; }
.tl-pickable { cursor: pointer; }
/* Not qualified for the work currently being dragged. Guidance only -- the cell
   stays a valid drop target, because a hand placement always wins here. */
.tl-dim { opacity: .38; }
.tl-pickable:hover { background: var(--accent-dim); }
.tl-corner { grid-row: 1 / span 2; position: sticky; left: 0; top: 0; z-index: 3; background: var(--surface-2); border-bottom: 1px solid var(--border); }
/* Row 1: the date, spanning its day's two half columns. */
.tl-daylabel { grid-row: 1; grid-column: span 2; position: sticky; top: 0; z-index: 2; text-align: center; padding: 4px 2px; background: var(--surface); border-bottom: 1px solid var(--border); border-left: 2px solid var(--border-strong); }
.tl-daylabel.weekend { background: var(--surface-2); }
.tl-daylabel.today { background: var(--accent-dim); }
/* Row 2: the AM / PM sub-columns (sticks just below the ~22px date row). */
.tl-half { grid-row: 2; position: sticky; top: 22px; z-index: 2; text-align: center; padding: 3px 2px; background: var(--surface); border-bottom: 1px solid var(--border); border-left: 1px solid var(--border); color: var(--text-dim); font-size: 10px; }
.tl-half.tl-daystart { border-left: 2px solid var(--border-strong); }
.tl-half.weekend { background: var(--surface-2); }
.tl-half.today { background: var(--accent-dim); }
.tl-wd { display: block; font-weight: 700; font-size: 11px; color: var(--text); }
/* Orders due that day: the glyph carries a title listing them; the padding
   makes a 10px diamond a hoverable target. The count appears past one order. */
.tl-due { color: var(--overdue); display: inline-flex; align-items: center; gap: 2px; padding: 0 4px; }
.tl-due-n { font-size: 10px; font-weight: 700; }
.tl-sec { grid-column: 1 / -1; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); background: var(--surface-2); padding: 3px 8px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.tl-rowlabel { position: sticky; left: 0; z-index: 1; background: var(--surface); display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-bottom: 1px solid var(--border); font-weight: 600; white-space: nowrap; }
.tl-mc { color: var(--text-dim); font-weight: 600; }
/* The plan grid dialog's row avatar (.am-dot) shares this rule rather than
   restating it: three copies of "round initials chip" would drift apart. */
.tl-dot, .am-dot { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; color: #fff; font-size: 10px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
.tl-cell { border-bottom: 1px solid var(--border); border-left: 1px solid var(--border); padding: 2px; min-height: 30px; display: flex; flex-direction: column; gap: 2px; }
.tl-cell.today { background: color-mix(in srgb, var(--accent-dim) 40%, var(--surface)); }
.tl-cell.weekend { background: var(--surface-2); }
.tl-cell.overbooked { background: var(--overdue-bg); }
.tl-bar { border-radius: 4px; padding: 2px 5px; font-size: 11px; color: #fff; cursor: pointer; white-space: nowrap; overflow: hidden; background: var(--accent); display: flex; align-items: center; gap: 4px; min-width: 0; max-width: 100%; box-sizing: border-box; }
/* Two lines: order · op on top, pieces · hours beneath. Each line truncates on
   its own; the affordances after them (↷, pin, ⋯) never do. */
.tl-bar-label { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.tl-bar-main, .tl-bar-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-bar-meta { font-size: 10px; opacity: .85; font-variant-numeric: tabular-nums; }
.tl-bar.ontime { background: var(--accent); }
.tl-bar.partial { background: var(--active); }
.tl-bar.late { background: var(--overdue); }
.tl-bar.unscheduled { background: var(--text-dim); }
.tl-bar:hover { outline: 2px solid var(--text); }
.tl-bar.selected { outline: 2px solid var(--text); outline-offset: 1px; box-shadow: 0 0 0 3px var(--accent-dim); }
.sched-selcount { display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; padding: 2px 6px;
  border-radius: var(--radius); background: var(--accent-dim); font-size: 12px; font-weight: 600; }
.sched-selclear { background: none; border: 0; color: var(--text-dim); font-size: 15px; line-height: 1; cursor: pointer; padding: 0 2px; }
.sched-selclear:hover { color: var(--text); }
/* Machine-only booking awaiting an operator: hatched + dashed. */
.tl-bar.tl-noop {
  background: repeating-linear-gradient(135deg, var(--surface-2) 0 6px, transparent 6px 12px);
  border: 1px dashed var(--text-dim);
  color: var(--text);
}
.tl-mcell { align-items: flex-start; }
/* flex-start lets a lane booking size to its text and spill past the slot; stretch it like a person's bar. */
.tl-mcell > .tl-bar { align-self: stretch; }
.tl-mcell.conflict { outline: 2px solid var(--overdue); outline-offset: -2px; }
.tl-mbar { display: block; height: 5px; width: 100%; border-radius: 2px; background: var(--accent); }
.tl-mbar.partial { background: var(--active); }
.tl-mbar.late { background: var(--overdue); }
.tl-mbar.unscheduled { background: var(--text-dim); }
.tl-occ { font-size: 10px; color: var(--text-dim); }
.tl-occ.over { color: var(--overdue); font-weight: 700; }

/* Worklist filter bar */
.wl-filters { display: flex; gap: 4px; margin-bottom: 6px; }
.wl-search { display: block; width: 100%; box-sizing: border-box; margin-bottom: 6px; padding: 4px 6px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 12px; }
.wl-center { flex: 1; min-width: 0; padding: 4px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 12px; }

/* ---- Schedule: timeline drag-and-drop (Build 1c-b) ---- */
.tl-bar[draggable="true"] { cursor: grab; }
.tl-bar[draggable="true"]:active { cursor: grabbing; }
.tl-cell.drop-target { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--accent-dim); }

/* Engine-owned (unpinned) bars are visually lighter than hand-pinned ones. */
.tl-bar.tl-engine { opacity: .72; }
.tl-pin { flex: 0 0 auto; cursor: pointer; font-size: 10px; opacity: .85; }
.tl-pin:hover { opacity: 1; }
.tl-seqwarn { flex: 0 0 auto; font-size: 10px; color: var(--active); font-weight: 700; }
.wl-op[draggable="true"] { cursor: grab; }
.wl-op[draggable="true"]:active { cursor: grabbing; }
.sched-worklist.wl-drop { outline: 2px dashed var(--overdue); outline-offset: -2px; }

/* ---- Schedule: per-cell booked/available hours (Build 1d-2) ---- */
.tl-cellhrs { align-self: flex-end; margin-top: auto; font-size: 9px; line-height: 1.1; color: var(--text-faint); }
.tl-cellhrs.over { color: var(--overdue); font-weight: 700; }

/* ---- Schedule: KPI chip filters + pulsing highlight (Build 1d-3) ---- */
.sched-kpi .kpi { cursor: pointer; }
.sched-kpi .kpi[disabled] { cursor: default; }
.sched-kpi .kpi.on { box-shadow: 0 0 0 2px var(--text) inset; }
.wl-priority { flex: 1; min-width: 0; padding: 4px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 12px; }
.wl-showassigned { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; font-size: 12px; color: var(--text-dim); }
@keyframes kpi-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  50% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent); }
}
.kpi-hi { animation: kpi-pulse 1.2s ease-in-out infinite; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) { .kpi-hi { animation: none; box-shadow: 0 0 0 2px var(--accent); } }

/* Ångra-historik panel (schedule-history.js) */
.hist-card { width: min(760px, 94vw); max-width: none; position: relative; }
/* position:relative is load-bearing: .hist-close reuses .drawer-close, which is
   position:absolute for the drawer (a fixed element). Without a positioned card the
   button escapes to .modal-backdrop and lands over the app header. Same fix .am-card
   already carries. The width lets an entry show WHO changed it, which §2.9 promises. */
.hist-note { margin: 0 0 12px; font-size: 13px; color: var(--text-dim); }
.hist-empty { margin: 0; color: var(--text-dim); }
.hist-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; max-height: 60vh; overflow-y: auto; }
.hist-row { display: grid; grid-template-columns: 52px minmax(0, 1fr) auto auto auto; gap: 10px; align-items: center; padding: 7px 8px; border-radius: var(--radius-sm); font-size: 13px; }
.hist-row:nth-child(odd) { background: var(--surface-2); }
.hist-row.now { outline: 1px solid var(--accent); }
.hist-time { font-variant-numeric: tabular-nums; color: var(--text-dim); }
.hist-what { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-who { color: var(--text-dim); white-space: nowrap; }
.hist-rows { font-variant-numeric: tabular-nums; color: var(--text-dim); white-space: nowrap; }
.hist-trail { display: flex; align-items: center; gap: 8px; }
.hist-current { font-size: 12px; color: var(--accent); white-space: nowrap; }

/* Import mode dialog: two selectable cards, the destructive one marked. */
.import-modes { display: grid; gap: 10px; margin: 14px 0 18px; }
.import-mode { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; }
.import-mode:has(input:checked) { border-color: var(--accent); }
.import-mode input { margin-top: 3px; flex: none; accent-color: var(--accent); }
.import-mode-body { display: grid; gap: 3px; font-size: 13px; }
.import-mode-body b { font-size: 13.5px; }
.import-mode-body > span { color: var(--text-dim); }
.import-mode-danger:has(input:checked) { border-color: var(--overdue); background: var(--overdue-bg); }
.import-mode-disabled { opacity: 0.55; cursor: not-allowed; }
.import-mode-disabled input { cursor: not-allowed; }
.import-mode-body > span.import-mode-warn { color: var(--overdue); font-weight: 600; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; }

/* Post-import banner: what a clean slate removed, and the way back. */
.import-result { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 320; display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 10px 14px; font-size: 13px; }
.import-result[hidden] { display: none; }
.import-result-x { background: none; border: 0; color: var(--text-dim); font-size: 18px;
  line-height: 1; cursor: pointer; padding: 0 2px; }
.import-result-x:hover { color: var(--text); }

/* Group-move spill notice. Same language as the post-import banner. */
.sched-toast { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  z-index: 320; display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 10px 14px; font-size: 13px; }
.sched-toast[hidden] { display: none; }

/* ---- Schedule: bar menu, join target, toast actions (Build 2a) ---- */
/* The handle stays in the DOM at opacity 0 rather than display:none — it carries
   tabindex="0", so keyboard users must still be able to reach and focus it. */
/* Collapsed to zero width until the bar is hovered, focused, or has its menu open, so the
   label keeps the room; still in the tab order (not display:none) for keyboard users. The
   negative margin swallows the flex gap while collapsed. Touch users long-press instead. */
.tl-handle { flex: 0 0 auto; font-size: 10px; line-height: 1; cursor: pointer; width: 0; margin-left: -4px; overflow: hidden; opacity: 0; }
.tl-bar:hover .tl-handle, .tl-bar:focus-within .tl-handle, .tl-handle[aria-expanded="true"] { width: auto; margin-left: 0; opacity: .9; }
.tl-handle:hover { opacity: 1; }
.tl-handle:focus, .tl-handle:focus-visible { width: auto; margin-left: 0; opacity: 1; outline: 2px solid var(--text); outline-offset: 1px; }

/* Anchored popover. z-index sits above .sched-toast (320) so a menu opened while a
   partial-drop toast is still up is not covered by it. */
.tl-menu { position: fixed; z-index: 340; min-width: 180px; padding: 4px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: 13px; }
.tl-menu[hidden] { display: none; }
.tl-menu-item { display: flex; justify-content: space-between; align-items: center; gap: 12px;
  width: 100%; padding: 7px 10px; background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--text); font-size: 13px; text-align: left; cursor: pointer; }
.tl-menu-item:hover:not([disabled]) { background: var(--surface-2); }
.tl-menu-item:focus { background: var(--surface-2); }
.tl-menu-item[disabled] { color: var(--text-dim); cursor: default; opacity: .7; }
.tl-menu-hint { color: var(--text-dim); font-size: 11px; white-space: nowrap; }

/* ---- Bar menu extras (Phase 3): second level, divider, Split… popover ---- */
/* Second level: the "Ge till… / Hand to…" person list, opened inside the same .tl-menu.
   A copy of .am-menu-sub under the tl- prefix (the two menus are deliberate copies rather
   than shared selectors), plus a height cap: positionMenu measures with
   getBoundingClientRect() AFTER the element is shown, so a capped list clamps against the
   viewport with no extra work — an uncapped roster would run off the screen instead. */
.tl-menu-sub { display: flex; flex-direction: column; margin-top: 2px; padding-top: 2px;
  border-top: 1px solid var(--border); max-height: 60vh; overflow-y: auto; }
/* Rule above "Ta bort från tavlan" once the menu grows past the phase-1 two items. */
.tl-menu-sep { height: 1px; margin: 4px 2px; background: var(--border); }
/* Label side of a person row. The avatar circle is .tl-dot (shared with .am-dot above) and
   is deliberately not restated here. min-width:0 lets the ellipsis win, so a long name
   cannot push the free-pieces hint off the popover. */
.tl-menu-name { display: flex; align-items: center; gap: 8px; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Split… popover. It lives inside .tl-menu, so it inherits that frame, the z-index (340,
   above the toast) and the viewport clamping rather than restating any of them. */
.tl-split { display: flex; flex-direction: column; gap: 8px; padding: 6px; min-width: 220px; }
/* .am-cellinput's appearance resets and focus ring, but framed: this field stands alone
   instead of sitting inside a grid cell that already draws a border around it. */
.tl-split-input { width: 100%; box-sizing: border-box; padding: 6px 8px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text); font: inherit; text-align: left;
  -moz-appearance: textfield; appearance: textfield; }
.tl-split-input::-webkit-outer-spin-button,
.tl-split-input::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
.tl-split-input:focus { outline: none;
  box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 3px var(--accent-dim); }
.tl-split-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.tl-split-chip { padding: 4px 9px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface-2); color: var(--text); font-size: 12px; cursor: pointer; }
.tl-split-chip:hover:not([disabled]) { background: var(--surface); }
.tl-split-chip:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Same disabled treatment as .tl-menu-item[disabled], so a greyed chip reads like a greyed row. */
.tl-split-chip[disabled] { color: var(--text-dim); cursor: default; opacity: .7; }
/* The reserved line height is deliberate: the hint is rewritten on every keystroke and the
   popover must not jump under the planner's cursor mid-type. */
.tl-split-hint { color: var(--text-dim); font-size: 11px; min-height: 14px; }
/* .am-footer's right-aligned button row at popover scale (Split / Cancel). */
.tl-split-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Sibling bar of the dragged part: same idiom as .tl-cell.drop-target, but the bar keeps
   its own status colour, so the halo goes outside instead of on the background. */
.tl-bar.tl-join-target { outline: 2px dashed var(--accent); outline-offset: -2px; box-shadow: 0 0 0 3px var(--accent-dim); }

/* Floating "Join → N st" label. A native title does not render mid-drag and .tl-bar has
   overflow:hidden, so this cannot be a ::after on the bar — it is a fixed sibling layer. */
.tl-join-tip { position: fixed; z-index: 340; pointer-events: none; padding: 3px 8px;
  background: var(--surface); color: var(--text); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); font-size: 12px; white-space: nowrap; }
.tl-join-tip[hidden] { display: none; }

/* Toast action buttons: applied alongside .btn-ghost, so only the size differs. */
.sched-toast-actions { display: flex; align-items: center; gap: 8px; }
.sched-toast-action { padding: 5px 10px; font-size: 12px; border-radius: var(--radius-sm); }

/* ---------- Plan grid dialog (Phase 2) ---------- */
/* The allocation dialog is a small spreadsheet of PIECES: people down the side,
   the visible week's half-days across the top. Everything below is the timeline's
   own grid one size smaller (see .tl-grid / .tl-menu above) — deliberately a
   copy under an am- prefix rather than shared selectors, so a change to the board
   cannot silently reshape the dialog. Every colour is a theme token, which is why
   this block needs no dark-theme override at all.
   The row avatar reuses the .tl-dot rule; it is not restated here. */

/* ---- Budget strip: pieces are the promise, hours are only an estimate ---- */
.am-budget { margin: 6px 0 14px; display: flex; flex-direction: column; gap: 5px; }
.am-budget-title { font-size: 15px; font-weight: 700; color: var(--text); }
.am-budget-counts { font-size: 12px; font-weight: 600; color: var(--text-dim); }
.am-budget-over { color: var(--overdue); font-weight: 700; }
/* The hours estimate is a chip, not a headline: it is derived from a rate the
   shop does not trust, and must never read like the number to hit. */
.am-budget-chip { align-self: flex-start; padding: 2px 8px; border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text-dim); font-size: 11px; }

/* ---- Week nav ---- */
.am-weeknav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.am-week-range { flex: 1 1 auto; text-align: center; font-size: 13px; font-weight: 700; color: var(--text); }
/* Link-styled: paging to a part in another week is navigation, not a command. */
.am-otherweeks { background: none; border: 0; padding: 0; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; }
.am-otherweeks:hover { text-decoration: underline; }

/* ---- People filter ---- */
.am-peoplefilter { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: 11px; color: var(--text-faint); }
.am-showall { background: none; border: 0; padding: 0; color: var(--accent); font-size: 11px; font-weight: 600; cursor: pointer; }
.am-showall:hover { text-decoration: underline; }

/* ---- The grid ---- */
/* A narrow screen scrolls THIS, never the page: the wrapper is the only
   overflow-x in the dialog and the grid inside it is min-content wide. */
.am-gridwrap { overflow-x: auto; max-height: 52vh; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.am-grid { display: grid; min-width: min-content; font-size: 12px; position: relative; }
/* grid-template-columns is set inline by JS (row label + 2 per day + Total). */

/* Header cell over the row labels — reads PIECES (ST) or HOURS. */
.am-corner { grid-row: 1 / span 2; position: sticky; left: 0; top: 0; z-index: 3; display: flex; align-items: flex-end; padding: 4px 8px; background: var(--surface-2); border-bottom: 1px solid var(--border); font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
/* Row 1: the date, spanning its day's two half columns. */
.am-daylabel { grid-row: 1; grid-column: span 2; position: sticky; top: 0; z-index: 2; text-align: center; padding: 4px 2px; background: var(--surface); border-bottom: 1px solid var(--border); border-left: 2px solid var(--border-strong); font-weight: 700; font-size: 11px; color: var(--text); }
.am-daylabel.weekend { background: var(--surface-2); }
.am-daylabel.today { background: var(--accent-dim); }
/* Row 2: the FM / EM sub-columns, sticking just under the ~22px date row. */
.am-half { grid-row: 2; position: sticky; top: 22px; z-index: 2; text-align: center; padding: 3px 2px; background: var(--surface); border-bottom: 1px solid var(--border); border-left: 1px solid var(--border); color: var(--text-dim); font-size: 10px; }
.am-half.am-daystart { border-left: 2px solid var(--border-strong); }
.am-totalhead { grid-row: 1 / span 2; position: sticky; top: 0; z-index: 2; display: flex; align-items: flex-end; justify-content: center; padding: 4px 6px; background: var(--surface-2); border-bottom: 1px solid var(--border); border-left: 2px solid var(--border-strong); font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }

.am-rowlabel { position: sticky; left: 0; z-index: 1; background: var(--surface); display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-bottom: 1px solid var(--border); font-weight: 600; white-space: nowrap; overflow: hidden; }
/* The name is the row's identity and keeps its natural width; the groups are
   a secondary property and take only what is left (flex-basis 0), truncating
   first. Only when the name alone is too wide does it shrink. */
.am-rowname { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.am-rowgroups { flex: 1 1 0; min-width: 0; font-size: 10px; font-weight: 500; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; }
.am-rowtotal { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 2px 6px; border-bottom: 1px solid var(--border); border-left: 2px solid var(--border-strong); background: var(--surface-2); font-weight: 700; }
/* The unstaffed lane sits last and is fenced off from the people above it. */
.am-machinerow { border-top: 2px solid var(--border-strong); color: var(--text-dim); }

/* ---- The six cell states (DIALOG-02) ---- */
.am-cell { border-bottom: 1px solid var(--border); border-left: 1px solid var(--border); padding: 1px; min-height: 34px; display: flex; flex-direction: column; align-items: stretch; justify-content: center; background: var(--surface); }
.am-cell.am-daystart { border-left: 2px solid var(--border-strong); }
.am-cell.placed { background: var(--accent-dim); color: var(--accent); font-weight: 700; }
/* free: nothing placed — the grey number is how many would fit, not a booking. */
.am-cell.free { background: var(--surface); color: var(--text-faint); }
/* over is allowed, only flagged: a hand placement always wins on this board. */
.am-cell.over { background: var(--overdue-bg); color: var(--overdue); font-weight: 700; }
.am-cell.absent { background: var(--surface-2); color: var(--text-faint); }
.am-cell.full { background: var(--queued-bg); color: var(--queued); }
/* The machine lane has no capacity, so it never paints over/full and shows no
   grey "fits" number — there is nothing to be full of. */
.am-cell.machine { background: var(--surface); color: var(--text-dim); }

/* The input is the cell: a visible box inside a 60px column would leave no room
   for the number. Spinners are stripped for the same reason. */
.am-cellinput { width: 100%; border: none; background: transparent; color: inherit; font: inherit; font-weight: inherit; text-align: center; padding: 1px 2px; -moz-appearance: textfield; appearance: textfield; }
.am-cellinput::-webkit-outer-spin-button,
.am-cellinput::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
/* The editing state, using the accent-ring focus recipe the rest of the app
   uses (see .team-form input:focus) — but INSET, because an outset ring would
   be clipped by the grid scroller. */
.am-cellinput:focus { outline: none; border-radius: var(--radius-sm); box-shadow: inset 0 0 0 1px var(--accent), inset 0 0 0 3px var(--accent-dim); }
.am-cellinput:disabled { cursor: default; caret-color: transparent; color: inherit; opacity: 1; }
/* The hours estimate / "fits N" line under the count. */
.am-cellsub { text-align: center; font-size: 10px; line-height: 1.1; font-weight: 400; color: inherit; opacity: .75; }

/* ---- Fill the rest menu ---- */
/* Fixed and above .modal-backdrop (300): the menu opens from inside the dialog,
   so anything at or below 300 would be painted under its own backdrop. 340 is
   the same level .tl-menu uses. */
.am-menu { position: fixed; z-index: 340; min-width: 200px; padding: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-lg); font-size: 13px; }
.am-menu[hidden] { display: none; }
.am-menu-item { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; padding: 7px 10px; background: none; border: 0; border-radius: var(--radius-sm); color: var(--text); font-size: 13px; text-align: left; cursor: pointer; }
.am-menu-item:hover:not([disabled]) { background: var(--surface-2); }
.am-menu-item:focus { background: var(--surface-2); }
/* Disabled means "nothing would fit" — the hint says so, so the row is greyed
   rather than hidden and the planner learns why. */
.am-menu-item[disabled] { color: var(--text-dim); cursor: default; opacity: .7; }
.am-menu-hint { color: var(--text-faint); font-size: 11px; white-space: nowrap; }
/* Second level: "Collect everything on one person…". */
.am-menu-sub { display: flex; flex-direction: column; margin-top: 2px; padding-top: 2px; border-top: 1px solid var(--border); }
