/* The HUD voice interface.
 *
 * Deliberately text-free while listening: in voice mode the transcript is noise,
 * not information — you already know what you said. State is carried entirely by
 * the ring's colour and motion, so a glance tells you whether it's idle,
 * listening, thinking or speaking without reading anything.
 */

:root {
  --hud-cyan: #4fd6f7;
  --hud-cyan-dim: #1c6d85;
  --hud-blue: #2b8fd8;
  --hud-amber: #ffb454;
  --hud-red: #ff5f56;
  --hud-glow: rgba(79, 214, 247, 0.55);
}

.hud {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  background:
    radial-gradient(circle at 50% 45%, #0d2230 0%, #060d14 55%, #03070b 100%);
  padding: calc(var(--safe-t) + 16px) 16px calc(var(--safe-b) + 16px);
}

/* Faint schematic grid, as in the reference. Pure CSS so there's no image to load. */
.hud::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(79, 214, 247, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(79, 214, 247, 0.045) 1px, transparent 1px);
  background-size: 42px 42px;
  mask-image: radial-gradient(circle at 50% 45%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(circle at 50% 45%, #000 20%, transparent 78%);
  pointer-events: none;
}

.hud-stage {
  position: relative;
  width: min(78vw, 340px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.hud-ring { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.hud-ring circle,
.hud-ring path { fill: none; stroke-linecap: round; }

.ring-track    { stroke: rgba(79, 214, 247, 0.14); stroke-width: 1.5; }
.ring-ticks    { stroke: rgba(79, 214, 247, 0.42); stroke-width: 1.4; }
.ring-outer    { stroke: rgba(79, 214, 247, 0.30); stroke-width: 1; }
.ring-sweep    { stroke: var(--hud-cyan); stroke-width: 2.6; filter: drop-shadow(0 0 6px var(--hud-glow)); }
.ring-accent   { stroke: var(--hud-amber); stroke-width: 3; opacity: 0.9; }

/* Counter-rotating rings. Speeds differ per state via --spin. */
.spin-slow    { animation: hud-spin var(--spin, 44s) linear infinite; transform-origin: 50% 50%; }
.spin-reverse { animation: hud-spin var(--spin-r, 30s) linear infinite reverse; transform-origin: 50% 50%; }

@keyframes hud-spin { to { transform: rotate(360deg); } }

/* ---------- core ---------- */

.hud-core {
  position: relative;
  width: 46%;
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: radial-gradient(circle, rgba(79, 214, 247, 0.20) 0%, rgba(10, 30, 42, 0.85) 70%);
  border: 1px solid rgba(79, 214, 247, 0.35);
  box-shadow: 0 0 30px rgba(79, 214, 247, 0.18), inset 0 0 26px rgba(79, 214, 247, 0.12);
  transition: box-shadow .3s, border-color .3s, transform .2s;
}

.hud-label {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: clamp(13px, 3.6vw, 19px);
  letter-spacing: 0.30em;
  /* letter-spacing adds a space after the last character too, so the line is
     wider than the ink and the ink sits left of centre. A full letter-space of
     indent is the correction, not half of one: the box is shrink-to-fit and
     centred by the transform below, so the indent widens the box and shifts it
     left by half as much again. Measured across candidates — 0.30em lands the
     ink within 0.02px of the ring's centre, 0.15em leaves it 1.4px left. */
  text-indent: 0.30em;
  /* The wordmark is wider than the core circle it sits in, and neither grid
     centring nor text-align centres content that overflows its box — both fall
     back to start-alignment, which left it hanging 56px off the right-hand
     side. Positioning it against the core's centre sidesteps the question:
     translate(-50%) is measured from the element's own width, so it lands
     centred however much wider than its container it happens to be. */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  color: var(--hud-cyan);
  text-shadow: 0 0 12px var(--hud-glow);
  user-select: none;
}

.hud-status {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(79, 214, 247, 0.6);
  min-height: 1.2em;
  text-align: center;
}

/* ---------- states ----------
 * idle      — slow drift, dim
 * listening — cyan, gentle breathing, faster sweep
 * thinking  — the pulse; amber, urgent
 * speaking  — bright, steady bloom in time with speech
 * denied    — red, for a voice that didn't match
 */

.hud[data-state='listening'] .hud-core {
  border-color: rgba(79, 214, 247, 0.75);
  box-shadow: 0 0 48px rgba(79, 214, 247, 0.42), inset 0 0 34px rgba(79, 214, 247, 0.22);
  animation: hud-breathe 2.6s ease-in-out infinite;
}
.hud[data-state='listening'] .hud-ring { --spin: 18s; --spin-r: 12s; }

.hud[data-state='thinking'] .hud-core {
  border-color: rgba(255, 180, 84, 0.8);
  background: radial-gradient(circle, rgba(255, 180, 84, 0.22) 0%, rgba(38, 26, 12, 0.85) 70%);
  animation: hud-pulse 0.85s ease-in-out infinite;
}
.hud[data-state='thinking'] .hud-label { color: var(--hud-amber); text-shadow: 0 0 14px rgba(255,180,84,.6); }
.hud[data-state='thinking'] .ring-sweep { stroke: var(--hud-amber); filter: drop-shadow(0 0 8px rgba(255,180,84,.6)); }
.hud[data-state='thinking'] .hud-ring { --spin: 6s; --spin-r: 4s; }

.hud[data-state='speaking'] .hud-core {
  border-color: rgba(120, 230, 255, 0.9);
  box-shadow: 0 0 60px rgba(79, 214, 247, 0.55), inset 0 0 40px rgba(79, 214, 247, 0.3);
  animation: hud-breathe 1.1s ease-in-out infinite;
}
.hud[data-state='speaking'] .hud-ring { --spin: 26s; --spin-r: 18s; }

.hud[data-state='denied'] .hud-core {
  border-color: rgba(255, 95, 86, 0.85);
  background: radial-gradient(circle, rgba(255, 95, 86, 0.22) 0%, rgba(40, 14, 12, 0.9) 70%);
  animation: hud-shake 0.45s ease-in-out 2;
}
.hud[data-state='denied'] .hud-label { color: var(--hud-red); text-shadow: 0 0 14px rgba(255,95,86,.6); }
.hud[data-state='denied'] .ring-sweep { stroke: var(--hud-red); }

@keyframes hud-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.045); }
}
@keyframes hud-pulse {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 26px rgba(255,180,84,.30), inset 0 0 22px rgba(255,180,84,.18); }
  50%      { transform: scale(1.09); box-shadow: 0 0 62px rgba(255,180,84,.62), inset 0 0 40px rgba(255,180,84,.34); }
}
@keyframes hud-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-6px); }
  75%      { transform: translateX(6px); }
}

