.spinner { width: 14px; height: 14px; border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 9999px; display: inline-block; animation: spin .7s linear infinite; vertical-align: -2px; }
@keyframes spin { to { transform: rotate(360deg); } }
.legend-swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; vertical-align: -1px; }

/* ------------------------------------------------------------------ Gantt */
.g-scroll { --row-h: 30px; --head-h: 60px; position: relative; overflow: auto;
  max-height: calc(100vh - 230px); min-height: 240px; font-size: 12px; border-top: 1px solid var(--line); }
.g-head, .g-row { display: flex; width: max-content; min-width: 100%; }
.g-head { position: sticky; top: 0; z-index: 20; height: var(--head-h); background: var(--surface-2);
  border-bottom: 1px solid var(--line-strong); }
/* The task grid is two blocks: .g-pin (the first column) and .g-rest (the other columns). Both stay put
   while the timeline scrolls sideways; on phones only the first column does. */
.g-left { position: sticky; z-index: 10; display: grid; flex: none; background: var(--surface); }
.g-pin { left: 0; grid-template-columns: var(--pin-cols); border-right: 1px solid var(--line); }
.g-rest { left: var(--pin-w); grid-template-columns: var(--rest-cols);
  border-right: 1px solid var(--line-strong); box-shadow: 2px 0 4px -2px rgba(0, 0, 0, .12); }
.g-head .g-left { z-index: 21; background: var(--surface-2); grid-template-rows: 30px 30px; }
/* Set by gantt.js when the columns would cover most of the grid: only the first column stays put. */
.g-pin-first-only .g-rest { position: static; z-index: auto; box-shadow: none; }  /* z-index would still stack this flex item over .g-pin */
.g-pin-first-only .g-pin { border-right-color: var(--line-strong); box-shadow: 2px 0 4px -2px rgba(0, 0, 0, .12); }

.g-th { display: flex; align-items: center; gap: 2px; padding: 0 6px; font-weight: 600; color: var(--ink-2);
  border-right: 1px solid var(--line); white-space: nowrap; overflow: hidden; user-select: none; }
.g-th { position: relative; }
.g-th.sortable { cursor: pointer; }
.col-resize { position: absolute; top: 0; right: -3px; width: 7px; height: 100%; cursor: col-resize; z-index: 2; }
.col-resize:hover { background: rgba(15, 97, 253, .35); }
.g-th.sortable:hover { background: var(--hover-strong); }
.g-th .sort-ind { color: var(--link); font-size: 10px; }
.g-tf { padding: 3px 3px; border-right: 1px solid var(--line); }
.g-tf input, .g-tf select { width: 100%; height: 22px; font-size: 11px; border: 1px solid var(--line-strong);
  border-radius: 0; padding: 0 4px; background: var(--surface); }
