:root {
  --ink: #f5f5f7;
  --ink-2: rgba(245, 245, 247, 0.62);
  --ink-3: rgba(245, 245, 247, 0.4);

  --content-surface: #fcfcfd;
  --content-surface-2: #f1f2f4;
  --content-ink: #1d1d1f;
  --content-ink-2: #6e6e73;
  --content-border: rgba(0, 0, 0, 0.08);

  --glass: rgba(255, 255, 255, 0.07);
  --glass-strong: rgba(255, 255, 255, 0.13);
  --glass-press: rgba(255, 255, 255, 0.18);
  --glass-border: rgba(255, 255, 255, 0.14);
  --glass-highlight: rgba(255, 255, 255, 0.16);

  /* Monochrome "chrome" accent — used on dark glass (buttons, tabs, the
     wordmark). Both stops are light, so gradient text can never fade to
     illegible the way a light->dark stop did before. Text sitting ON this
     gradient needs --accent-ink (dark), not white. */
  --accent: #d4d4d9;
  --accent-2: #ffffff;
  --accent-grad: linear-gradient(135deg, var(--accent), var(--accent-2));
  --accent-ink: #1d1d1f;
  /* Separate, darker accent for anything drawn ON the canvas itself (hotspot
     pins, draw-tool vertices, the pending-zone outline) — the canvas is a
     light surface, so the light chrome accent above would be invisible there. */
  --canvas-accent: #3a3a3c;
  --ok: #32d74b;
  --warn: #ff9f0a;
  --breach: #ff453a;

  --radius-xl: 26px;
  --radius-lg: 20px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --shadow-float: 0 10px 40px rgba(0, 0, 0, 0.5), 0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-glass-inset: inset 0 1px 0 rgba(255, 255, 255, 0.14), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
  --shadow-canvas: 0 30px 80px rgba(0, 0, 0, 0.55), 0 4px 16px rgba(0, 0, 0, 0.3);
  --glow-accent: 0 0 0 1px rgba(255, 255, 255, 0.4), 0 0 22px rgba(255, 255, 255, 0.28);
}

