/* ==========================================================================
   halcyon.css - the "Halcyon" control surface for AvControl (route /halcyon)
   --------------------------------------------------------------------------
   Implements the authoritative visual spec (halcyon-spec.md, itself derived
   from "Halcyon Control.dc.html" v2). Every value here comes from that spec.

   SCOPE RULE: every selector is scoped under .hal-root so nothing can leak
   into the MudBlazor dashboard at "/". The only exceptions are the two
   body.halcyon rules in section 17, gated behind a class that halcyon.js
   adds on mount and removes on dispose.

   FONTS: 'Instrument Sans' (UI) and 'Space Grotesk' (numerals) are ALREADY
   loaded app-wide by Components/App.razor, with exactly the weights this
   design needs (Space Grotesk 400;500;600;700, Instrument Sans 400;500;600).
   Deliberately no @import here - a second request for the same Google Fonts
   URL only costs latency on a vessel with a flaky uplink. Both stacks below
   carry real fallbacks so the panel still reads when the boat is offline.

   MARKUP CONTRACT - the class combinations this stylesheet expects:
     scene button ......... class="hal-chip hal-scene"            (+ is-active)
     media source chip .... class="hal-chip hal-media-src"        (+ is-active)
     amp source chip ...... class="hal-chip hal-amp-src"          (+ is-active)
     media app chip ....... class="hal-chip hal-chip--dot hal-media-app"
                            style="--hal-app-rgb:229,9,20"        (+ is-active)
     amp zone chip ........ class="hal-chip hal-chip--dot hal-amp-zone"
     room tab ............. class="hal-room-tab"      inside .hal-segment
     shade zone pill ...... class="hal-chip--flat hal-shade-zone"
                                                      inside .hal-segment--sm
     fan step ............. class="hal-chip--flat hal-fan-step"
                                                      inside .hal-segment--fan
     climate card ......... class="hal-card hal-card--climate"
                            data-hal-mode="cool|heat|auto"
     light icon ........... <svg class="hal-light-icon"> with NO stroke attr
     dial svg parts ....... .hal-dial-track .hal-dial-value
                            .hal-dial-handle .hal-dial-pin

   Continuous values ride on custom properties, never generated classes:
     --hal-fill --hal-pos --hal-prog --hal-vol-deg --hal-vol-sweep
     --hal-vol-arc --hal-vol-arc-glow --hal-well-glow --hal-art-glow
     --hal-app-rgb
   State classes (shared, never card-prefixed):
     is-active is-on is-off is-playing is-muted is-dragging is-dimmed is-offline
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

.hal-root {
  /* ---- fonts ---- */
  --hal-font-ui:       'Instrument Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --hal-font-num:      'Space Grotesk', 'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* ---- base ---- */
  --hal-bg:            #07080b;
  --hal-bg-top:        #0a0c11;
  --hal-bg-bot:        #06070a;

  /* ---- accent (amber) + derivations ---- */
  --hal-accent:        #e8b45a;
  --hal-accent-rgb:    232, 180, 90;
  --hal-accent-hi:     rgb(255, 225, 113);
  --hal-accent-dim:    rgb(167, 130, 65);
  --hal-accent-lo:     rgb(144, 112, 56);
  --hal-accent-glow:   rgba(232, 180, 90, 0.45);
  --hal-accent-bd:     rgba(232, 180, 90, 0.70);

  /* ---- text ramp (descending prominence) ---- */
  --hal-t0:            #eef0f4;
  --hal-t1:            #c6ccd6;
  --hal-t2:            #9aa1ae;
  --hal-t3:            #8b93a1;
  --hal-t4:            #79808d;
  --hal-t5:            #666d7a;
  --hal-t6:            #565d69;
  --hal-t7:            #4d5460;
  --hal-on-accent:     #ffe9c4;
  --hal-value:         #f2f4f7;
  --hal-glyph-dark:    #141009;

  /* ---- semantic colours ---- */
  --hal-cool:          #7dd8ff;
  --hal-heat:          #ff9d66;
  --hal-warm-hi:       #ffe3a6;
  --hal-warm:          #ffb45e;
  --hal-warm-lo:       #ff9d42;
  --hal-warm-icon:     #ffd08a;
  --hal-alert:         #ff5f57;
  --hal-alert-text:    #ff8d87;

  /* ---- radii ---- */
  --hal-r-card:        26px;
  --hal-r-topbar:      16px;
  --hal-r-scene:       16px;
  --hal-r-tile:        14px;
  --hal-r-feed:        16px;
  --hal-r-chip:        12px;
  --hal-r-chip-sm:     11px;
  --hal-r-fan:         9px;
  --hal-r-dimwell:     24px;
  --hal-r-pill:        999px;

  /* ---- spacing ---- */
  --hal-page-pad:      10px 16px 12px;
  --hal-grid-gap:      12px;
  --hal-card-pad:      16px 20px 14px;

  /* ---- motion ---- */
  --hal-ease:          cubic-bezier(.22, .61, .36, 1);
  --hal-t-chip:        .3s;
  --hal-t-btn:         .2s;
  --hal-t-card:        .45s;
  --hal-t-swap:        .5s;
  --hal-t-slide:       .35s;
  --hal-t-dim:         .6s;
  --hal-t-shade:       .7s;

  /* ---- glass recipe (card shell) ---- */
  --hal-glass-bg:
      radial-gradient(120% 70% at 18% -8%, rgba(255,255,255,0.09), transparent 50%),
      linear-gradient(165deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015) 55%, rgba(255,255,255,0.035));
  --hal-glass-bd:       rgba(255, 255, 255, 0.12);
  --hal-glass-bd-hover: rgba(255, 255, 255, 0.18);
  --hal-glass-blur:     blur(24px) saturate(1.6);
  --hal-glass-sh:
      0 34px 64px -24px rgba(0,0,0,0.8),
      0 12px 24px -16px rgba(0,0,0,0.6),
      inset 0 1.5px 0 rgba(255,255,255,0.14),
      inset 0 -1px 0 rgba(0,0,0,0.35),
      inset 1px 0 0 rgba(255,255,255,0.04);
  --hal-glass-sh-hover:
      0 44px 80px -28px rgba(0,0,0,0.85),
      0 18px 32px -18px rgba(0,0,0,0.65),
      inset 0 1.5px 0 rgba(255,255,255,0.2),
      inset 0 -1px 0 rgba(0,0,0,0.35);

  /* ---- recessed well recipe ---- */
  --hal-well-bg:       rgba(0, 0, 0, 0.30);
  --hal-well-bd:       rgba(255, 255, 255, 0.06);
  --hal-well-sh:       inset 0 2px 6px rgba(0, 0, 0, 0.5);

  /* ---- climate mode channel (overridden per mode in section 12) ---- */
  --hal-mode-col:      var(--hal-accent);
  --hal-mode-rgb:      232, 180, 90;
  --hal-mode-bd:       rgba(232, 180, 90, 0.50);
  --hal-mode-bg:       rgba(232, 180, 90, 0.14);
  --hal-mode-bd-45:    rgba(232, 180, 90, 0.45);
  --hal-mode-bg-13:    rgba(232, 180, 90, 0.13);
  --hal-mode-glow:     rgba(232, 180, 90, 0.45);

  /* ---- media app brand channel (overridden per chip, inline) ---- */
  --hal-app-rgb:       232, 180, 90;
}


/* ==========================================================================
   2. LOCAL RESET  (zero specificity, so every component rule below wins)
   ========================================================================== */

:where(.hal-root) *,
:where(.hal-root) *::before,
:where(.hal-root) *::after { box-sizing: border-box; }

:where(.hal-root) :where(h1, h2, h3, h4, h5, h6, p, figure) {
  margin: 0; font-size: inherit; font-weight: inherit;
}

:where(.hal-root) :where(button, input, select, textarea) {
  font: inherit; color: inherit; margin: 0;
}

:where(.hal-root) :where(button) {
  -webkit-appearance: none; appearance: none;
  padding: 0; border: none; background: none; text-align: inherit;
  -webkit-tap-highlight-color: transparent;
}

:where(.hal-root) :where(a) { color: inherit; text-decoration: none; }
:where(.hal-root) :where(svg) { display: block; flex: none; }