/* ---------- controls ---------- */

.hud-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }

.hud-btn {
  padding: 9px 16px;
  background: rgba(79, 214, 247, 0.07);
  border: 1px solid rgba(79, 214, 247, 0.3);
  color: rgba(79, 214, 247, 0.9);
  border-radius: 999px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
}
.hud-btn:active { background: rgba(79, 214, 247, 0.18); }
.hud-btn.danger { border-color: rgba(255, 95, 86, 0.4); color: rgba(255, 95, 86, 0.9); }

.hud-alert {
  position: absolute;
  top: calc(var(--safe-t) + 14px);
  left: 50%;
  transform: translateX(-50%);
  max-width: min(90vw, 420px);
  padding: 10px 16px;
  background: rgba(60, 16, 14, 0.92);
  border: 1px solid rgba(255, 95, 86, 0.5);
  border-radius: 12px;
  color: #ffd9d6;
  font-size: 13px;
  text-align: center;
}

/* Motion is the entire status language here, so reduced-motion needs a real
   alternative rather than simply switching everything off. */
@media (prefers-reduced-motion: reduce) {
  .spin-slow, .spin-reverse { animation: none; }
  .hud[data-state='listening'] .hud-core,
  .hud[data-state='speaking'] .hud-core { animation: none; }
  .hud[data-state='thinking'] .hud-core {
    animation: hud-fade 1.4s ease-in-out infinite;
  }
  @keyframes hud-fade { 0%,100% { opacity: .62; } 50% { opacity: 1; } }
}