* { box-sizing: border-box; }
html, body {
  height: 100%;
  margin: 0;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  letter-spacing: -0.01em;
}
body {
  background:
    radial-gradient(1000px 700px at 8% -10%, rgba(255, 255, 255, 0.14), transparent 60%),
    radial-gradient(900px 650px at 100% 0%, rgba(100, 116, 139, 0.20), transparent 55%),
    radial-gradient(1100px 800px at 90% 100%, rgba(48, 209, 88, 0.16), transparent 55%),
    radial-gradient(900px 700px at 0% 100%, rgba(255, 69, 58, 0.14), transparent 55%),
    linear-gradient(180deg, #0a0a10, #08080c 60%, #060608);
  background-attachment: fixed;
  animation: drift 40s ease-in-out infinite alternate;
}
@keyframes drift {
  0% { background-position: 0 0, 0 0, 0 0, 0 0, 0 0; }
  100% { background-position: 2% 3%, -3% -2%, -2% 2%, 3% -3%, 0 0; }
}
button { font: inherit; letter-spacing: inherit; }

#app { height: 100%; display: flex; flex-direction: column; }

/* ---------------------------------- topbar --------------------------------- */
.topbar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 14px 0;
  padding: 0 14px;
  height: 56px;
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: saturate(200%) blur(28px);
  -webkit-backdrop-filter: saturate(200%) blur(28px);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-float), var(--shadow-glass-inset);
  position: relative;
  z-index: 20;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-right: 10px;
  white-space: nowrap;
  color: var(--ink);
}
.brand .dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent-grad);
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.7), 0 0 2px rgba(255, 255, 255, 0.9);
  display: inline-block;
  flex: none;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-title {
  font-size: 16px; font-weight: 800; letter-spacing: 0.04em;
  background: var(--accent-grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.brand-sub {
  font-size: 9.5px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-3); margin-top: 2px;
}

.tabs { display: flex; align-items: center; gap: 4px; overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab {
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-2);
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s var(--ease), color 0.18s var(--ease), border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.tab:hover { background: var(--glass); color: var(--ink); }
.tab.active {
  background: var(--accent-grad);
  color: var(--accent-ink);
  box-shadow: var(--glow-accent);
}
.tab-add {
  border: 1px solid var(--glass-border);
  background: var(--glass);
  color: var(--ink-2);
  width: 30px; height: 30px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  flex: none;
  transition: border-color .18s var(--ease), color .18s var(--ease), background .18s var(--ease), transform .12s var(--ease);
}
.tab-add:hover { border-color: var(--accent); color: #fff; background: var(--glass-strong); }
.tab-add:active { transform: scale(0.92); }

.spacer { flex: 1; }

.mode-toggle {
  display: flex; background: rgba(0, 0, 0, 0.28); border-radius: 999px; padding: 3px; flex: none;
  border: 1px solid var(--glass-border);
}
.mode-toggle button {
  border: none; background: transparent; padding: 6px 13px; border-radius: 999px;
  font-size: 12.5px; font-weight: 650; color: var(--ink-3); cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease), box-shadow .18s var(--ease);
}
.mode-toggle button.active { background: var(--glass-strong); color: var(--ink); box-shadow: var(--shadow-glass-inset); }
.mode-toggle button[data-mode="live"].active { background: linear-gradient(135deg, #ff9f0a, #ff453a); color: #fff; }

.icon-btn {
  position: relative;
  border: 1px solid transparent; background: transparent; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 16px; cursor: pointer;
  color: var(--ink); flex: none; transition: background .18s var(--ease), border-color .18s var(--ease), transform .12s var(--ease);
}
.icon-btn:hover { background: var(--glass); border-color: var(--glass-border); }
.icon-btn:active { transform: scale(0.92); }
.badge {
  position: absolute; top: 1px; right: 1px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: var(--breach); color: #fff; font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1;
  box-shadow: 0 0 0 2px rgba(8, 8, 12, 0.9), 0 0 10px rgba(255, 69, 58, 0.85);
  animation: badge-pulse 1.8s ease-in-out infinite;
}
.badge[data-zero="true"] { display: none; animation: none; }
@keyframes badge-pulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(8, 8, 12, 0.9), 0 0 6px rgba(255, 69, 58, 0.6); }
  50% { box-shadow: 0 0 0 2px rgba(8, 8, 12, 0.9), 0 0 14px rgba(255, 69, 58, 1); }
}

/* ------------------------------------ stage --------------------------------- */
.stage { flex: 1; display: flex; flex-direction: column; min-height: 0; position: relative; }

.toolbar {
  flex: none; display: flex; align-items: center; gap: 10px; padding: 16px 18px 12px;
}
.tool {
  border: 1px solid var(--glass-border); background: var(--glass); color: var(--ink);
  padding: 9px 16px; border-radius: 999px; font-size: 13px; font-weight: 600; cursor: pointer;
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  box-shadow: var(--shadow-glass-inset);
  transition: transform .12s var(--ease), border-color .18s var(--ease), background .18s var(--ease), box-shadow .18s var(--ease);
}
.tool:hover { border-color: rgba(255, 255, 255, 0.4); background: var(--glass-strong); }
.tool:active { transform: scale(0.96); }
.tool.active { background: var(--accent-grad); color: var(--accent-ink); border-color: transparent; box-shadow: var(--glow-accent); }

.legend { margin-left: auto; display: flex; align-items: center; gap: 16px; font-size: 12px; color: var(--ink-2); }
.legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 6px; vertical-align: -1px; }
.dot.ok { background: var(--ok); box-shadow: 0 0 8px rgba(50, 215, 75, 0.85); }
.dot.warn { background: var(--warn); box-shadow: 0 0 8px rgba(255, 159, 10, 0.85); }
.dot.breach { background: var(--breach); box-shadow: 0 0 8px rgba(255, 69, 58, 0.9); }

.canvas-wrap {
  flex: 1; min-height: 0; margin: 4px 16px 16px; border-radius: var(--radius-xl);
  padding: 1px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.16) 45%, rgba(255, 255, 255, 0.06) 70%);
  box-shadow: var(--shadow-canvas);
  position: relative;
  overflow: hidden;
}
.canvas-wrap::after {
  content: "";
  position: absolute; inset: 1px; border-radius: calc(var(--radius-xl) - 1px);
  /* A flat white canvas read as a jarring hole in the dark chrome around it —
     this layers a dot grid (a drawing surface, not a blank page) over soft
     corner tints echoing the body's own gradient. First pass at this used
     opacities under 0.07, which turned out perceptually indistinguishable
     from flat white next to actual content (confirmed by swapping in an
     opaque debug color and seeing it render fine — the mechanism was never
     the problem, the values were just too faint to read as "not white"). */
  background:
    radial-gradient(circle at 1px 1px, rgba(0, 0, 0, 0.14) 1.4px, transparent 0) 0 0 / 26px 26px,
    radial-gradient(900px 600px at 12% -8%, rgba(100, 116, 139, 0.16), transparent 60%),
    radial-gradient(800px 550px at 100% 108%, rgba(190, 130, 80, 0.14), transparent 55%),
    linear-gradient(165deg, var(--content-surface), var(--content-surface-2));
  z-index: 0;
}
#floorSvg { width: 100%; height: 100%; display: block; cursor: crosshair; touch-action: none; position: relative; z-index: 1; }
#floorSvg.select-mode { cursor: default; }