/* Keyboard focus stays visible: the panel is also driven from a desktop
   browser over the tunnel, not only by finger on the wall-mounted iPad. */
:where(.hal-root) :where(button, a, [tabindex]):focus-visible {
  outline: 2px solid var(--hal-accent-bd);
  outline-offset: 2px;
}


/* ==========================================================================
   3. PAGE FRAME - five absolute layers under a z-index:1 content column
   ========================================================================== */

.hal-root {
  position: relative;
  height: 100vh;          /* fallback for browsers without dvh */
  height: 100dvh;
  min-height: 520px;
  overflow: hidden;
  color: var(--hal-t0);
  background: var(--hal-bg);
  font-family: var(--hal-font-ui);
  font-size: 13px;
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  touch-action: manipulation;
}

/* the design shows no scrollbars anywhere */
.hal-root ::-webkit-scrollbar { width: 0; height: 0; }
.hal-root * { scrollbar-width: none; }

/* layer 1 - four-stop background glow (alphas already multiplied by glow 0.7) */
.hal-bg {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(1100px 760px at 10% -12%, rgba(232,180,90,0.084), transparent 62%),
    radial-gradient(900px 560px  at 82% -14%, rgba(80,120,210,0.063), transparent 60%),
    radial-gradient(1000px 720px at 92% 112%, rgba(52,74,130,0.168),  transparent 62%),
    radial-gradient(1400px 340px at 50% 103%, rgba(232,180,90,0.042), transparent 70%),
    linear-gradient(180deg, var(--hal-bg-top), var(--hal-bg-bot) 70%);
}

/* layers 2+3 - drifting light orbs (the "4D" depth pass) */
.hal-orb { position: absolute; border-radius: 50%; pointer-events: none; }
.hal-orb-1 {
  top: -240px; left: -200px; width: 660px; height: 660px;
  background: radial-gradient(circle, rgba(232,180,90,0.112), transparent 62%);
  filter: blur(90px);
  animation: hal-drift1 24s ease-in-out infinite alternate;
}
.hal-orb-2 {
  bottom: -280px; right: -220px; width: 740px; height: 740px;
  background: radial-gradient(circle, rgba(70,100,190,0.14), transparent 62%);
  filter: blur(100px);
  animation: hal-drift2 30s ease-in-out infinite alternate;
}

/* layer 4 - vignette */
.hal-vignette {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 0%, transparent 55%, rgba(0,0,0,0.55));
}

/* layer 5 - film grain, above everything */
.hal-grain {
  position: fixed; inset: 0; z-index: 9999; pointer-events: none; opacity: .5;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/><feColorMatrix type='saturate' values='0'/><feComponentTransfer><feFuncA type='linear' slope='0.05'/></feComponentTransfer></filter><rect width='140' height='140' filter='url(%23n)'/></svg>");
}

/* content column */
.hal-shell {
  position: relative; z-index: 1;
  display: flex; flex-direction: column;
  height: 100%;
  padding: var(--hal-page-pad);
}


/* ==========================================================================
   4. KEYFRAMES
   ========================================================================== */

@keyframes hal-fadeUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes hal-swapA  { from { opacity: .2; transform: scale(.988); }    to { opacity: 1; transform: none; } }
@keyframes hal-swapB  { from { opacity: .2; transform: scale(.988); }    to { opacity: 1; transform: none; } }
@keyframes hal-vu {
  0%   { transform: scaleY(.22); }
  30%  { transform: scaleY(.9); }
  55%  { transform: scaleY(.4); }
  80%  { transform: scaleY(1); }
  100% { transform: scaleY(.22); }
}
@keyframes hal-livePulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes hal-drift1 { from { transform: translate(-6%, -5%) scale(1); }  to { transform: translate(9%, 7%) scale(1.18); } }
@keyframes hal-drift2 { from { transform: translate(5%, 9%) scale(1.12); } to { transform: translate(-9%, -7%) scale(0.94); } }


/* ==========================================================================
   5. GRID - 12 columns, gap 12; each card variant carries its own span
   ========================================================================== */

.hal-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-flow: dense;
  gap: var(--hal-grid-gap);
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.hal-grid--swapA { animation: hal-swapA var(--hal-t-swap) var(--hal-ease) both; }
.hal-grid--swapB { animation: hal-swapB var(--hal-t-swap) var(--hal-ease) both; }

/* landscape spans (1180x820 target) */
.hal-card--media   { grid-column: span 5; }
.hal-card--amp     { grid-column: span 3; }
.hal-card--climate { grid-column: span 4; }
.hal-card--lights  { grid-column: span 4; }
.hal-card--shades  { grid-column: span 3; }
.hal-card--vessel  { grid-column: span 5; }


/* ==========================================================================
   6. TOP BAR
   ========================================================================== */

.hal-topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 6px 12px;
  border-radius: var(--hal-r-topbar);
  background:
    radial-gradient(90% 160% at 12% -30%, rgba(255,255,255,0.1), transparent 55%),
    linear-gradient(165deg, rgba(255,255,255,0.065), rgba(255,255,255,0.015) 60%);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow:
    0 22px 46px -18px rgba(0,0,0,0.7),
    0 8px 18px -12px rgba(0,0,0,0.5),
    inset 0 1.5px 0 rgba(255,255,255,0.14);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  animation: hal-fadeUp .6s var(--hal-ease) both;
}

.hal-brand { display: flex; align-items: center; gap: 11px; flex: none; }
.hal-brand-tile {
  position: relative;
  width: 34px; height: 34px; border-radius: 11px; flex: none;
  background: radial-gradient(120% 120% at 30% 20%, #343a46, #14171d 60%, #0c0e12);
  box-shadow:
    inset 0 1px 1px rgba(255,255,255,0.2),
    inset 0 -4px 8px rgba(0,0,0,0.5),
    0 8px 16px -6px rgba(0,0,0,0.7);
  display: flex; align-items: center; justify-content: center;
}
.hal-brand-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--hal-accent);
  box-shadow: 0 0 12px 2px var(--hal-accent-glow);
}
.hal-brand-text { min-width: 0; }
.hal-brand-name {
  font-family: var(--hal-font-num);
  font-size: 15px; font-weight: 600; letter-spacing: .16em;
  color: var(--hal-t0); white-space: nowrap;
}
.hal-brand-sub {
  font-size: 10.5px; letter-spacing: .22em; color: var(--hal-t4);
  margin-top: 1px; white-space: nowrap;
}

/* room tabs. AvControl has ~13 rooms against the design's 3, so the pill
   scrolls horizontally rather than shrinking the 13.5px / 11-20px metrics. */
.hal-rooms {
  flex: 1; min-width: 0;
  display: flex; justify-content: center;
}
.hal-rooms .hal-segment {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  /* 13 rooms never fit: hide the bar and fade the edge so it reads as
     scrollable instead of looking like a tab was chopped in half. */
  scrollbar-width: none; -ms-overflow-style: none;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
}
.hal-rooms .hal-segment::-webkit-scrollbar { display: none; }
.hal-room-tab {
  white-space: nowrap; flex: none;
  font-family: var(--hal-font-ui);
  font-size: 13.5px; font-weight: 600;
  padding: 11px 20px; border-radius: var(--hal-r-pill);
  cursor: pointer;
  border: 1px solid transparent;
  background: transparent;
  color: var(--hal-t3);
  box-shadow: none;
  transition: all .35s var(--hal-ease);
}
.hal-room-tab:hover  { color: #fff; }
.hal-room-tab:active { transform: scale(0.97); }
.hal-room-tab.is-active {
  border-color: rgba(232,180,90,0.55);
  background: linear-gradient(180deg, rgba(232,180,90,0.2), rgba(232,180,90,0.08));
  color: #fff;
  box-shadow: 0 0 18px -4px rgba(232,180,90,0.5), inset 0 1px 0 rgba(255,255,255,0.15);
}

.hal-topinfo { display: flex; align-items: center; gap: 16px; flex: none; }
.hal-topinfo-date   { font-size: 12.5px; color: var(--hal-t2); text-align: right; white-space: nowrap; }
.hal-topinfo-status {
  font-family: var(--hal-font-num);
  font-size: 11px; letter-spacing: .18em; color: var(--hal-t5);
  margin-top: 1px; white-space: nowrap; text-align: right;
}
.hal-topbar-divider { width: 1px; height: 30px; background: rgba(255,255,255,0.09); flex: none; }
.hal-clock {
  font-family: var(--hal-font-num);
  font-size: 23px; font-weight: 500; letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}


/* ==========================================================================
   7. HEADER ROW + SCENES
   ========================================================================== */

.hal-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; padding: 10px 4px 10px;
}
.hal-header-left { min-width: 0; animation: hal-fadeUp .6s .05s var(--hal-ease) both; }
.hal-title {
  font-family: var(--hal-font-num);
  font-size: 24px; font-weight: 600; letter-spacing: -0.01em; line-height: 1;
  color: var(--hal-t0);
}
.hal-summary {
  font-size: 13px; font-weight: 400; letter-spacing: .02em;
  color: var(--hal-t3); margin-top: 7px;
}

