/* Hauslab shell. KIOSK WEBVIEW RULES: no backdrop-filter anywhere; no CSS filter
 * on animated nodes; SVG <filter> only on static layers; animate transform/opacity only. */
* { box-sizing: border-box; }
#hauslab { display: grid; grid-template: "top top" auto "rail stage" 1fr / 64px 1fr; height: 100vh;
  background: var(--hl-bg); color: var(--hl-text); font: 14px/1.5 var(--hl-font-body); overflow: hidden; }
.hl-top { grid-area: top; display: flex; align-items: center; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--hl-line); }
.hl-mark { font: 700 17px/1 var(--hl-font-disp); letter-spacing: 1.5px; }
.hl-mark-d { color: var(--hl-lens-light); margin: 0 1px; }
.hl-conn { display: flex; align-items: center; gap: 8px; color: var(--hl-dim); font: 500 12px/1 var(--hl-font-mono); }
.hl-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--hl-faint); }
.hl-dot.ok { background: var(--hl-good); }
.hl-dot.error { background: var(--hl-bad); }
.hl-clock { margin-left: auto; font: 500 13px/1 var(--hl-font-mono); }
.hl-rail { grid-area: rail; display: flex; flex-direction: column; gap: 6px; padding: 14px 8px; border-right: 1px solid var(--hl-line); }
.hl-lens { writing-mode: vertical-rl; padding: 12px 6px; background: none; border: 1px solid transparent; border-radius: 8px;
  color: var(--hl-faint); font: 600 10.5px/1 var(--hl-font-disp); letter-spacing: 2.4px; cursor: pointer; }