.g-tf input.active, .g-tf select.active { border-color: #0f61fd; background: var(--tint-blue); }
/* Multi-select filter: a button in the filter row that opens a checkbox list (.g-multi-pop on <body>) */
.g-multi { display: flex; align-items: center; justify-content: space-between; gap: 4px; width: 100%; height: 22px;
  font-size: 11px; border: 1px solid var(--line-strong); padding: 0 4px; background: var(--surface); color: var(--ink); text-align: left; }
.g-multi > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-multi.active { border-color: #0f61fd; background: var(--tint-blue); }
.g-multi-pop { position: fixed; z-index: 60; min-width: 170px; padding: 6px; font-size: 12px; background: var(--surface);
  color: var(--ink); border: 1px solid var(--line-strong); box-shadow: 0 6px 16px rgba(0, 0, 0, .2); }
.g-multi-pop[hidden] { display: none; }
.g-multi-pop label { display: flex; align-items: center; gap: 6px; padding: 3px 4px; cursor: pointer; }
.g-multi-pop label:hover { background: var(--hover); }
.g-multi-pop .badge { margin-left: 0; }
.g-multi-n { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.g-multi-actions { display: flex; justify-content: space-between; gap: 8px; margin-top: 4px; padding: 4px 4px 0;
  border-top: 1px solid var(--line-soft); }
.g-multi-actions button { color: var(--link); text-decoration: underline; font-size: 11px; }

.g-row { height: var(--row-h); border-bottom: 1px solid var(--line-soft); }
.g-row:hover .g-left, .g-row:hover .g-track { background-color: var(--hover); }
.g-row.same-order .g-left { background: var(--tint-blue-soft); }
.g-row.selected .g-left { background: var(--sel); }
.g-row.excluded .g-left { color: var(--faint); text-decoration: line-through; }
.g-td { display: flex; align-items: center; padding: 0 6px; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; border-right: 1px solid var(--line-soft); }
.g-td > span.trunc { overflow: hidden; text-overflow: ellipsis; }
.g-td.right { justify-content: flex-end; }
.g-td.center { justify-content: center; }
.g-td select { height: 22px; font-size: 11px; border: 1px solid var(--line-strong); border-radius: 0; padding: 0 2px; }
.g-td button.link { color: var(--link); text-decoration: underline; font-size: 11px; }
.g-td button.lock { font-size: 13px; line-height: 1; padding: 2px 4px; border-radius: 0; }
.g-td button.lock:hover { background: var(--line); }
.g-td button.lock.off { opacity: .35; }
.g-td button.lock.off:hover { opacity: 1; }
.badge { font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: .25rem; background: var(--badge-bg); color: var(--badge-ink); }
.badge.scheduled { background: var(--badge-sched-bg); color: var(--badge-sched-ink); }
.badge.manual { background: var(--badge-manual-bg); color: var(--badge-manual-ink); }
.badge.unscheduled { background: var(--badge-warn-bg); color: var(--badge-warn-ink); }
.badge.excluded { background: var(--badge-bg); color: var(--muted); }
.badge.late { background: var(--badge-late-bg); color: var(--badge-late-ink); margin-left: 3px; }
.badge.breakin { background: var(--badge-brk-bg); color: var(--badge-brk-ink); margin-left: 3px; }
.badge.backlog { background: var(--badge-late-bg); color: var(--badge-late-ink); margin-left: 3px; }
/* Maintenance class: preventive (PM) vs corrective (CM). */
.badge.pm { background: var(--badge-sched-bg); color: var(--badge-sched-ink); }
.badge.cm { background: var(--badge-brk-bg); color: var(--badge-brk-ink); }

/* timeline */
.g-time { position: relative; flex: none; }
.g-time-row { display: flex; height: 20px; }
.g-time-cell { flex: none; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); color: var(--ink-3);
  font-size: 11px; display: flex; align-items: center; justify-content: center; overflow: hidden; white-space: nowrap; }
.g-time-cell.week { font-weight: 600; justify-content: flex-start; padding-left: 6px; border-right-color: var(--faint); }
.g-time-cell.weekend { background: var(--weekend-cell); }
.g-time-cell.night { background: var(--night-cell); color: var(--ink-2); }
.g-track { position: relative; flex: none;
  background-image:
    linear-gradient(to right, var(--faint) 1px, transparent 1px),
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    repeating-linear-gradient(to right, transparent 0 var(--sw), var(--night-stripe) var(--sw) calc(var(--sw) * 2));
  background-size: calc(var(--sw) * 14) 100%, calc(var(--sw) * 2) 100%, auto; }
.g-now { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--now-line); z-index: 5; pointer-events: none; }

.g-bar { position: absolute; top: 5px; height: 20px; border-radius: 4px; background: var(--bar-other);
  color: #fff; font-size: 10px; line-height: 20px; padding: 0 4px; white-space: nowrap; overflow: hidden;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25); touch-action: none; }
.g-bar.scheduled { background: var(--bar-scheduled); }
.g-bar.manual { background: var(--bar-manual); }
.g-bar.late { background: var(--bar-late); }
.g-bar.locked { outline: 2px dashed var(--bar-lock-ring); outline-offset: 1px; }
.g-bar.saving { opacity: .55; }
.g-bar.dragging { opacity: .85; box-shadow: 0 4px 10px rgba(0, 0, 0, .35); z-index: 6; }
.g-scroll:not(.g-readonly) .g-bar { cursor: grab; touch-action: none; }
.g-scroll:not(.g-readonly) .g-bar.dragging { cursor: grabbing; }
.g-handle { position: absolute; top: 0; bottom: 0; width: 7px; cursor: ew-resize; }
.g-handle.l { left: 0; } .g-handle.r { right: 0; }
.g-scroll:not(.g-readonly) .g-bar:hover .g-handle { background: rgba(255, 255, 255, .35); }
.g-readonly .g-handle, .g-bar.narrow .g-handle { display: none; }
.g-bar-label { position: absolute; top: 0; line-height: var(--row-h); font-size: 10px; color: var(--ink-3);
  white-space: nowrap; pointer-events: none; }
.g-offscreen { position: absolute; top: 7px; font-size: 10px; color: var(--muted); }
.g-empty { padding: 40px; text-align: center; color: var(--muted); position: sticky; left: 0; }

.g-tooltip { position: fixed; z-index: 60; max-width: 320px; background: var(--tooltip-bg); color: var(--tooltip-ink); font-size: 11px;
  border-radius: 0; padding: 8px 10px; pointer-events: none; box-shadow: 0 6px 16px rgba(0, 0, 0, .3); }
.g-tooltip .k { color: var(--tooltip-key); }
.g-tooltip .alert { color: var(--tooltip-alert); font-weight: 700; }

/* ------------------------------------------------------------------ Dashboard */
.dash-card { background: var(--surface); border-radius: 0; box-shadow: 0 1px 3px var(--shadow), 0 0 0 1px var(--card-ring, transparent); padding: 16px; }
.dash-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.dash-card-head h2 { font-weight: 600; color: var(--ink); }
.dash-sub { font-size: 12px; color: var(--ink-3); margin: 2px 0 8px; }
/* Chart cards: the chart fills whatever height the card has left (cards in a grid row share the
 * tallest one's height); the min-height (220px, 16rem for .tall, or per-bar from dashboard.js) is the
 * floor. The canvas is taken out of flow so it never props the card open itself. */
.dash-card:has(> .dash-chart) { display: flex; flex-direction: column; }
.dash-chart { position: relative; width: 100%; flex: 1 1 auto; min-height: 220px; }
.dash-chart.tall { min-height: 16rem; }
.dash-chart > canvas { position: absolute; inset: 0; }
.seg { margin-left: auto; display: inline-flex; border: 1px solid var(--line-strong); border-radius: 0; overflow: hidden; font-size: 12px; }
.seg button { padding: 2px 10px; color: var(--ink-2); }
.seg button + button { border-left: 1px solid var(--line-strong); }
.seg button.on { background: var(--ink); color: var(--surface); }
.kpi { background: var(--surface); border-radius: 0; box-shadow: 0 1px 3px var(--shadow), 0 0 0 1px var(--card-ring, transparent); padding: 12px 14px; }
.kpi-label { font-size: 12px; color: var(--ink-3); }
.kpi-value { font-size: 26px; font-weight: 600; color: var(--ink); line-height: 1.2; margin-top: 2px; }
.kpi-sub { font-size: 11px; color: var(--muted); }
/* Maintenance KPI cards (dashboard): headline figures, backlog per work centre, PM / CM split. */
.mk-figures { display: flex; flex-wrap: wrap; gap: 8px 32px; margin-bottom: 12px; }
.mk-bars { display: grid; grid-template-columns: minmax(48px, auto) 1fr auto; gap: 4px 8px; align-items: center; font-size: 12px; }
.mk-bar { height: 10px; background: var(--line-soft); position: relative; }
.mk-bar > span { position: absolute; inset: 0 auto 0 0; background: var(--chart-blue); }
.mk-split { display: flex; height: 14px; background: var(--line-soft); overflow: hidden; }
.mk-split > span + span { border-left: 2px solid var(--surface); }
.mk-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 12px; color: var(--ink-2); margin-top: 6px; }
.mk-swatch { display: inline-block; width: 10px; height: 10px; margin-right: 4px; vertical-align: -1px; }
.mk-pm { background: var(--chart-blue); }
.mk-cm { background: var(--chart-orange); }
.mk-other { background: var(--chart-pnone); }
/* Gantt metrics strip: follows the grid's filters. */
.g-metrics { display: flex; flex-wrap: wrap; border-bottom: 1px solid var(--line); font-size: 12px; }
.g-metric { display: flex; flex-direction: column; justify-content: center; padding: 6px 14px; border-right: 1px solid var(--line); text-align: left; }
.g-metric-label { font-size: 11px; color: var(--ink-3); }
.g-metric-value { font-size: 16px; font-weight: 600; color: var(--ink); line-height: 1.25; font-variant-numeric: tabular-nums; }
.g-metric-value small { font-size: 11px; font-weight: 400; color: var(--ink-3); }
.g-metric-sub { font-size: 11px; color: var(--muted); }
button.g-metric:not(:disabled):hover { background: var(--hover); }
button.g-metric.active { background: var(--tint-blue); box-shadow: inset 0 -2px 0 #0f61fd; }
.check { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 0; font-size: 13px; background: var(--surface); }
.check:not(:disabled):hover { background: var(--hover); border-color: var(--line-strong); }
.check.active { border-color: #0f61fd; background: var(--tint-blue); }
.check.zero { color: var(--muted); }
.check-count { font-weight: 600; font-variant-numeric: tabular-nums; }
.dash-table { width: 100%; font-size: 12px; border-collapse: separate; border-spacing: 0; }
.dash-table th { position: sticky; top: 0; background: var(--surface-2); text-align: left; font-weight: 600; color: var(--ink-2);
  padding: 6px 8px; border-bottom: 1px solid var(--line-strong); white-space: nowrap; cursor: pointer; user-select: none; }
.dash-table th:hover { background: var(--hover-strong); }
.dash-table td { padding: 4px 8px; border-bottom: 1px solid var(--line-soft); white-space: nowrap; max-width: 260px;
  overflow: hidden; text-overflow: ellipsis; }
.dash-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.dash-table tr.excluded td { color: var(--faint); }
.dash-table tbody tr:hover td { background: var(--hover); }
.issue { font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: .25rem; background: var(--badge-warn-bg); color: var(--badge-warn-ink); }
/* Home page: asset cards (each card is the submit button of its own form) */
.asset-card { display: flex; flex-direction: column; gap: 12px; width: 100%; height: 100%; text-align: left; padding: 16px;
  background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow), 0 0 0 1px var(--card-ring, transparent);
  border-top: 3px solid transparent; transition: box-shadow .12s, border-color .12s; }
.asset-card:hover { box-shadow: 0 4px 12px var(--shadow), 0 0 0 1px var(--line-strong); border-top-color: var(--wg-blue); }
.asset-card.current { border-top-color: var(--wg-blue); }
.asset-name { font-size: 18px; font-weight: 600; line-height: 1.3; }
.asset-desc { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.asset-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.asset-stats dt { font-size: 11px; color: var(--ink-3); }
.asset-stats dd { font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }
.asset-flags { display: flex; flex-wrap: wrap; gap: 4px; min-height: 18px; }
.asset-flags .badge { margin-left: 0; }
.asset-foot { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 12px; margin-top: auto;
  padding-top: 10px; border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--ink-3); }
.asset-open { color: var(--link); font-weight: 600; }

/* Plan lock banner (Gantt + dashboard) */
.plan-lock-banner { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 10px 14px; font-size: 13px;
  background: var(--badge-manual-bg); color: var(--badge-manual-ink); border-left: 4px solid currentColor; }
.plan-lock-banner[hidden] { display: none; }
/* Support mode: a platform superuser working inside a client's workspace. */
.support-banner { font-size: 13px; background: var(--badge-warn-bg); color: var(--badge-warn-ink);
  border-bottom: 2px solid currentColor; }

/* Emergency break-in form + list */
.bi-label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 2px; }
.bi-field { width: 100%; border: 1px solid var(--field-border); padding: 4px 8px; font-size: 13px; }
.bi-lines { width: 100%; font-size: 13px; border-collapse: collapse; }
.bi-lines th { text-align: left; font-size: 12px; font-weight: 600; color: var(--ink-2); padding: 0 4px 4px 0; }
.bi-lines td { padding: 0 4px 4px 0; vertical-align: middle; }
.bi-lines .bi-field { padding: 3px 6px; }
.bi-remove { color: var(--muted); font-size: 14px; padding: 2px 6px; }
.bi-remove:hover:not(:disabled) { color: var(--ink); background: var(--hover); }
.bi-remove:disabled { opacity: .3; }
.bi-item { border: 1px solid var(--line); padding: 8px 10px; font-size: 13px; background: var(--surface); }
.bi-item + .bi-item { margin-top: 6px; }
.bi-meta { font-size: 11px; color: var(--ink-3); }
.bi-actions button { color: var(--link); text-decoration: underline; font-size: 12px; }
.bi-impact { display: grid; grid-template-columns: minmax(48px, auto) 1fr auto; gap: 4px 8px; align-items: center; font-size: 12px; }
.bi-bar { height: 10px; background: var(--line-soft); position: relative; }
.bi-bar > span { position: absolute; inset: 0 auto 0 0; background: var(--chart-orange); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ------------------------------------------------------------------ Capacity heatmap */
.hm-scroll { overflow-x: auto; }
.hm-table { width: 100%; min-width: 980px; table-layout: fixed; border-collapse: separate; border-spacing: 2px;
  font-size: 11px; font-variant-numeric: tabular-nums; }
.hm-table th { font-weight: 500; color: var(--ink-3); }
.hm-corner { text-align: left; vertical-align: bottom; font-size: 10px; color: var(--muted-2) !important; padding: 0 6px 2px 0; }
.hm-week { text-align: left; padding: 0 2px 2px; overflow: hidden; text-overflow: ellipsis; border-bottom: 1px solid var(--line-strong); white-space: nowrap; }
.hm-day { line-height: 1.15; padding-bottom: 2px; }
.hm-day.we { color: var(--muted-2); }
.hm-tot-h { vertical-align: bottom; }
.wk-start { border-left: 5px solid var(--surface); }
.hm-wc { text-align: left; padding: 0 8px 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600 !important; color: var(--ink) !important;
  border-left: 3px solid transparent; }
.hm-wc.active { border-left-color: #0f61fd; background: var(--tint-blue); }
.hm-note { font-weight: 400; font-size: 9px; color: var(--muted-2); }
.hm-sh { text-align: left; padding-right: 6px; color: var(--muted-2) !important; font-weight: 400 !important; }
tbody .hm-first > * { border-top: 6px solid var(--surface); }
tbody:first-of-type .hm-first > * { border-top: 0; }
.hm-c { height: 26px; text-align: center; border-radius: 3px; background-clip: padding-box; cursor: pointer; position: relative; color: var(--ink); }
.hm-c:hover, .hm-c:focus-visible { outline: 2px solid var(--ink); outline-offset: 0; }
.hm-tot { font-weight: 600; cursor: default; }
/* sequential blue ramp (steps 100/200/300/450/650) - light = lots of spare capacity */
.u1 { background: var(--hm-u1); color: var(--hm-u1-ink); }
.u2 { background: var(--hm-u2); color: var(--hm-u2-ink); }
.u3 { background: var(--hm-u3); color: var(--hm-u3-ink); }
.u4 { background: var(--hm-u4); color: var(--hm-u4-ink); }
.u5 { background: var(--hm-u5); color: var(--hm-u5-ink); }
.over { background: #d03b3b; color: #fff; font-weight: 600; }
.hm-c.over::after { content: ""; position: absolute; top: 0; right: 0; border-style: solid; border-width: 0 7px 7px 0;
  border-color: transparent #fff transparent transparent; border-top-right-radius: 3px; }
.off { background: repeating-linear-gradient(135deg, var(--hm-off-a) 0 4px, var(--hm-off-b) 4px 5px); color: var(--muted-2); cursor: default; }
.hm-chip { display: inline-flex; align-items: center; gap: 4px; }
.hm-swatch { width: 14px; height: 12px; border-radius: 3px; display: inline-block; }

:root[data-theme="dark"] { --card-ring: var(--line); }

/* Admin: asset list (header and each row's form share one grid) */
.asset-admin-row { display: grid; grid-template-columns: minmax(10rem, 16rem) 7rem minmax(12rem, 1fr) 9rem auto;
  gap: 8px; align-items: center; min-width: 720px; }
.asset-admin-row > input[type="hidden"] { display: none; }

/* ------------------------------------------------------------------ Phones (< 768 px) */
@media (max-width: 767px) {
  /* Gantt: only the first column stays pinned; bars can't be dragged (tap a row for its actions). */
  .g-rest { position: static; z-index: auto; box-shadow: none; }
  .g-pin { border-right-color: var(--line-strong); box-shadow: 2px 0 4px -2px rgba(0, 0, 0, .12); }
  .g-scroll { max-height: calc(100vh - 140px); }
  .g-scroll .g-bar { cursor: pointer !important; touch-action: auto; }
  .g-handle { display: none; }
  /* Dropdown panels anchored to a toolbar button span the screen instead of running off its edge. */
  .menu-panel { position: fixed; left: 1rem; right: 1rem; width: auto; max-height: 75vh; overflow: auto; }
  .info-pop { position: fixed; left: 1rem; right: 1rem; top: 25%; width: auto; }
  .info-pop::before { display: none; }
  /* Gantt metrics: two per row, backlog across the bottom. */
  .g-metrics { display: grid; grid-template-columns: 1fr 1fr; }
  .g-metric { border-right: 0; border-bottom: 1px solid var(--line); }
  .g-metric:first-child { border-right: 1px solid var(--line); }
  .g-metric:last-child { grid-column: span 2; border-bottom: 0; }
}

/* Gantt row details (phones): a sheet sliding up from the bottom, with the row's quick actions. */
.g-sheet { position: fixed; inset: 0; z-index: 70; }
.g-sheet[hidden] { display: none; }
.g-sheet-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .45); }
.g-sheet-panel { position: absolute; left: 0; right: 0; bottom: 0; max-height: 85vh; overflow: auto; padding: 16px 16px 20px;
  background: var(--surface); color: var(--ink); box-shadow: 0 -6px 20px rgba(0, 0, 0, .25); font-size: 14px; }
.g-sheet-dl { display: grid; grid-template-columns: max-content 1fr; gap: 6px 12px; margin: 12px 0; }
.g-sheet-dl dt { color: var(--ink-3); }
.g-sheet-dl dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.g-sheet-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.g-sheet select { border: 1px solid var(--line-strong); padding: 4px 6px; background: var(--surface); }