.hal-scenes {
  display: flex; gap: 10px; flex: none;
  animation: hal-fadeUp .6s .1s var(--hal-ease) both;
}
.hal-scene {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 16px 9px 11px;
  border-radius: var(--hal-r-scene);
  cursor: pointer;
  font-family: var(--hal-font-ui);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: all .4s var(--hal-ease);
}
/* .hal-chip is declared later in the file, so these two need the extra class
   to keep winning the tie on hover/active. */
.hal-scene.hal-chip:hover,
.hal-scene:hover  { border-color: rgba(255,255,255,0.28); }
.hal-scene.hal-chip:active,
.hal-scene:active { transform: translateY(1px) scale(0.98); }
.hal-scene-ic {
  width: 26px; height: 26px; border-radius: 9px; flex: none;
  background: rgba(255,255,255,0.06);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12);
  display: flex; align-items: center; justify-content: center;
}
/* svg inside: 15x15, viewBox 0 0 24 24, fill:none, stroke-width 1.8, round caps */
.hal-scene-ic svg { stroke: var(--hal-t3); transition: stroke .4s var(--hal-ease); }
.hal-scene.is-active .hal-scene-ic svg { stroke: var(--hal-accent); }
.hal-scene-label {
  font-size: 13px; font-weight: 600; letter-spacing: .01em;
  white-space: nowrap; color: var(--hal-t1);
  transition: color var(--hal-t-chip);
}
.hal-scene.is-active .hal-scene-label { color: var(--hal-on-accent); }


/* ==========================================================================
   8. CARD SHELL + HEADER + ENTRANCE STAGGER
   ========================================================================== */

.hal-card {
  position: relative; overflow: hidden;
  min-width: 0; min-height: 0;
  /* every card is a column so inner flex:1 regions (knob-wrap, dial-wrap,
     .hal-lights, .hal-media-body) actually distribute the height instead of
     pinning to the top and overflowing the card at 820px. */
  display: flex; flex-direction: column;
  padding: var(--hal-card-pad);
  border-radius: var(--hal-r-card);
  background: var(--hal-glass-bg);
  border: 1px solid var(--hal-glass-bd);
  backdrop-filter: var(--hal-glass-blur);
  -webkit-backdrop-filter: var(--hal-glass-blur);
  box-shadow: var(--hal-glass-sh);
  transition: transform var(--hal-t-card) var(--hal-ease),
              box-shadow var(--hal-t-card) var(--hal-ease),
              border-color var(--hal-t-card) var(--hal-ease);
}
.hal-card:hover {
  transform: translateY(-4px);
  border-color: var(--hal-glass-bd-hover);
  box-shadow: var(--hal-glass-sh-hover);
}

/* cards whose body must stretch vertically.
   .hal-card--lights joins the spec's three because a real room can hold far
   more than the design's four fixtures and the grid inside needs to scroll. */
.hal-card--amp,
.hal-card--climate,
.hal-card--shades,
.hal-card--lights { display: flex; flex-direction: column; }

/* entrance stagger */
.hal-card--media   { animation: hal-fadeUp .7s .08s var(--hal-ease) backwards; }
.hal-card--amp     { animation: hal-fadeUp .7s .14s var(--hal-ease) backwards; }
.hal-card--climate { animation: hal-fadeUp .7s .20s var(--hal-ease) backwards; }
.hal-card--lights  { animation: hal-fadeUp .7s .26s var(--hal-ease) backwards; }
.hal-card--shades  { animation: hal-fadeUp .7s .32s var(--hal-ease) backwards; }
.hal-card--vessel  { animation: hal-fadeUp .7s .38s var(--hal-ease) backwards; }

.hal-card-head {
  display: flex; align-items: center; justify-content: space-between;
  min-width: 0;
}
.hal-card-head--gap10 { margin-bottom: 10px; }
.hal-card-head--gap8  { margin-bottom: 8px; gap: 10px; }
.hal-card-titles { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.hal-card-label {
  font-size: 11px; font-weight: 600; letter-spacing: .18em;
  color: var(--hal-t4); text-transform: uppercase; white-space: nowrap;
}
.hal-card-sub {
  font-size: 11.5px; font-weight: 400; color: var(--hal-t6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hal-card-actions { display: flex; align-items: center; gap: 8px; flex: none; }


/* ==========================================================================
   9. SHARED PRIMITIVES - chips, wells, segments, helpers
   ========================================================================== */

/* --- the chip recipe (scenes, media sources, amp sources) --- */
.hal-chip {
  cursor: pointer;
  font-family: var(--hal-font-ui);
  border: 1px solid rgba(255,255,255,0.09);
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.015));
  color: var(--hal-t2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07);
  transition: all var(--hal-t-chip);
}
.hal-chip:hover  { border-color: rgba(255,255,255,0.24); }
.hal-chip:active { transform: scale(0.97); }
.hal-chip.is-active {
  border-color: rgba(232,180,90,0.55);
  background: linear-gradient(180deg, rgba(232,180,90,0.2), rgba(232,180,90,0.08));
  color: var(--hal-on-accent);
  box-shadow: 0 0 18px -4px rgba(232,180,90,0.5), inset 0 1px 0 rgba(255,255,255,0.15);
}

/* --- variant A: "dotted" chip (media app chips, amp zone chips) --- */
.hal-chip--dot {
  border-color: rgba(255,255,255,0.08);
  background: linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.01));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
  color: var(--hal-t3);
}
.hal-chip--dot.is-active {
  border-color: rgba(232,180,90,0.5);
  background: linear-gradient(180deg, rgba(232,180,90,0.18), rgba(232,180,90,0.06));
  color: var(--hal-on-accent);
  box-shadow: 0 0 14px -4px rgba(232,180,90,0.45), inset 0 1px 0 rgba(255,255,255,0.12);
}
.hal-chip-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: #3d434e; opacity: .4; box-shadow: none;
  transition: all var(--hal-t-chip);
}
.is-active > .hal-chip-dot { opacity: 1; }

/* --- variant B: "flat" chip (segmented controls inside a recessed well) --- */
.hal-chip--flat {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  color: var(--hal-t4);
}

/* --- recessed wells + segmented pills --- */
.hal-well {
  background: var(--hal-well-bg);
  border: 1px solid var(--hal-well-bd);
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.45);
}
.hal-segment {
  display: flex; gap: 4px; padding: 4px;
  border-radius: var(--hal-r-pill);
  background: rgba(0,0,0,0.32);
  border: 1px solid rgba(255,255,255,0.06);
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.5);
}
.hal-segment--sm {
  display: flex; gap: 3px; padding: 3px;
  border-radius: var(--hal-r-pill);
  background: rgba(0,0,0,0.3);
  border: 1px solid rgba(255,255,255,0.06);
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.45);
}
.hal-segment--fan {
  flex: 1; display: flex; gap: 5px; padding: 4px;
  border-radius: var(--hal-r-chip);
  background: rgba(0,0,0,0.3);
  border: 1px solid rgba(255,255,255,0.06);
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.45);
}

/* --- typography helpers --- */
.hal-micro {
  font-size: 11px; font-weight: 600; letter-spacing: .18em;
  color: var(--hal-t4); text-transform: uppercase;
}
.hal-num { font-family: var(--hal-font-num); font-variant-numeric: tabular-nums; }