.floor-bg-image { pointer-events: none; }

/* zone polygons */
.zone-poly {
  stroke-width: 2;
  transition: fill .5s var(--ease), stroke .3s var(--ease), filter .3s var(--ease);
  cursor: pointer;
}
.zone-poly.state-ok { fill: url(#gradOk); stroke: #22a83f; }
.zone-poly.state-warn {
  fill: url(#gradWarn); stroke: #d98207;
  filter: drop-shadow(0 0 7px rgba(255, 159, 10, 0.4));
}
.zone-poly.state-breach {
  fill: url(#gradBreach); stroke: #e0352c;
  animation: breach-glow 1.8s ease-in-out infinite;
}
@keyframes breach-glow {
  0%, 100% { filter: drop-shadow(0 0 5px rgba(255, 69, 58, 0.55)); }
  50% { filter: drop-shadow(0 0 16px rgba(255, 69, 58, 0.95)); }
}
.zone-poly.pending { fill: rgba(58, 58, 60, 0.12); stroke: var(--canvas-accent); stroke-dasharray: 6 4; }
.zone-poly.selected { stroke-width: 3.5; }
.zone-poly.pulse { animation: pulse 0.6s var(--ease); }
@keyframes pulse { 0% { filter: brightness(1); } 40% { filter: brightness(1.4); } 100% { filter: brightness(1); } }

.zone-label { pointer-events: none; }
.zone-label .name { font-size: 15px; font-weight: 750; fill: var(--content-ink); paint-order: stroke; stroke: rgba(255,255,255,.7); stroke-width: 3px; }
.zone-label .value { font-size: 12.5px; font-weight: 650; fill: var(--content-ink-2); paint-order: stroke; stroke: rgba(255,255,255,.7); stroke-width: 3px; }

.draw-vertex { fill: var(--canvas-accent); stroke: #fff; stroke-width: 2; filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.4)); }
.draw-line { stroke: var(--canvas-accent); stroke-width: 2; stroke-dasharray: 5 4; fill: none; }

.shape-vertex {
  fill: var(--canvas-accent); stroke: #fff; stroke-width: 2; cursor: grab;
  filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.4));
}
.shape-vertex:active { cursor: grabbing; }
.shape-midpoint {
  fill: rgba(255, 255, 255, 0.85); stroke: var(--canvas-accent); stroke-width: 1.5; cursor: copy; opacity: 0.7;
  transition: opacity .15s var(--ease), r .15s var(--ease);
}
.shape-midpoint:hover { opacity: 1; r: 7; }
#floorSvg.editing-shape { cursor: default; }

/* ------------------------------------ panel --------------------------------- */
.panel {
  position: absolute; top: 12px; right: 12px; bottom: 12px; width: 340px;
  background: rgba(20, 20, 26, 0.6);
  backdrop-filter: saturate(200%) blur(32px); -webkit-backdrop-filter: saturate(200%) blur(32px);
  border: 1px solid var(--glass-border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-float), var(--shadow-glass-inset);
  padding: 22px; overflow-y: auto; z-index: 15;
  transform: translateX(calc(100% + 24px)); transition: transform .32s var(--ease);
  color: var(--ink);
}
.panel.open { transform: translateX(0); }
.panel h2 { font-size: 17px; margin: 0 0 16px; color: var(--ink); }

/* Same surface as .panel, mirrored to slide in from the left instead. */
.panel-left {
  position: absolute; top: 12px; left: 12px; bottom: 12px; width: 320px;
  background: rgba(20, 20, 26, 0.6);
  backdrop-filter: saturate(200%) blur(32px); -webkit-backdrop-filter: saturate(200%) blur(32px);
  border: 1px solid var(--glass-border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-float), var(--shadow-glass-inset);
  padding: 22px; overflow-y: auto; z-index: 15;
  transform: translateX(calc(-100% - 24px)); transition: transform .32s var(--ease);
  color: var(--ink); display: flex; flex-direction: column;
}
.panel-left.open { transform: translateX(0); }
.panel-left h2 { font-size: 17px; margin: 0 0 4px; color: var(--ink); }
.plan-browser-search {
  width: 100%; padding: 10px 11px; border-radius: var(--radius-sm); border: 1px solid var(--glass-border);
  background: rgba(255, 255, 255, 0.06); color: var(--ink); font-size: 13.5px; margin: 14px 0 10px; flex: none;
}
.plan-browser-tree { overflow-y: auto; flex: 1; margin: 0 -6px; padding: 0 6px; }
.plan-browser-site { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-3); margin: 16px 0 6px; }
.plan-browser-site:first-child { margin-top: 0; }
.plan-browser-row {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--radius-sm);
  cursor: pointer; font-size: 13.5px; color: var(--ink-2); transition: background .15s var(--ease), color .15s var(--ease);
}
.plan-browser-row:hover { background: var(--glass); color: var(--ink); }
.plan-browser-row.active { background: var(--glass-strong); color: var(--ink); font-weight: 600; }
.plan-browser-row .meta { margin-left: auto; font-size: 11px; color: var(--ink-3); font-weight: 400; }
.plan-browser-empty { color: var(--ink-3); font-size: 13px; text-align: center; padding: 30px 10px; }

/* ------------------------------------ pull-tabs ------------------------------ */
/* Small labeled handles on the canvas edges — replaces topbar icons for the
   two panels that actually live on a side of the screen (Plan Browser,
   Alerts). Same glass surface as the panels they open, and shift outward by
   the panel's own width + margin when open, so the tab tracks the panel's
   edge instead of staying pinned to the screen edge underneath it. */
.pull-tab {
  position: absolute; top: 100px; z-index: 16;
  background: rgba(20, 20, 26, 0.6);
  backdrop-filter: saturate(200%) blur(32px); -webkit-backdrop-filter: saturate(200%) blur(32px);
  border: 1px solid var(--glass-border);
  color: var(--ink-2); font: inherit; font-size: 12.5px; font-weight: 600; letter-spacing: -0.01em;
  padding: 10px 14px; cursor: pointer;
  display: flex; align-items: center; gap: 6px;
  box-shadow: var(--shadow-float);
  transition: left .32s var(--ease), right .32s var(--ease), background .15s var(--ease), color .15s var(--ease);
}
.pull-tab:hover { background: var(--glass-strong); color: var(--ink); }
.pull-tab-chevron { display: inline-block; font-size: 13px; transition: transform .32s var(--ease); }
.pull-tab.open .pull-tab-chevron { transform: rotate(180deg); }
.pull-tab-icon { display: inline-block; font-size: 16px; line-height: 1; }

.pull-tab-left { left: 0; border-left: none; border-radius: 0 var(--radius-lg) var(--radius-lg) 0; }
.pull-tab-left.open { left: 332px; }

.pull-tab-right { right: 0; border-right: none; border-radius: var(--radius-lg) 0 0 var(--radius-lg); }
.pull-tab-right.open { right: 352px; }
.pull-tab-right .badge { position: static; box-shadow: none; }

.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; }
.field input[type="text"], .field input[type="number"], .field input[type="email"],
.field input[type="password"], .field select {
  width: 100%; padding: 10px 11px; border-radius: var(--radius-sm); border: 1px solid var(--glass-border);
  background: rgba(255, 255, 255, 0.06); color: var(--ink); font-size: 14px;
  transition: border-color .15s var(--ease), background .15s var(--ease), box-shadow .15s var(--ease);
}
.field input::placeholder { color: var(--ink-3); }
.field input[type="text"]:focus, .field input[type="number"]:focus, .field input[type="email"]:focus,
.field input[type="password"]:focus, .field select:focus {
  outline: none; border-color: var(--accent); background: rgba(255, 255, 255, 0.09);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.16);
}
.field select option { background: #18181d; color: var(--ink); }
.field-row { display: flex; gap: 10px; }
.field-row .field { flex: 1; }
.switch-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.switch-row label { font-size: 13px; font-weight: 600; color: var(--ink); }
.switch { position: relative; width: 42px; height: 25px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .track {
  position: absolute; inset: 0; background: rgba(255, 255, 255, 0.16); border-radius: 999px; cursor: pointer;
  transition: background .2s var(--ease);
}
.switch .track::after {
  content: ""; position: absolute; width: 21px; height: 21px; border-radius: 50%; background: #fff;
  top: 2px; left: 2px; box-shadow: 0 1px 3px rgba(0,0,0,.4); transition: transform .2s var(--ease);
}
.switch input:checked + .track { background: var(--ok); box-shadow: 0 0 10px rgba(50, 215, 75, 0.6); }
.switch input:checked + .track::after { transform: translateX(17px); }

.hint { font-size: 11.5px; color: var(--ink-3); margin-top: -8px; margin-bottom: 14px; line-height: 1.45; }
.divider { height: 1px; background: var(--glass-border); margin: 18px 0; }

.btn-row { display: flex; gap: 10px; margin-top: 18px; }
.refresh-btn { width: 100%; margin: 8px 0 14px; }
.btn {
  flex: 1; padding: 11px 12px; border-radius: 999px; border: 1px solid transparent; font-size: 13.5px; font-weight: 650;
  cursor: pointer; transition: transform .12s var(--ease), opacity .15s var(--ease), box-shadow .15s var(--ease);
}
.btn:active { transform: scale(0.96); }
.btn-primary { background: var(--accent-grad); color: var(--accent-ink); box-shadow: var(--glow-accent); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { background: var(--glass); color: var(--ink); border-color: var(--glass-border); }
.btn-ghost:hover { background: var(--glass-strong); }
.btn-danger { background: rgba(255, 69, 58, 0.15); color: #ff6961; border-color: rgba(255, 69, 58, 0.3); }
.btn-danger:hover { background: rgba(255, 69, 58, 0.25); }

/* ------------------------------------ drawer --------------------------------- */
.drawer {
  position: absolute; top: 12px; right: 12px; bottom: 12px; width: 340px;
  background: rgba(20, 20, 26, 0.6);
  backdrop-filter: saturate(200%) blur(32px); -webkit-backdrop-filter: saturate(200%) blur(32px);
  border: 1px solid var(--glass-border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-float), var(--shadow-glass-inset);
  padding: 22px; overflow-y: auto; z-index: 14;
  transform: translateX(calc(100% + 24px)); transition: transform .32s var(--ease);
  color: var(--ink);
}
.drawer.open { transform: translateX(0); }
.drawer h2 { font-size: 17px; margin: 0 0 4px; color: var(--ink); }
.drawer .sub { font-size: 12px; color: var(--ink-2); margin-bottom: 16px; }
.alert-item {
  background: rgba(255, 255, 255, 0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-sm);
  padding: 13px; margin-bottom: 10px;
}
.alert-item.clickable { cursor: pointer; transition: background .2s var(--ease); }
.alert-item.clickable:hover { background: rgba(255, 255, 255, 0.09); }
.alert-item .row1 { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.alert-item .zone { font-weight: 700; font-size: 13.5px; color: var(--ink); }
.alert-item .time { font-size: 11px; color: var(--ink-3); }
.alert-floorplan { font-size: 11px; color: var(--ink-3); margin-bottom: 6px; }
.alert-item .msg { font-size: 12.5px; color: var(--ink-2); margin-bottom: 8px; }
.pill { display: inline-block; font-size: 10.5px; font-weight: 700; padding: 3px 9px; border-radius: 999px; }
.pill.sent { background: rgba(50, 215, 75, 0.18); color: #4ee06a; box-shadow: 0 0 8px rgba(50,215,75,.25); }
.pill.sim { background: rgba(255, 255, 255, 0.14); color: #e8e8ed; }
.pill.failed { background: rgba(255, 69, 58, 0.18); color: #ff6961; }
.empty { color: var(--ink-3); font-size: 13px; text-align: center; padding: 40px 10px; }

/* ------------------------------------ modal --------------------------------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  z-index: 30;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity .2s var(--ease);
}
.modal-backdrop.open { opacity: 1; pointer-events: auto; }
.modal {
  width: 440px; max-width: calc(100vw - 40px); max-height: calc(100vh - 60px); overflow-y: auto;
  background: rgba(24, 24, 30, 0.72);
  backdrop-filter: saturate(200%) blur(36px); -webkit-backdrop-filter: saturate(200%) blur(36px);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-xl); box-shadow: var(--shadow-float), var(--shadow-glass-inset);
  padding: 26px; transform: scale(0.95) translateY(6px); transition: transform .22s var(--ease);
  color: var(--ink);
}
.modal-backdrop.open .modal { transform: scale(1) translateY(0); }
.modal h2 { margin: 0 0 4px; font-size: 19px; color: var(--ink); }
.modal .sub { color: var(--ink-2); font-size: 13px; margin-bottom: 20px; }
.status-line { font-size: 12.5px; padding: 10px 12px; border-radius: var(--radius-sm); margin: 10px 0; }
.status-line.ok { background: rgba(50, 215, 75, 0.15); color: #4ee06a; }
.status-line.error { background: rgba(255, 69, 58, 0.15); color: #ff6961; }

.sync-status {
  display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600;
  padding: 8px 12px; border-radius: var(--radius-sm); margin-bottom: 14px; width: fit-content;
}
.sync-status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none; }
.sync-status.sync-idle, .sync-status.sync-saved { background: rgba(50, 215, 75, 0.12); color: #4ee06a; }
.sync-status.sync-idle::before, .sync-status.sync-saved::before { background: #32d74b; }
.sync-status.sync-pending, .sync-status.sync-saving { background: rgba(255, 255, 255, 0.1); color: var(--ink-2); }
.sync-status.sync-pending::before, .sync-status.sync-saving::before { background: var(--ink-3); animation: sync-pulse 1s ease-in-out infinite; }
.sync-status.sync-error { background: rgba(255, 69, 58, 0.15); color: #ff6961; }
.sync-status.sync-error::before { background: var(--breach); }
@keyframes sync-pulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }

.connection-status {
  display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600;
  margin: 6px 0 12px;
}
.connection-status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none; }
.connection-status.conn-checking { color: var(--ink-3); }
.connection-status.conn-checking::before { background: var(--ink-3); animation: sync-pulse 1s ease-in-out infinite; }
.connection-status.conn-ok { color: #4ee06a; }
.connection-status.conn-ok::before { background: #32d74b; }
.connection-status.conn-error { color: #ff6961; }
.connection-status.conn-error::before { background: var(--breach); }

.toast-stack {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); z-index: 40;
  display: flex; flex-direction: column; gap: 8px; align-items: center;
  transition: left .28s var(--ease);
}
/* A right-side panel/drawer (zone, hotspot, alerts) sits in the rightmost
   ~364px — re-center toasts over the remaining canvas so they don't land
   on top of that panel's own controls. Mirrored for the left-side plan
   browser; if both are open the remaining middle strip is already roughly
   centered, so neither shift applies. */
.toast-stack.panel-open-right { left: calc(50% - 182px); }
.toast-stack.panel-open-left { left: calc(50% + 172px); }
.toast {
  background: rgba(24, 24, 30, 0.82); color: var(--ink); padding: 11px 20px; border-radius: 999px;
  font-size: 13px; font-weight: 550;
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  box-shadow: var(--shadow-float);
  animation: toast-in .3s var(--ease);
}
@keyframes toast-in { from { opacity: 0; transform: translateY(10px) scale(.96); } to { opacity: 1; transform: translateY(0) scale(1); } }

.draw-hint {
  position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  background: rgba(24, 24, 30, 0.75); color: var(--ink); padding: 9px 12px 9px 18px; border-radius: 999px;
  font-size: 12.5px; z-index: 12; pointer-events: none; white-space: nowrap;
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  box-shadow: var(--shadow-float);
}
.draw-hint[hidden] { display: none; }
.draw-hint-actions { display: flex; gap: 6px; pointer-events: auto; }
.draw-hint-actions .btn { padding: 5px 12px; font-size: 12px; }

/* ------------------------------------ site switcher / breadcrumb --------------- */
.site-select {
  border: 1px solid var(--glass-border); background: var(--glass); color: var(--ink);
  padding: 7px 10px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  max-width: 160px; margin-right: 6px; flex: none;
}
.site-select option { background: #18181d; color: var(--ink); }

.breadcrumb {
  flex: none; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 22px 0; font-size: 12.5px; color: var(--ink-2);
}
.breadcrumb[hidden] { display: none; }
.crumb {
  border: none; background: transparent; color: var(--ink-2); font: inherit; font-weight: 600;
  cursor: pointer; padding: 4px 8px; border-radius: 999px; transition: background .15s var(--ease), color .15s var(--ease);
}
.crumb:hover { background: var(--glass); color: var(--ink); }
.crumb.current { color: var(--ink); cursor: default; }
.crumb.current:hover { background: transparent; }
.crumb-sep { color: var(--ink-3); }

/* ------------------------------------ zoom controls ----------------------------- */
.zoom-controls { display: flex; gap: 4px; }
.tool.icon-only { width: 38px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 17px; font-weight: 700; }

#floorSvg { cursor: grab; }
#floorSvg.drawing { cursor: crosshair; }
#floorSvg.panning { cursor: grabbing; }

/* ------------------------------------ hotspots ---------------------------------- */
/* --hotspot-accent is its own color, distinct from both --canvas-accent (the
   neutral grey used for transient draw-tool feedback elsewhere on the
   canvas) and the ok/warn/breach capacity-state colors, so a hotspot never
   reads as "this has a status" — it's a link, not a measurement. */
.hotspot { cursor: pointer; --hotspot-accent: #0a84ff; }
.hotspot-ring {
  fill: rgba(10, 132, 255, 0.16); stroke: var(--hotspot-accent); stroke-width: 2;
  transition: r .15s var(--ease), fill .15s var(--ease);
}
.hotspot:hover .hotspot-ring { r: 19; fill: rgba(10, 132, 255, 0.26); }
.hotspot-dot { fill: var(--hotspot-accent); filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.45)); }
.hotspot-dot-core { fill: #fff; }
.hotspot-label-pill { fill: rgba(12, 24, 44, 0.86); filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.35)); }
.hotspot-label { font-size: 12px; font-weight: 700; fill: #fff; }

/* ------------------------------------ manage modal ------------------------------- */
.modal-wide { width: 640px; }
.manage-site {
  background: rgba(255, 255, 255, 0.04); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md); padding: 14px; margin-bottom: 14px;
}
.manage-site-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.manage-name {
  border: 1px solid transparent; background: transparent; color: var(--ink); font-size: 14px; font-weight: 650;
  padding: 6px 8px; border-radius: var(--radius-sm); flex: 1; min-width: 0;
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.manage-name:hover { background: rgba(255, 255, 255, 0.05); }
.manage-name:focus { outline: none; border-color: var(--accent); background: rgba(255, 255, 255, 0.08); }
.manage-name-site { font-size: 15px; font-weight: 750; }
.manage-tree-list { display: flex; flex-direction: column; gap: 4px; }
.manage-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: var(--radius-sm);
  transition: background .15s var(--ease);
}
.manage-row:hover { background: rgba(255, 255, 255, 0.04); }
.manage-meta { font-size: 11px; color: var(--ink-3); white-space: nowrap; flex: none; }

.report-row {
  display: flex; align-items: center; gap: 18px; padding: 12px 6px;
  border-bottom: 1px solid var(--glass-border);
}
.report-row:last-child { border-bottom: none; }
.report-row-name { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.report-row-name strong { font-size: 14px; color: var(--ink); }
.report-stat { font-size: 12.5px; color: var(--ink-2); white-space: nowrap; flex: none; }
.report-stat strong { color: var(--ink); }
.manage-parent-select {
  border: 1px solid var(--glass-border); background: rgba(255, 255, 255, 0.06); color: var(--ink-2);
  font-size: 11.5px; padding: 5px 7px; border-radius: var(--radius-sm); flex: none; max-width: 130px;
}
.manage-parent-select option { background: #18181d; color: var(--ink); }
.manage-empty { color: var(--ink-3); font-size: 12.5px; padding: 8px 4px; }
.btn-sm { flex: none; padding: 6px 12px; font-size: 12px; }

/* ------------------------------------ dashboard list ----------------------------- */
.dashboard-row {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; margin-bottom: 6px;
  background: rgba(255, 255, 255, 0.05); border: 1px solid var(--glass-border); border-radius: var(--radius-sm);
}
#dashboardList .dashboard-row-name {
  font-weight: 650; font-size: 13px; color: var(--ink); flex: none; width: 120px;
  border: 1px solid transparent; background: transparent; padding: 4px 6px; border-radius: var(--radius-sm);
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.dashboard-row-name:hover { background: rgba(255, 255, 255, 0.05); }
.dashboard-row-name:focus { outline: none; border-color: var(--accent); background: rgba(255, 255, 255, 0.08); }
.dashboard-row-id { font-size: 11.5px; color: var(--ink-3); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ------------------------------------ big screen mode ---------------------------- */
.bigscreen-clock {
  font-variant-numeric: tabular-nums; font-weight: 650; font-size: 13px; color: var(--ink-2);
  margin-right: 6px; white-space: nowrap;
}
body.bigscreen .tab-add,
body.bigscreen #drawZoneBtn,
body.bigscreen #hotspotBtn,
body.bigscreen #uploadFloorplanBtn,
body.bigscreen #manageBtn,
body.bigscreen #settingsBtn,
body.bigscreen #reportBtn,
body.bigscreen #alertsTab,
body.bigscreen #planBrowserTab,
body.bigscreen #modeToggle,
body.bigscreen .site-select { display: none; }
body.bigscreen .toolbar { padding-right: 410px; }
body.bigscreen .canvas-wrap { margin-right: 410px; }
body.bigscreen .drawer { transform: none !important; }

/* ------------------------------------ empty floorplan state ---------------------- */
.empty-floorplan {
  position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; text-align: center; padding: 40px;
  color: var(--content-ink-2);
}
.empty-floorplan[hidden] { display: none; }
.empty-floorplan-icon { font-size: 44px; }
.empty-floorplan h3 { margin: 0; color: var(--content-ink); font-size: 19px; }
.empty-floorplan p { margin: 0; max-width: 320px; font-size: 13.5px; line-height: 1.5; }
.empty-floorplan .btn { flex: none; padding: 10px 20px; }

/* ------------------------------------ read-only (signed-out) mode ---------------- */
body.read-only #settingsBtn,
body.read-only #modeToggle,
body.read-only .tab-add,
body.read-only #drawZoneBtn,
body.read-only #hotspotBtn,
body.read-only #uploadFloorplanBtn,
body.read-only #manageBtn,
body.read-only #reportBtn { display: none; }
.field select:disabled, .field input:disabled, .btn:disabled {
  opacity: 0.45; cursor: not-allowed;
}

/* ------------------------------------ viewer mode (phone/tablet) ----------------- */
/* Phones and tablets get an end-user viewing experience, not the full editing
   toolset — same CSS-only hide-list convention as read-only/bigscreen above. */
body.viewer-mode .tab-add,
body.viewer-mode #drawZoneBtn,
body.viewer-mode #hotspotBtn,
body.viewer-mode #uploadFloorplanBtn,
body.viewer-mode #manageBtn,
body.viewer-mode #settingsBtn,
body.viewer-mode #bigScreenBtn,
body.viewer-mode #reportBtn { display: none; }
body.viewer-mode #editShapeBtn,
body.viewer-mode #deleteZoneBtn { display: none !important; }

/* Phone/tablet layout — panels go full-width instead of a docked sidebar, and
   the pull-tabs' open offsets are recalculated to match. Independent of
   viewer-mode: this is pure layout, and applies even to the (rare) signed-in
   admin who happens to be on a small screen. */
@media (max-width: 1024px) {
  /* Full-width panels leave no room for a tab tracking their far edge like
     desktop does — so on mobile the tab just stays put at the screen edge,
     sitting on top of the open panel (it's above it in z-index), and stays
     the way to close it again. */
  .panel, .panel-left, .drawer { width: calc(100vw - 24px); }
  .pull-tab-left.open { left: 0; }
  .pull-tab-right.open { right: 0; }

  .topbar { margin: 8px 8px 0; padding: 0 10px; gap: 6px; }
  .brand-sub { display: none; }
  .breadcrumb { padding: 8px 14px 0; }
  .toolbar { flex-wrap: wrap; padding: 12px 14px 8px; row-gap: 8px; }
  .legend { margin-left: 0; flex-basis: 100%; gap: 12px; }
}

/* Larger touch targets on hotspot markers for any coarse (touch) pointer,
   independent of screen size — a touch laptop at desktop width benefits too. */
@media (pointer: coarse) {
  .hotspot-ring { r: 20; }
  .hotspot:hover .hotspot-ring { r: 23; }
  .hotspot-dot { r: 9; }
  .hotspot-dot-core { r: 3.5; }
}