.hl-lens.live { color: var(--hl-dim); }
.hl-lens.active { color: var(--hl-text); border-color: var(--hl-line2); background: var(--hl-panel); }
[data-tier="ambient"] .hl-rail, [data-tier="ambient"] .hl-top { opacity: 0.25; transition: opacity 0.6s; }
.hl-stage { grid-area: stage; position: relative; }
.hl-base, .hl-field, .hl-overlay { position: absolute; inset: 0; width: 100%; height: 100%; }
.hl-base svg, .hl-overlay svg { width: 100%; height: 100%; }
.hl-field { pointer-events: none; opacity: calc(0.9 * var(--hl-glow-scale) * var(--hl-lux-scale, 1)); }
.hl-room rect { fill: var(--hl-panel); stroke: var(--hl-line); }
.hl-room.outdoor rect { fill: none; stroke-dasharray: 3 4; }
.hl-room text { fill: var(--hl-faint); font: 600 9.5px var(--hl-font-disp); letter-spacing: 1.6px; text-transform: uppercase; }
.hl-lamp-dot { stroke: none; }
.hl-lamp.off .hl-lamp-ring { stroke: var(--hl-faint); stroke-width: 1; }
.hl-lamp.on .hl-lamp-ring { stroke: var(--hl-lens-light); stroke-width: 1.2; }
.hl-lamp.na { opacity: 0.25; }
.hl-lamp, .hl-roomhit, .hl-presence, .hl-vibration, .hl-vacuum { cursor: pointer; pointer-events: all; }
.hl-life-core { fill: var(--hl-lens-life); }
.hl-life-halo { fill: none; stroke: var(--hl-lens-life); stroke-width: 1; opacity: 0; }
.hl-presence.active .hl-life-halo { opacity: 0.7; animation: hl-breathe calc(3.2s / var(--hl-motion-scale)) ease-in-out infinite; }
.hl-vibration.active .hl-life-halo { opacity: 0.8; animation: hl-ripple 1.4s ease-out infinite; }
.hl-presence.idle .hl-life-core, .hl-vibration.idle .hl-life-core { fill: var(--hl-faint); }
.hl-vacuum.idle .hl-life-core { fill: var(--hl-dim); }
.hl-presence.na, .hl-vibration.na, .hl-vacuum.na { opacity: 0.2; }
@keyframes hl-breathe { 0%, 100% { transform: scale(1); opacity: 0.25; } 50% { transform: scale(1.6); opacity: 0.7; } }
@keyframes hl-ripple { from { transform: scale(0.6); opacity: 0.8; } to { transform: scale(2.2); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hl-life-halo { animation: none !important; } }
.hl-sheet { position: absolute; top: 60px; right: 0; bottom: 0; width: 300px; background: var(--hl-panel);
  border-left: 1px solid var(--hl-line); padding: 18px; }
.hl-sheet h2 { margin: 0 0 12px; font: 600 15px var(--hl-font-disp); text-transform: capitalize; }
.hl-sheet button { background: var(--hl-panel2); color: var(--hl-text); border: 1px solid var(--hl-line2);
  border-radius: 8px; padding: 8px 12px; margin: 4px 4px 4px 0; cursor: pointer; font: 500 12px var(--hl-font-disp); }
.hl-row-slider { display: block; margin: 10px 0; color: var(--hl-dim); font-size: 12px; }
.hl-row-slider input { width: 100%; }
.hl-row-info { color: var(--hl-dim); font: 500 12px var(--hl-font-mono); margin: 8px 0; }
#hauslab[data-mode="away"] .hl-field { opacity: calc(0.5 * var(--hl-glow-scale) * var(--hl-lux-scale, 1)); }

/* AIR lens (ported airflow-lab synoptics; SMIL animateMotion is on-device proven) */
.hl-iso { fill: none; stroke: var(--hl-text); stroke-width: 0.8; opacity: 0.5; }
.hl-iso.half { stroke-dasharray: 2 3; opacity: 0.35; stroke-width: 0.6; }
.hl-iso-t { fill: var(--hl-dim); font: 500 8px var(--hl-font-mono); paint-order: stroke; stroke: var(--hl-bg); stroke-width: 2.5px; }
.hl-air-stream-guide { fill: none; stroke: var(--hl-lens-air); stroke-width: 1; stroke-dasharray: 1 6; }
.hl-air-p { fill: var(--hl-lens-air); }
.hl-air-static { fill: none; stroke: var(--hl-faint); stroke-width: 1; stroke-dasharray: 2 6; opacity: 0.5; }
.hl-air-arrow { fill: var(--hl-lens-air); }
.hl-air-pin { cursor: pointer; pointer-events: all; }
.hl-air-pin.off { opacity: 0.35; }
.hl-air-pin-temp { fill: #0a0c11; font: 700 8.5px var(--hl-font-mono); text-anchor: middle; }
.hl-air-pin-name { fill: var(--hl-dim); font: 500 7.5px var(--hl-font-disp); letter-spacing: 0.8px; text-anchor: middle; }
.hl-air-tag { fill: var(--hl-panel2); stroke: var(--hl-line2); }
.hl-air-tag-t { fill: var(--hl-dim); font: 700 7px var(--hl-font-mono); text-anchor: middle; letter-spacing: 1px; }
.hl-air-v { font: 700 13px var(--hl-font-disp); letter-spacing: 1.2px; fill: var(--hl-text); }
.hl-air-v.good { fill: var(--hl-good); } .hl-air-v.bad { fill: var(--hl-bad); }
.hl-air-v.warn { fill: var(--hl-warn); } .hl-air-v.muted { fill: var(--hl-dim); }
.hl-air-vk { fill: var(--hl-dim); font: 500 8.5px var(--hl-font-mono); }
.hl-air-flow-note { fill: var(--hl-faint); font: 500 8px var(--hl-font-mono); }
.hl-win-bar { stroke: var(--hl-dim); stroke-width: 3; stroke-linecap: round; }
.hl-win-open .hl-win-bar { stroke: var(--hl-good); }
.hl-win-closed .hl-win-bar { stroke: var(--hl-faint); }
.hl-win-unknown .hl-win-bar { stroke-dasharray: 3 4; }
.hl-win-flow { fill: none; stroke: var(--hl-good); stroke-width: 1.5; }

/* MEDIA lens — rings compose volume (inline --hl-ring-dur) with mode damping */
.hl-speaker { cursor: pointer; pointer-events: all; }
.hl-speaker-core { fill: var(--hl-lens-media); }
.hl-speaker-mark { fill: var(--hl-bg); }
.hl-speaker.idle .hl-speaker-core { fill: var(--hl-faint); }
.hl-speaker.na { opacity: 0.2; }
.hl-media-ring { fill: none; stroke: var(--hl-media-accent, var(--hl-lens-media)); stroke-width: 1.2;
  animation: hl-media-ring calc(var(--hl-ring-dur, 3s) / var(--hl-motion-scale)) linear infinite;
  animation-delay: var(--hl-ring-delay, 0s); }
@keyframes hl-media-ring { from { transform: scale(0.4); opacity: 0.75; } to { transform: scale(3.2); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hl-media-ring { animation: none; opacity: 0.3; } }
[data-active-lens="media"] .hl-lens.active { color: var(--hl-media-accent, var(--hl-text)); }
.hl-row-art { width: 100%; border-radius: 8px; margin: 2px 0 10px; display: block; }
.hl-row-buttons button { font-size: 15px; min-width: 54px; }

/* LIFE afterglow — a 30-min CSS-driven fade; negative delay encodes the age */
.hl-afterglow { fill: var(--hl-lens-life); opacity: 0;
  animation: hl-afterglow 1800s linear forwards; animation-delay: var(--hl-ag-delay, 0s); }
@keyframes hl-afterglow { from { opacity: 0.22; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hl-afterglow { animation: none; } }

/* AIR sheet — 24 h temp band (sheet-only SVG row) */
.hl-row-svg { margin: 6px 0 10px; }
.hl-row-svg-l { display: block; font: 500 10.5px var(--hl-font-mono); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--hl-dim); margin-bottom: 4px; }
.hl-band { display: block; width: 100%; height: 44px; }
.hl-band-env { fill: var(--hl-lens-air); opacity: 0.18; }
.hl-band-mean { fill: none; stroke: var(--hl-lens-air); stroke-width: 1.4; }
.hl-band-t { font: 400 8px var(--hl-font-mono); fill: var(--hl-dim); }

/* ── phone layout (companion-app sidebar / small browsers) ─────────────────
   Rail drops to a bottom bar; the engaged sheet becomes a bottom sheet.
   Same nodes, same classes — layout only (no new markup, no JS). */
@media (max-width: 600px) {
  #hauslab { grid-template: "top" auto "stage" 1fr "rail" auto / 1fr; }
  .hl-top { padding: 10px 12px; gap: 10px; }
  .hl-rail { flex-direction: row; justify-content: center; gap: 10px;
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
    border-right: 0; border-top: 1px solid var(--hl-line); }
  .hl-lens { writing-mode: horizontal-tb; padding: 8px 14px; } /* desktop rail rotates labels; a bottom bar must not */
  .hl-sheet { top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 65%;
    overflow-y: auto; border-left: 0; border-top: 1px solid var(--hl-line2);
    border-radius: var(--hl-radius) var(--hl-radius) 0 0;
    padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
}

/* lux damping: the panel's own light sensor dims the scene at night.
   Opacity only (kiosk WebView rule: no filter/backdrop-filter). --hl-lux-scale is a
   multiplier, not an override, so it COMPOSES with mode glow-scale instead of
   replacing it: sleep+dim = 0.9 · 0.45 · 0.8 ≈ 0.32 (darker than sleep alone at
   0.405), away+dark = 0.5 · 0.7 · 0.55 ≈ 0.19. The previous approach set opacity flat
   (dim 0.8 / dark 0.55) and relied on #hauslab ID specificity to win over the
   away-mode rule by source order — that made sleep+dim BRIGHTER than sleep alone
   (0.405 → 0.8), which this multiplier composition supersedes. */
.hl-base, .hl-field, .hl-overlay { transition: opacity 1.2s; }
#hauslab[data-lux="dim"] { --hl-lux-scale: 0.8; }
#hauslab[data-lux="dark"] { --hl-lux-scale: 0.55; }
.hl-base, .hl-overlay { opacity: var(--hl-lux-scale, 1); }