/* ==========================================================================
   10. MEDIA CARD - .hal-card--media
   ========================================================================== */

.hal-media-state {
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em;
  color: var(--hal-t6);                       /* STANDBY  (no state class) */
  white-space: nowrap;
  transition: color var(--hal-t-chip);
}
.hal-media-state.is-on      { color: var(--hal-t2); }       /* PAUSED   (powered) */
.hal-media-state.is-playing { color: var(--hal-accent); }   /* NOW PLAYING */

.hal-media-power {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255,255,255,0.12);
  background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02));
  color: var(--hal-t4);
  box-shadow: none;
  transition: all .35s;
}
.hal-media-power:active { transform: scale(0.94); }
.hal-media-power.is-on {
  border-color: rgba(232,180,90,0.55);
  background: linear-gradient(180deg, rgba(232,180,90,0.25), rgba(232,180,90,0.1));
  color: var(--hal-on-accent);
  box-shadow: 0 0 16px -2px rgba(232,180,90,0.5);
}

.hal-media-body {
  display: flex; gap: 18px; align-items: center;
  flex: 1; min-height: 0;
  opacity: 1; transition: opacity .5s;
}
.hal-media-body.is-off { opacity: .35; }

.hal-media-art {
  position: relative;
  width: 96px; height: 96px; flex: none;
  border-radius: var(--hal-r-tile);
  overflow: hidden;
  background: radial-gradient(120% 120% at 30% 20%, #262b36, #12151b 62%, #0b0d11);
  display: flex; align-items: center; justify-content: center;
  color: var(--hal-t6);
  box-shadow:
    0 18px 36px -12px rgba(0,0,0,0.7),
    0 0 40px -6px var(--hal-art-glow, transparent);
  transition: box-shadow .6s;
}
.hal-media-art img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hal-media-meta { flex: 1; min-width: 0; }
.hal-media-title {
  font-family: var(--hal-font-num);
  font-size: 17px; font-weight: 600; letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--hal-t0);
}
.hal-media-sub {
  font-size: 12.5px; color: var(--hal-t3); margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.hal-progress { margin-top: 10px; }
.hal-progress-track {
  height: 4px; border-radius: 2px;
  background: rgba(255,255,255,0.08);
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.5);
  overflow: hidden;
}
.hal-progress-fill {
  height: 100%; width: var(--hal-prog, 0%); border-radius: 2px;
  background: linear-gradient(90deg, var(--hal-accent-dim), var(--hal-accent));
  box-shadow: 0 0 10px var(--hal-accent-glow);
  transition: width .4s var(--hal-ease);
}
.hal-progress-times {
  display: flex; justify-content: space-between; margin-top: 6px;
  font-family: var(--hal-font-num);
  font-size: 11px; letter-spacing: .06em; color: var(--hal-t5);
  font-variant-numeric: tabular-nums;
}

.hal-transport { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.hal-transport-btn {
  width: 44px; height: 44px; border-radius: 50%; flex: none;
  cursor: pointer;
  border: 1px solid rgba(255,255,255,0.1);
  background: linear-gradient(180deg, rgba(255,255,255,0.07), rgba(255,255,255,0.02));
  color: var(--hal-t1);
  display: flex; align-items: center; justify-content: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12), 0 8px 16px -8px rgba(0,0,0,0.8);
  transition: all var(--hal-t-btn);
}
.hal-transport-btn:hover  { color: #fff; }
.hal-transport-btn:active { transform: scale(0.93); }

.hal-play {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  cursor: pointer;
  border: 1px solid var(--hal-accent-bd);
  background: radial-gradient(120% 120% at 32% 22%,
              var(--hal-accent-hi), var(--hal-accent) 58%, var(--hal-accent-lo));
  color: var(--hal-glyph-dark);
  display: flex; align-items: center; justify-content: center;
  box-shadow:
    0 12px 26px -8px var(--hal-accent-glow),
    inset 0 1px 1px rgba(255,255,255,0.5),
    inset 0 -6px 10px rgba(0,0,0,0.25);
  transition: all var(--hal-t-btn);
}
.hal-play:active { transform: scale(0.94); }

.hal-media-apps { display: flex; gap: 8px; margin-top: 10px; }
.hal-media-app {
  flex: 1; min-width: 0; min-height: 40px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--hal-r-chip-sm);
  padding: 0 6px; white-space: nowrap; cursor: pointer;
}
.hal-media-app:hover  { border-color: rgba(255,255,255,0.26); }
.hal-media-app:active { transform: scale(0.95); }
.hal-media-app-name {
  font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
  overflow: hidden; text-overflow: ellipsis;
}
/* the active app chip is tinted in the app's OWN brand colour, not amber.
   Set --hal-app-rgb on the chip, e.g. style="--hal-app-rgb:229,9,20". */
.hal-media-app .hal-chip-dot { background: rgb(var(--hal-app-rgb)); }
.hal-media-app.is-active {
  border-color: rgba(var(--hal-app-rgb), 0.6);
  background: linear-gradient(180deg, rgba(var(--hal-app-rgb), 0.2), rgba(var(--hal-app-rgb), 0.06));
  color: #fff;
  box-shadow: 0 0 20px -4px rgba(var(--hal-app-rgb), 0.55), inset 0 1px 0 rgba(255,255,255,0.16);
}
.hal-media-app.is-active .hal-chip-dot {
  opacity: 1;
  box-shadow: 0 0 10px rgb(var(--hal-app-rgb));
}

.hal-media-srcs { display: flex; gap: 8px; margin-top: 8px; }
.hal-media-src {
  flex: 1; min-width: 0;
  padding: 9px 4px; border-radius: var(--hal-r-chip);
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer;
}


/* ==========================================================================
   11. AMPLIFIER CARD - .hal-card--amp
   ========================================================================== */

.hal-mute {
  padding: 6px 12px; border-radius: var(--hal-r-pill); flex: none;
  cursor: pointer;
  font-family: var(--hal-font-ui);
  font-size: 10.5px; font-weight: 700; letter-spacing: .14em;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(255,255,255,0.04);
  color: var(--hal-t4);
  transition: all var(--hal-t-chip);
}
.hal-mute:active { transform: scale(0.96); }
.hal-mute.is-muted {
  border-color: rgba(255,95,87,0.55);
  background: rgba(255,95,87,0.14);
  color: var(--hal-alert-text);
}