/* ---------------- HUD panels ----------------
 * Three columns on a wide screen, stacked under the reactor on a phone. The
 * reactor stays the centre of attention at every size: the panels are glanceable
 * detail, not the point. */

/* Narrow — a phone, or a split window. The panels stack under the ring and the
   HUD scrolls, because on a 390px screen there is no "side" to put them on. */
.hud-panels {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 560px;
}

/* Wide — dock them to the edges.
   Each panel is positioned individually rather than placed in a grid that
   overlays the screen: the container's max-width used to survive into the wide
   layout, so the "right" column was pinned 1100px from the left edge and landed
   in the middle of a large display, on top of the ring.

   display:contents dissolves the wrapper so the panels position against the
   viewport, and the widths are clamped so they scale with the device instead of
   being one fixed number that is cramped on a laptop and lost on a monitor. */
@media (min-width: 980px) {
  .hud-panels { display: contents; }

  .hud-panel {
    position: fixed;
    width: clamp(230px, 20vw, 340px);
    max-height: calc(50vh - 60px);
    overflow-y: auto;
    z-index: 62;
  }

  #panel-markets   { left: 20px;  top: calc(var(--safe-t) + 74px); }
  #panel-briefing  { right: 20px; top: calc(var(--safe-t) + 74px); }
  /* Under markets on the left, so a long answer never grows into the ring. */
  #panel-transcript { left: 20px; bottom: calc(var(--safe-b) + 20px); }
}

/* Wider still: there is room to breathe, and room for bigger panels. */
@media (min-width: 1600px) {
  .hud-panel { width: clamp(300px, 18vw, 420px); }
  #panel-markets, #panel-transcript { left: 36px; }
  #panel-briefing { right: 36px; }
}



.hud-panel {
  border: 1px solid rgba(80, 200, 255, 0.18);
  border-radius: 12px;
  background: rgba(6, 14, 24, 0.55);
  padding: 10px 12px;
  backdrop-filter: blur(6px);
}

.hud-panel h3 {
  margin: 0 0 8px;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(120, 210, 255, 0.75);
  display: flex;
  align-items: center;
  gap: 6px;
}