.hal-amp-sub {
  font-size: 11.5px; color: var(--hal-t6); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.hal-amp-zones { display: flex; gap: 7px; margin-top: 8px; }
.hal-amp-zone {
  flex: 1; min-width: 0; min-height: 40px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--hal-r-chip-sm);
  font-size: 11.5px; font-weight: 600;
  white-space: nowrap; cursor: pointer;
}
.hal-amp-zone:hover  { border-color: rgba(255,255,255,0.26); }
.hal-amp-zone:active { transform: scale(0.96); }
.hal-amp-zone .hal-chip-dot { background: #3d434e; opacity: 1; box-shadow: none; }
.hal-amp-zone.is-active .hal-chip-dot {
  background: var(--hal-accent);
  box-shadow: 0 0 8px rgba(232,180,90,0.7);
}

/* --- the rotary knob --- */
.hal-knob-wrap {
  flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 4px 0 2px;
}
.hal-knob {
  position: relative;
  width: 144px; height: 144px; flex: none;
  cursor: grab;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
}
.hal-knob.is-dragging { cursor: grabbing; }

/* the 270deg ring, 10px thick, cut by a radial mask.
   --hal-vol-arc is written by halcyon.js during a drag and by the component
   on every state change; the fallback below keeps the ring correct for
   markup that only sets --hal-vol-sweep. */
.hal-knob-arc {
  position: absolute; inset: 0; border-radius: 50%;
  background: var(--hal-vol-arc,
    conic-gradient(from 225deg,
      rgba(var(--hal-accent-rgb), 0.95) 0deg,
      rgba(var(--hal-accent-rgb), 0.55) var(--hal-vol-sweep, 0deg),
      rgba(255,255,255,0.07) var(--hal-vol-sweep, 0deg) 270deg,
      transparent 270deg));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 10px), #000 calc(100% - 9px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 10px), #000 calc(100% - 9px));
  filter: drop-shadow(0 0 10px var(--hal-vol-arc-glow, transparent));
  transition: filter .4s;
}
.hal-knob-body {
  position: absolute; inset: 16px; border-radius: 50%;
  background:
    conic-gradient(from 140deg, rgba(255,255,255,0.05), transparent 25%,
                   rgba(255,255,255,0.04) 50%, transparent 75%, rgba(255,255,255,0.05)),
    radial-gradient(125% 125% at 30% 18%, #3f4552, #161920 55%, #0b0d11);
  box-shadow:
    0 24px 40px -10px rgba(0,0,0,0.9),
    inset 0 1.5px 1px rgba(255,255,255,0.22),
    inset 0 -12px 20px rgba(0,0,0,0.6),
    0 0 0 1px rgba(255,255,255,0.06);
}
.hal-knob-rotor {
  position: absolute; inset: 22px; border-radius: 50%;
  transform: rotate(var(--hal-vol-deg, -135deg));
  transition: transform .12s linear;
}
.hal-knob.is-dragging .hal-knob-rotor { transition: none; }
.hal-knob-pin {
  position: absolute; top: 5px; left: 50%; margin-left: -2px;
  width: 4px; height: 15px; border-radius: 3px;
  background: var(--hal-accent);
  box-shadow: 0 0 10px 1px rgba(232,180,90,0.7);
  transition: background var(--hal-t-chip), box-shadow var(--hal-t-chip);
}
.hal-knob.is-muted .hal-knob-pin {
  background: var(--hal-t6);
  box-shadow: 0 0 10px 1px transparent;
}
.hal-knob-readout {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  pointer-events: none;
}
.hal-knob-value {
  font-family: var(--hal-font-num);
  font-size: 30px; font-weight: 600; letter-spacing: -0.02em;
  color: var(--hal-value);
  font-variant-numeric: tabular-nums;
  transition: color var(--hal-t-chip);
}
.hal-knob.is-muted .hal-knob-value { color: var(--hal-t5); }
.hal-knob-db {
  font-family: var(--hal-font-num);
  font-size: 11px; letter-spacing: .14em; color: var(--hal-t5);
  margin-top: 2px;
}

/* --- VU meter: 16 bars, per-bar duration/delay from the spec table --- */
.hal-vu {
  display: flex; justify-content: center; align-items: flex-end;
  gap: 3px; height: 22px;
  opacity: .13; transition: opacity .5s;
}
.hal-vu.is-active { opacity: 1; }
.hal-vu-bar {
  width: 5px; height: 20px; border-radius: 2px;
  background: linear-gradient(180deg, var(--hal-accent), var(--hal-accent-dim));
  transform-origin: bottom;
  transform: scaleY(.22);
}
/* 16 bars; dur = (0.55 + ((i*37) % 40) / 55), delay = -(i*0.13). The bars keep
   animating while the meter is idle exactly as in the prototype - the .13
   container opacity is what reads as "off". Compositor-only transforms. */
.hal-vu-bar:nth-child(1)  { animation: hal-vu 0.55s ease-in-out -0.00s infinite; }
.hal-vu-bar:nth-child(2)  { animation: hal-vu 1.22s ease-in-out -0.13s infinite; }
.hal-vu-bar:nth-child(3)  { animation: hal-vu 1.17s ease-in-out -0.26s infinite; }
.hal-vu-bar:nth-child(4)  { animation: hal-vu 1.11s ease-in-out -0.39s infinite; }
.hal-vu-bar:nth-child(5)  { animation: hal-vu 1.06s ease-in-out -0.52s infinite; }
.hal-vu-bar:nth-child(6)  { animation: hal-vu 1.00s ease-in-out -0.65s infinite; }
.hal-vu-bar:nth-child(7)  { animation: hal-vu 0.95s ease-in-out -0.78s infinite; }
.hal-vu-bar:nth-child(8)  { animation: hal-vu 0.90s ease-in-out -0.91s infinite; }
.hal-vu-bar:nth-child(9)  { animation: hal-vu 0.84s ease-in-out -1.04s infinite; }
.hal-vu-bar:nth-child(10) { animation: hal-vu 0.79s ease-in-out -1.17s infinite; }
.hal-vu-bar:nth-child(11) { animation: hal-vu 0.73s ease-in-out -1.30s infinite; }
.hal-vu-bar:nth-child(12) { animation: hal-vu 0.68s ease-in-out -1.43s infinite; }
.hal-vu-bar:nth-child(13) { animation: hal-vu 0.62s ease-in-out -1.56s infinite; }
.hal-vu-bar:nth-child(14) { animation: hal-vu 0.57s ease-in-out -1.69s infinite; }
.hal-vu-bar:nth-child(15) { animation: hal-vu 1.24s ease-in-out -1.82s infinite; }
.hal-vu-bar:nth-child(16) { animation: hal-vu 1.19s ease-in-out -1.95s infinite; }

/* 11 Denon inputs in a 3-column card: equal-flex squeezed them to ~20px of
   unreadable sliver. Scroll instead, at a legible minimum width. */
.hal-amp-srcs {
  display: flex; gap: 7px; margin-top: 10px;
  flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 2px; flex: none;
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 18px), transparent 100%);
          mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 18px), transparent 100%);
}
.hal-amp-srcs::-webkit-scrollbar { display: none; }
.hal-amp-src {
  flex: 0 0 auto; min-width: 56px; min-height: 36px;
  padding: 8px 11px; border-radius: var(--hal-r-chip-sm);
  font-size: 11px; font-weight: 600;
  text-align: center; white-space: nowrap;
  cursor: pointer;
}


/* ==========================================================================
   12. CLIMATE CARD - .hal-card--climate
   ========================================================================== */

/* mode channel. Put data-hal-mode on the card (or any ancestor of the dial). */
.hal-card--climate[data-hal-mode="cool"] {
  --hal-mode-col:   #7dd8ff;
  --hal-mode-rgb:   125, 216, 255;
  --hal-mode-bd:    rgba(125, 216, 255, 0.50);
  --hal-mode-bg:    rgba(125, 216, 255, 0.14);
  --hal-mode-bd-45: rgba(125, 216, 255, 0.45);
  --hal-mode-bg-13: rgba(125, 216, 255, 0.13);
  --hal-mode-glow:  rgba(125, 216, 255, 0.45);
}
.hal-card--climate[data-hal-mode="heat"] {
  --hal-mode-col:   #ff9d66;
  --hal-mode-rgb:   255, 157, 102;
  --hal-mode-bd:    rgba(255, 157, 102, 0.50);
  --hal-mode-bg:    rgba(255, 157, 102, 0.14);
  --hal-mode-bd-45: rgba(255, 157, 102, 0.45);
  --hal-mode-bg-13: rgba(255, 157, 102, 0.13);
  --hal-mode-glow:  rgba(255, 157, 102, 0.45);
}
.hal-card--climate[data-hal-mode="auto"] {
  --hal-mode-col:   #e8b45a;
  --hal-mode-rgb:   232, 180, 90;
  --hal-mode-bd:    rgba(232, 180, 90, 0.50);
  --hal-mode-bg:    rgba(232, 180, 90, 0.14);
  --hal-mode-bd-45: rgba(232, 180, 90, 0.45);
  --hal-mode-bg-13: rgba(232, 180, 90, 0.13);
  --hal-mode-glow:  rgba(232, 180, 90, 0.45);
}

.hal-modes { display: flex; gap: 6px; flex: none; }
.hal-mode {
  width: 38px; height: 38px; border-radius: var(--hal-r-chip-sm); flex: none;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255,255,255,0.09);
  background: rgba(255,255,255,0.03);
  color: var(--hal-t4);
  transition: all var(--hal-t-chip);
}
.hal-mode:active { transform: scale(0.94); }
.hal-mode.is-active {
  border-color: var(--hal-mode-bd);
  background: var(--hal-mode-bg);
  color: var(--hal-mode-col);
}
/* svg 14x14, viewBox 0 0 24 24, fill:none, stroke:currentColor, width 1.9 */

.hal-dial-wrap {
  position: relative; flex: 1;
  display: flex; align-items: center; justify-content: center;
  padding: 2px 0 0;
}
.hal-dial {
  position: relative;
  width: 176px; height: 176px; flex: none;
  cursor: pointer;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
}
.hal-dial-svg { position: absolute; inset: 0; overflow: visible; }
.hal-dial-svg path { fill: none; stroke-width: 9; stroke-linecap: round; }
.hal-dial-track  { stroke: rgba(255,255,255,0.07); }
.hal-dial-value  {
  stroke: var(--hal-mode-col);
  filter: drop-shadow(0 0 10px var(--hal-mode-glow));
  transition: stroke .4s var(--hal-ease);
}
.hal-dial-handle { fill: #f4f6f9; filter: drop-shadow(0 3px 6px rgba(0,0,0,0.6)); }
.hal-dial-pin    { fill: var(--hal-mode-col); transition: fill .4s var(--hal-ease); }
.hal-dial.is-dragging .hal-dial-value,
.hal-dial.is-dragging .hal-dial-pin { transition: none; }

.hal-dial-face {
  position: absolute; inset: 28px; border-radius: 50%;
  background:
    radial-gradient(130% 130% at 32% 20%, rgba(255,255,255,0.07), rgba(255,255,255,0.015) 55%),
    rgba(10,12,16,0.5);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.1),
    inset 0 -8px 20px rgba(0,0,0,0.45),
    0 14px 28px -12px rgba(0,0,0,0.7);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  pointer-events: none;
}
.hal-dial-verb {
  font-size: 10.5px; font-weight: 600; letter-spacing: .16em;
  color: var(--hal-mode-col);
  transition: color .4s;
}
.hal-dial-target {
  font-family: var(--hal-font-num);
  font-size: 34px; font-weight: 600; letter-spacing: -0.03em; line-height: 1.1;
  margin-top: 2px; color: var(--hal-t0);
  font-variant-numeric: tabular-nums;
}
.hal-dial-now {
  font-family: var(--hal-font-num);
  font-size: 11.5px; letter-spacing: .08em; color: var(--hal-t5);
  margin-top: 3px;
}
.hal-dial-min,
.hal-dial-max {
  position: absolute; bottom: 16px;
  font-family: var(--hal-font-num);
  font-size: 10px; color: var(--hal-t7);
  pointer-events: none;
}
.hal-dial-min { left: 24px; }
.hal-dial-max { right: 20px; }

.hal-fan-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.hal-fan-label {
  font-size: 11px; font-weight: 600; letter-spacing: .16em;
  color: var(--hal-t4); flex: none;
}
.hal-fan-step {
  flex: 1; min-width: 0;
  padding: 9px 0; border-radius: var(--hal-r-fan);
  cursor: pointer;
  font-family: var(--hal-font-num);
  font-size: 11.5px; font-weight: 600; letter-spacing: .08em;
  text-align: center;
  border: 1px solid transparent;
  background: transparent;
  color: var(--hal-t4);
  transition: all var(--hal-t-chip);
}
.hal-fan-step:active { transform: scale(0.96); }
.hal-fan-step.is-active {
  border-color: var(--hal-mode-bd-45);
  background: var(--hal-mode-bg-13);
  color: var(--hal-mode-col);
}


/* ==========================================================================
   13. LIGHTING CARD - .hal-card--lights
   ========================================================================== */