.dot-status {
  width: 7px; height: 7px; border-radius: 50%;
  background: #3ddc84;
  box-shadow: 0 0 6px currentColor;
}
.dot-status.stale { background: #f5b642; }
.dot-status.down { background: #ff5f56; }

/* Two columns, one line each. As a flex row with both sides free to wrap, a
   long sender and a long subject each broke onto a second line and every row
   ended up a different height — the panel read as a list of paragraphs rather
   than a column of entries. A fixed first column and truncation keeps the
   right-hand edge straight; the full text is on the row's title. */
.hud-row {
  display: grid;
  grid-template-columns: minmax(0, 7.5em) minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  font-size: 13px;
  padding: 3px 0;
  color: rgba(220, 240, 255, 0.9);
}
.hud-row > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hud-row > span:last-child { text-align: right; }
.hud-row .sub { color: rgba(160, 190, 215, 0.7); font-size: 12px; }
.hud-row.imminent { color: #7fe3ff; font-weight: 600; }
.up { color: #3ddc84; }
.down { color: #ff6b6b; }

.hud-quote {
  font-size: 13px; line-height: 1.45; font-style: italic;
  color: rgba(215, 235, 255, 0.92);
}
.hud-quote cite { display: block; margin-top: 4px; font-style: normal;
  font-size: 11px; color: rgba(150, 185, 215, 0.75); }

.hud-age { font-size: 10px; color: #f5b642; margin-left: auto; }
.hud-empty { font-size: 12px; color: rgba(150, 180, 205, 0.6); }

/* ---------- one screen: the type bar and the transcript ----------
   There is no mode switch any more. Talking and typing are the same screen,
   and the reply comes back the way the question went in. */

.hud .composer {
  width: min(100%, 620px);
  flex: none;
  background: rgba(9, 16, 24, 0.72);
  border: 1px solid rgba(79, 214, 247, 0.22);
  border-radius: 999px;
  padding: 6px 6px 6px 10px;
  backdrop-filter: blur(10px);
  align-items: center;
}
.hud .composer textarea {
  background: transparent;
  border: none;
  padding: 9px 6px;
  color: var(--text);
}
.hud .composer textarea::placeholder {
  color: rgba(79, 214, 247, 0.45);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 13px;
  letter-spacing: 0.08em;
}
.hud .composer textarea:focus { border: none; outline: none; }
.hud .composer .icon-btn.mic { background: transparent; border: none; color: rgba(79, 214, 247, .8); }
.hud .composer .icon-btn.mic.active { color: var(--accent); }

/* The transcript is a panel like the others — draggable, and out of the way
   when it is not wanted. Capped in height so a long answer scrolls inside it
   rather than pushing the reactor off the screen. */
.hud-panel.transcript .panel-body { max-height: min(46vh, 420px); overflow-y: auto; }
.hud-panel.transcript .messages { padding: 0; overflow: visible; }
.hud-panel.transcript .msg { margin-bottom: 10px; }
.hud-panel.transcript .bubble { max-width: 100%; font-size: 13px; padding: 8px 11px; }

.panel-x {
  float: right;
  background: none; border: none; cursor: pointer;
  color: rgba(79, 214, 247, 0.5);
  font-size: 12px; line-height: 1; padding: 0 2px;
}
.panel-x:hover { color: rgba(79, 214, 247, 0.95); }

/* ---------- modular panels ----------
   Drag a panel by its heading and it leaves the grid and stays put. */

.hud-panel h3.drag-handle {
  cursor: grab;
  /* Without this the browser claims the gesture for scrolling on a phone and
     the panel never moves at all. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
.hud-panel h3.drag-handle:active { cursor: grabbing; }

.hud-panel.moved {
  position: fixed;
  margin: 0;
  z-index: 64;
  width: min(320px, 78vw);
}
.hud-panel.dragging {
  /* Lifted, and never animated: a transition on left/top makes the panel lag
     behind the finger, which reads as the drag being broken. */
  transition: none;
  border-color: rgba(79, 214, 247, 0.55);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  opacity: 0.96;
}

.hud-suggestions {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  max-width: min(100%, 620px);
}
.hud-suggestions .chip {
  background: rgba(79, 214, 247, 0.06);
  border: 1px solid rgba(79, 214, 247, 0.22);
  color: rgba(203, 233, 245, 0.85);
  font-size: 12.5px;
  padding: 7px 13px;
}
.hud-suggestions .chip:active { background: rgba(79, 214, 247, 0.16); }

/* A moved panel is positioned by its inline left/top. The docked rules also set
   `right` or `bottom`, and an ID selector outranks a class — so those have to be
   cleared at ID specificity or a dragged transcript stretches between its inline
   top and its docked bottom. */
#panel-markets.moved,
#panel-briefing.moved,
#panel-transcript.moved {
  right: auto;
  bottom: auto;
  max-height: min(50vh, 440px);
}

/* On a narrow screen everything stacks, which is taller than the viewport.
   Centring a flex column that overflows clips the top *and* makes it
   unscrollable, so below the docking breakpoint the HUD flows from the top. */
@media (max-width: 979px) {
  .hud {
    justify-content: flex-start;
    overflow-y: auto;
    gap: 18px;
  }
  .hud-stage { flex: none; }
}

/* Mic state, said out loud rather than implied by an icon. */
.hud-mic {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase;
  min-height: 1.2em;
}
.mic-armed { color: rgba(255, 138, 128, 0.95); animation: mic-blink 1.6s ease-in-out infinite; }
@keyframes mic-blink { 50% { opacity: .45; } }
.wake-where { color: rgba(79, 214, 247, 0.42); }
.wake-where[data-state='on'] { color: rgba(63, 208, 127, 0.85); }
.wake-where[data-state='muted'] { color: rgba(255, 180, 84, 0.8); }

@media (prefers-reduced-motion: reduce) { .mic-armed { animation: none; } }