.hal-master {
  position: relative;
  width: 46px; height: 26px; border-radius: var(--hal-r-pill); flex: none;
  cursor: pointer;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(0,0,0,0.4);
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.4);
  transition: all .35s;
}
.hal-master.is-on {
  border-color: rgba(232,180,90,0.5);
  background: linear-gradient(180deg, rgba(232,180,90,0.5), rgba(232,180,90,0.25));
}
.hal-master-knob {
  position: absolute; top: 2px; left: 2px;
  width: 20px; height: 20px; border-radius: 50%;
  background: radial-gradient(120% 120% at 32% 22%, #fdfdfe, #c9ccd4 70%);
  box-shadow: 0 3px 7px rgba(0,0,0,0.5);
  transform: translateX(0);
  transition: transform var(--hal-t-slide) var(--hal-ease);
}
.hal-master.is-on .hal-master-knob { transform: translateX(20px); }

/* The design fits exactly four fixtures. Real rooms hold up to a dozen, so
   the track count flexes while the 52x112 well geometry never shrinks. */
.hal-lights {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(52px, 1fr));
  gap: 12px;
  align-content: start;
  justify-items: center;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.hal-light { display: flex; flex-direction: column; align-items: center; gap: 9px; }

.hal-dimwell {
  position: relative; overflow: hidden;
  width: 52px; height: 112px; border-radius: var(--hal-r-dimwell); flex: none;
  cursor: ns-resize;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
  background: rgba(0,0,0,0.38);
  border: 1px solid rgba(255,255,255,0.07);
  box-shadow: inset 0 3px 10px rgba(0,0,0,0.6), var(--hal-well-glow, 0 0 0 transparent);
  transition: box-shadow .5s;
}
.hal-dimfill {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: var(--hal-fill, 0%);
  background: linear-gradient(180deg, var(--hal-warm-hi), var(--hal-warm) 70%, var(--hal-warm-lo));
  box-shadow: 0 -2px 14px rgba(255,190,110,0.55), inset 0 2px 3px rgba(255,255,255,0.55);
  border-radius: 0 0 23px 23px;
  transition: height var(--hal-t-dim) var(--hal-ease);
}
.hal-dimwell.is-dragging .hal-dimfill { transition: none; }
.hal-dimwell-notch {
  position: absolute; left: 12px; right: 12px; top: 8px;
  height: 3px; border-radius: 2px;
  background: rgba(255,255,255,0.12);
}

.hal-light-btn {
  background: none; border: none; padding: 0;
  cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  max-width: 100%;
  opacity: 1; transition: opacity .4s;
}
.hal-light-btn.is-off  { opacity: .55; }
.hal-light-btn:active  { transform: scale(0.95); }
/* svg 17x17, viewBox 0 0 24 24, fill:none, stroke-width 1.7 - and NO stroke
   attribute in the markup, so the rule below can drive it. */
.hal-light-icon { stroke: var(--hal-t6); transition: stroke .4s; }
.hal-light-btn.is-on .hal-light-icon { stroke: var(--hal-warm-icon); }
.hal-light-name {
  font-size: 11.5px; font-weight: 600; color: var(--hal-t1);
  max-width: 100%; text-align: center;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hal-light-value {
  font-family: var(--hal-font-num);
  font-size: 10.5px; letter-spacing: .08em; color: var(--hal-t5);
}


/* ==========================================================================
   14. SHADES CARD - .hal-card--shades
   ========================================================================== */

.hal-shade-zone {
  padding: 6px 13px; border-radius: var(--hal-r-pill); flex: none;
  cursor: pointer; white-space: nowrap;
  font-family: var(--hal-font-ui);
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  border: 1px solid transparent;
  background: transparent;
  color: var(--hal-t4);
  transition: all var(--hal-t-chip);
}
.hal-shade-zone:active { transform: scale(0.96); }
.hal-shade-zone.is-active {
  border-color: rgba(232,180,90,0.5);
  background: linear-gradient(180deg, rgba(232,180,90,0.18), rgba(232,180,90,0.06));
  color: var(--hal-on-accent);
}

/* fixed 104px windows, wrapping instead of shrinking (spec section 8 rule 1) */
.hal-shades {
  flex: 1; min-height: 0;
  display: flex; flex-wrap: wrap; gap: 12px;
  justify-content: center; align-content: center;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.hal-shade {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  opacity: 1; transition: opacity .35s;
}
.hal-shade.is-dimmed { opacity: .38; }

.hal-window {
  position: relative; overflow: hidden;
  width: 104px; height: 104px; border-radius: var(--hal-r-tile); flex: none;
  cursor: ns-resize;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
  border: 1px solid rgba(255,255,255,0.12);
  background: linear-gradient(180deg, #17223d 0%, #0e1526 55%, #0a0f1b 100%);
  box-shadow: inset 0 0 24px rgba(0,0,0,0.55), 0 12px 24px -12px rgba(0,0,0,0.7);
}
.hal-window-stars {
  position: absolute; top: 18px; left: 16px;
  width: 3px; height: 3px; border-radius: 50%;
  background: rgba(255,255,255,0.65);
  box-shadow:
    24px 10px 0 -0.5px rgba(255,255,255,0.4),
    52px 4px  0 -1px   rgba(255,255,255,0.3),
    70px 16px 0 -0.5px rgba(255,255,255,0.45);
}
.hal-window-moon {
  position: absolute; top: 26px; right: 16px;
  width: 14px; height: 14px; border-radius: 50%;
  background: radial-gradient(circle at 38% 35%, #fdf6e3, #d9ceac 68%, #b9ad8a);
  box-shadow: 0 0 16px 3px rgba(250,240,210,0.3);
}
.hal-window-horizon {
  position: absolute; left: 0; right: 0; bottom: 0; height: 34%;
  background: linear-gradient(180deg, transparent, rgba(20,26,40,0.9));
}
.hal-window-panel {
  position: absolute; left: 0; right: 0; top: 0;
  height: var(--hal-pos, 0%);
  background:
    repeating-linear-gradient(180deg, rgba(226,231,240,0.16) 0 3px, rgba(148,155,170,0.05) 3px 11px),
    linear-gradient(180deg, rgba(30,34,44,0.92), rgba(22,25,33,0.88));
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  border-bottom: 3px solid rgba(235,238,245,0.35);
  box-shadow: 0 6px 16px rgba(0,0,0,0.5);
  transition: height var(--hal-t-shade) var(--hal-ease);
}
.hal-window.is-dragging .hal-window-panel { transition: none; }
/* A real shade takes TravelMs (10 s) to run, not .7 s. Set
   --hal-t-shade on the .hal-window to the real travel time when the panel is
   moving under a command, so the drawing tracks the physical blind. */

.hal-shade-caption { text-align: center; max-width: 104px; }
.hal-shade-name {
  font-size: 11.5px; font-weight: 600; color: var(--hal-t1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hal-shade-value {
  font-family: var(--hal-font-num);
  font-size: 10.5px; letter-spacing: .08em; color: var(--hal-t5);
  margin-top: 2px;
}

.hal-presets { display: flex; gap: 7px; margin-top: 8px; }
.hal-preset {
  flex: 1; min-width: 0;
  padding: 10px 2px; border-radius: var(--hal-r-chip-sm);
  cursor: pointer; text-align: center;
  font-family: var(--hal-font-ui);
  font-size: 11.5px; font-weight: 600;
  border: 1px solid rgba(255,255,255,0.1);
  background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02));
  color: var(--hal-t1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
  transition: all .25s;
}
.hal-preset:hover  { color: #fff; border-color: rgba(255,255,255,0.26); }
.hal-preset:active { transform: scale(0.97); }


/* ==========================================================================
   15. VESSEL CARD - .hal-card--vessel  (replaces the design's Cameras card)
   ========================================================================== */

.hal-card--vessel { display: flex; flex-direction: column; }

.hal-vessel-body { flex: 1; min-height: 0; display: flex; gap: 12px; }

.hal-vessel-panel {
  position: relative; overflow: hidden;
  flex: 1; min-width: 0;
  border-radius: var(--hal-r-feed);
  padding: 14px 16px;
  display: flex; flex-direction: column; justify-content: space-between;
  background: linear-gradient(180deg, #17223d 0%, #0e1526 55%, #0a0f1b 100%);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 0 24px rgba(0,0,0,0.55), 0 12px 24px -12px rgba(0,0,0,0.7);
}
.hal-vessel-scan {
  position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(180deg,
              rgba(226,231,240,0.16) 0 3px, rgba(148,155,170,0.05) 3px 11px);
  opacity: .35;
}
.hal-vessel-vignette {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 0%, transparent 55%, rgba(0,0,0,0.55));
}
.hal-vessel-live {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--hal-alert);
  box-shadow: 0 0 10px var(--hal-alert);
  animation: hal-livePulse 1.6s ease-in-out infinite;
}
.hal-vessel-badge {
  position: relative; z-index: 1;
  display: flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em;
  color: var(--hal-t2); white-space: nowrap;
}
.hal-vessel-badge--cool { color: var(--hal-cool); }
.hal-vessel-primary {
  position: relative; z-index: 1;
  font-family: var(--hal-font-num);
  font-size: 34px; font-weight: 600; letter-spacing: -0.03em; line-height: 1.1;
  color: var(--hal-t0);
  font-variant-numeric: tabular-nums;
}
.hal-vessel-unit {
  position: relative; z-index: 1;
  font-family: var(--hal-font-num);
  font-size: 11.5px; letter-spacing: .08em; color: var(--hal-t5);
  margin-top: 3px;
}
.hal-vessel-corner {
  position: absolute; width: 14px; height: 14px; pointer-events: none;
  border-color: rgba(255,255,255,0.24);
  border-style: solid; border-width: 0;
}
.hal-vessel-corner--tl { top: 10px;    left: 10px;    border-top-width: 2px;    border-left-width: 2px; }
.hal-vessel-corner--tr { top: 10px;    right: 10px;   border-top-width: 2px;    border-right-width: 2px; }
.hal-vessel-corner--bl { bottom: 10px; left: 10px;    border-bottom-width: 2px; border-left-width: 2px; }
.hal-vessel-corner--br { bottom: 10px; right: 10px;   border-bottom-width: 2px; border-right-width: 2px; }

.hal-vessel-rail {
  width: 138px; flex: none;
  display: flex; flex-direction: column; gap: 7px;
  overflow-y: auto; overscroll-behavior: contain;
}
.hal-vessel-stat {
  min-height: 40px; border-radius: var(--hal-r-chip-sm); flex: none;
  padding: 0 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 7px;
  border: 1px solid rgba(255,255,255,0.08);
  background: linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0.01));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
.hal-vessel-stat-label {
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em;
  color: var(--hal-t4); white-space: nowrap;
}
.hal-vessel-stat-value {
  font-family: var(--hal-font-num);
  font-size: 13px; font-weight: 600; letter-spacing: .02em;
  color: var(--hal-t1); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.hal-vessel-stat.is-offline .hal-vessel-stat-value { color: var(--hal-t6); }


/* ==========================================================================
   16. SHARED STATES + SMALL EXTENSIONS
   ========================================================================== */

/* Offline devices. No design source for this - it is the minimum honest
   addition, kept to exactly the two declarations the spec allows. */
.hal-root .is-offline { pointer-events: none; opacity: .45; }
.hal-root .is-offline .hal-light-name,
.hal-root .is-offline .hal-shade-name,
.hal-root .is-offline .hal-media-title { color: var(--hal-t6); }

/* Nothing behind a panel: label plus an em dash in t6, never an invented
   number (spec section 8 rule 7). */
.hal-empty {
  display: flex; align-items: center; justify-content: center;
  flex: 1; min-height: 60px;
  font-size: 11.5px; letter-spacing: .06em; color: var(--hal-t6);
  text-align: center;
}

/* EXTENSION (not in the class contract): the wall-mounted iPad has no browser
   chrome and HalcyonLayout drops the MudBlazor drawer, so the top bar needs a
   way back to the dashboard. */
.hal-back {
  display: flex; align-items: center; gap: 6px; flex: none;
  padding: 7px 12px; border-radius: var(--hal-r-pill);
  font-size: 11px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  border: 1px solid rgba(255,255,255,0.09);
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.015));
  color: var(--hal-t3);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07);
  transition: all var(--hal-t-chip);
  cursor: pointer;
}
.hal-back:hover  { color: #fff; border-color: rgba(255,255,255,0.24); }
.hal-back:active { transform: scale(0.97); }

/* EXTENSION (not in the class contract): ISnackbar is dead under
   HalcyonLayout (no MudSnackbarProvider), so errors need a surface in the
   Halcyon visual language. */
.hal-toast {
  position: absolute; z-index: 20; left: 50%; bottom: 22px;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  max-width: min(520px, calc(100% - 48px));
  padding: 11px 16px; border-radius: var(--hal-r-chip);
  font-size: 12px; letter-spacing: .02em; color: var(--hal-t1);
  background: var(--hal-glass-bg);
  border: 1px solid var(--hal-glass-bd);
  backdrop-filter: var(--hal-glass-blur);
  -webkit-backdrop-filter: var(--hal-glass-blur);
  box-shadow: 0 24px 48px -18px rgba(0,0,0,0.85), inset 0 1px 0 rgba(255,255,255,0.12);
  animation: hal-fadeUp .35s var(--hal-ease) both;
}
.hal-toast::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--hal-alert); box-shadow: 0 0 10px var(--hal-alert);
}


/* ==========================================================================
   17. HOST INTEGRATION + PORTRAIT + REDUCED MOTION
   ========================================================================== */

/* wwwroot/app.css paints a global film grain on body::before and lets the page
   scroll. halcyon.js adds .halcyon to <body> on mount and removes it on
   dispose, so /halcyon owns its own grain and never double-grains, while
   every other route is untouched. */
body.halcyon { overflow: hidden; }
body.halcyon::before { content: none; }

/* Portrait (820x1180): spans change, the date block hides. Nothing else. */
@media (orientation: portrait) {
  .hal-card--media   { grid-column: span 7; }
  .hal-card--amp     { grid-column: span 5; }
  .hal-card--climate { grid-column: span 6; }
  .hal-card--lights  { grid-column: span 6; }
  .hal-card--shades  { grid-column: span 6; }
  .hal-card--vessel  { grid-column: span 12; }

  .hal-topinfo-date,
  .hal-topinfo-status { display: none; }
}

/* Narrow desktop windows over the tunnel: keep the card geometry, stack the
   grid rather than crushing the 144px knob and 176px dial. */
@media (max-width: 860px) {
  .hal-card--media,
  .hal-card--amp,
  .hal-card--climate,
  .hal-card--lights,
  .hal-card--shades,
  .hal-card--vessel { grid-column: span 12; }
  .hal-header { flex-direction: column; align-items: flex-start; gap: 12px; }
  .hal-scenes { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  .hal-orb-1,
  .hal-orb-2,
  .hal-vessel-live,
  .hal-vu-bar,
  .hal-topbar,
  .hal-header-left,
  .hal-scenes,
  .hal-grid--swapA,
  .hal-grid--swapB,
  .hal-card--media,
  .hal-card--amp,
  .hal-card--climate,
  .hal-card--lights,
  .hal-card--shades,
  .hal-card--vessel,
  .hal-toast { animation: none !important; }

  .hal-vu-bar { transform: scaleY(.6); }
  .hal-card:hover { transform: none; }
}


/* ==========================================================================
   18. APPENDED BY Components/Halcyon/HalcyonVessel.razor

   Section 15 supplies the vessel panel, badge, figure and stat primitives but
   no row containers for them, and its LIVE dot is the design's fixed red
   camera tally. This card's dot instead reports the age of the NMEA 2000 feed,
   so it needs three freshness states. No new hues: the "ok" green is the
   prototype's own alt-accent (#8fe6b0, spec section 1.1), "stale" is the amber
   accent, "dead" is the design's --hal-alert red already on .hal-vessel-live.
   ========================================================================== */

.hal-vessel-top {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.hal-vessel-hero {
  position: relative; z-index: 1;
  display: flex; align-items: flex-end; flex-wrap: wrap; gap: 8px 20px;
  padding: 6px 0;
}
.hal-vessel-figure { display: flex; flex-direction: column; min-width: 0; }
.hal-vessel-strip {
  position: relative; z-index: 1;
  display: flex; flex-wrap: wrap; gap: 5px 16px;
}
.hal-vessel-strip-item { display: flex; align-items: baseline; gap: 7px; min-width: 0; }

/* Feed freshness (see FeedLevel in HalcyonVessel.razor). */
.hal-vessel-live--ok    { background: #8fe6b0; box-shadow: 0 0 10px #8fe6b0; }
.hal-vessel-live--stale {
  background: var(--hal-accent);
  box-shadow: 0 0 10px var(--hal-accent-glow);
  animation-duration: .8s;
}
.hal-vessel-live--dead  { animation: none; }

.hal-vessel-badge--warn  { color: var(--hal-accent); }
.hal-vessel-badge--alert { color: var(--hal-alert-text); }

/* Battery / tank thresholds, same ladder Systems.razor uses. */
.hal-vessel-stat--warn  .hal-vessel-stat-value { color: var(--hal-accent); }
.hal-vessel-stat--alert .hal-vessel-stat-value { color: var(--hal-alert-text); }

/* ==========================================================================
   18. SHORT-VIEWPORT PASS  (added 2026-08-24)
   The design's fixed control geometry (176px dial, 144px knob, 112px dimmer
   wells, 104px shade windows) was sized for a tall canvas. On the real iPad
   target (1180x820) the two grid rows plus top bar and header exceed the
   viewport, so the climate FAN row and the top of the shade windows were
   being clipped by .hal-card{overflow:hidden}. Scale the fixed geometry down
   instead of cropping it. Everything stays proportional - the dial and knob
   SVGs carry viewBoxes, so they scale cleanly.
   ========================================================================== */

@media (max-height: 900px) {
  .hal-dial     { width: 148px; height: 148px; }
  .hal-knob     { width: 124px; height: 124px; }
  .hal-window   { width: 88px;  height: 88px;  }
  .hal-dimwell  { height: 92px; }
  .hal-media-art { width: 84px; height: 84px; }
  .hal-grid     { gap: 10px; }
}

@media (max-height: 780px) {
  .hal-dial     { width: 126px; height: 126px; }
  .hal-knob     { width: 108px; height: 108px; }
  .hal-window   { width: 76px;  height: 76px;  }
  .hal-dimwell  { height: 76px; }
  .hal-media-art { width: 72px; height: 72px; }
}

/* Let the fixed-size controls give up space before the card clips them. */
.hal-dial-wrap, .hal-knob-wrap { min-height: 0; }
.hal-dial, .hal-knob { max-width: 100%; max-height: 100%; }

/* --- 18b. short-viewport corrections (2026-08-24, from visual iteration) --- */

/* Lighting: .hal-lights used align-content:start, so the wells pinned to the
   top of a flex:1 grid and left a large void beneath them. Centre them. */
.hal-lights { align-content: center; }

/* Shades: 4 windows need two rows, and at 820px the second row's captions were
   cut off. Shrink the window and tighten the caption so both rows fit whole. */
@media (max-height: 900px) {
  .hal-window { width: 76px; height: 76px; }
  .hal-shades { gap: 8px; }
  .hal-shade  { gap: 3px; }
  .hal-shade-caption { max-width: 84px; }
  .hal-shade-name  { font-size: 10.5px; }
  .hal-shade-value { font-size: 9.5px; }
}
@media (max-height: 780px) {
  .hal-window { width: 66px; height: 66px; }
}

/* Climate header: the room sub-label and the READ ONLY badge collided because
   the badge could be squeezed. Let the sub truncate, never the badge. */
.hal-card-head > .hal-card-titles { min-width: 0; flex: 1 1 auto; }
.hal-card-head > .hal-micro { flex: 0 0 auto; white-space: nowrap; margin-left: 8px; }
.hal-card--climate .hal-card-sub { min-width: 0; flex: 0 1 auto; }

/* --- 18c. final fit corrections (2026-08-24) --- */
@media (max-height: 900px) {
  /* two rows of shade windows + captions were ~10px taller than the card body */
  .hal-window { width: 68px; height: 68px; }
  .hal-shade-caption { max-width: 78px; }

  /* CLIMATE's "Saloon - no feedback" sub duplicated what the READ ONLY badge
     already says, and collided with it. Badge wins; sub is dropped. */
  .hal-card--climate .hal-card-sub { display: none; }
}

/* 4 shades wrapped 3+1, which looks accidental. Constrain the row so they
   pair up 2+2 (and 3-per-row only when the card is genuinely wide). */
@media (max-height: 900px) {
  .hal-shades { max-width: 172px; margin-left: auto; margin-right: auto; }
}
