/* HUD chrome: frame, panels, corner brackets, readouts. No colour literals here -
 * every value comes from theme.css. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg-deep);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  overflow: hidden;
  /* The window is the app; nothing here is user-selectable chrome. */
  user-select: none;
}

/* ---- Texture layers -------------------------------------------------------
 * Fixed, non-interactive, and pinned to very low opacity. If either of these
 * ever becomes visible enough to notice on its own, it is too strong. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 900;
  background: repeating-linear-gradient(
    to bottom,
    var(--scanline-ink) 0px,
    var(--scanline-ink) 1px,
    transparent 1px,
    transparent 3px
  );
  opacity: var(--scanline-opacity);
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 899;
  background:
    linear-gradient(var(--line-bright) 1px, transparent 1px) 0 0 / 40px 40px,
    linear-gradient(90deg, var(--line-bright) 1px, transparent 1px) 0 0 / 40px 40px;
  opacity: var(--grid-opacity);
}

/* ---- Layout --------------------------------------------------------------- */
.hud {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  height: 100vh;
  padding: var(--gap);
  gap: var(--gap);
}

.hud__body {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--gap);
  min-height: 0;
}

.hud__column {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-height: 0;
}

/* The sidebar scrolls as one column; its panels keep their natural height.
 *
 * Without this, flex shrinks every panel to fit the window and each one shows a
 * fraction of a row - Contacts rendered the top half of a name, Daily Quests
 * showed a "0/3" badge above none of the three. Each panel body does scroll, so
 * nothing was unreachable, but a panel cropped mid-letter reads as a broken
 * render rather than as something to scroll, and this is a window whose whole
 * job is being legible at a glance from across the room.
 *
 * Found by seeding a realistic amount of data and looking at it. Five near-empty
 * panels fit fine, which is why it survived four phases of screenshots.
 */
.hud__column--side {
  overflow-y: auto;
  /* Room for the scrollbar, so the corner brackets do not sit under it. */
  padding-right: var(--gap-sm);
}

/* Descendant, not child. Plugin panels are appended into `.slot`, which is
 * `display: contents` - so they are flex *items* of this column while still
 * being DOM *children* of the slot, and `>` silently matches none of them.
 * The first version of this fix used `>`, changed nothing, and looked like the
 * flex rule was wrong rather than the selector. */
.hud__column--side .panel {
  flex: 0 0 auto;
}

/* ---- Top bar -------------------------------------------------------------- */
.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap);
  padding-bottom: var(--gap-sm);
  border-bottom: 1px solid var(--line);
}

.topbar__mark {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--amber);
}

.topbar__clock {
  font-family: var(--font-mono);
  font-size: var(--fs-data);
  color: var(--text-bright);
  font-variant-numeric: tabular-nums;
}

.topbar__meta {
  display: flex;
  gap: var(--gap-lg);
  align-items: baseline;
}

/* ---- Panels --------------------------------------------------------------- */
.panel {
  position: relative;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap-lg) var(--gap);
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* Panels slide in from slightly below; they do not scale or bounce. */
  animation: panel-enter var(--dur-slow) var(--ease-mech) both;
}

.panel--primary {
  flex: 1;
  background: var(--bg-panel-raised);
  border-color: var(--line-bright);
}

@keyframes panel-enter {
  from {
    opacity: 0;
    transform: translateY(calc(6px * var(--scale)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Corner brackets. Two pseudo-elements, each drawing two corners via borders. */
.panel::before,
.panel::after {
  content: "";
  position: absolute;
  width: var(--bracket-size);
  height: var(--bracket-size);
  pointer-events: none;
  border-color: var(--amber-dim);
  border-style: solid;
}

.panel::before {
  top: -1px;
  left: -1px;
  border-width: var(--bracket-weight) 0 0 var(--bracket-weight);
}

.panel::after {
  bottom: -1px;
  right: -1px;
  border-width: 0 var(--bracket-weight) var(--bracket-weight) 0;
}

.panel--primary::before,
.panel--primary::after {
  border-color: var(--amber);
  width: calc(var(--bracket-size) * 1.6);
  height: calc(var(--bracket-size) * 1.6);
}

.panel__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap);
  margin-bottom: var(--gap);
}

.panel__title {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0;
}

/* The rule that trails a section header, like a readout divider. */
.panel__title::after {
  content: "";
  display: inline-block;
  width: calc(28px * var(--scale));
  height: 1px;
  margin-left: var(--gap-sm);
  vertical-align: middle;
  background: var(--line-bright);
}

.panel__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* ---- Primary readout: the one next task ----------------------------------- */
.directive {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  height: 100%;
}

.directive__project {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--teal);
}

.directive__task {
  font-size: var(--fs-hero);
  line-height: 1.15;
  color: var(--text-bright);
  font-weight: 600;
  margin: 0;
  text-wrap: balance;
}

.directive__empty {
  display: flex;
  flex-direction: column;
  gap: var(--gap-sm);
  justify-content: center;
  flex: 1;
  color: var(--text-faint);
  font-family: var(--font-mono);
  /* Not --fs-body. This is the hero slot, and "nothing queued" is a state you
     want to read from the same distance as a task title - it is the answer to
     the question the whole window exists to answer. It rendered at 14px until
     the visual suite was run for the first time in phase 9. */
  font-size: var(--fs-data);
}

.directive__empty strong {
  color: var(--text-dim);
  font-weight: 500;
  font-size: var(--fs-heading);
}

/* ---- Readouts (label/value pairs) ----------------------------------------- */
.readout {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap);
  padding: var(--gap-xs) 0;
  border-bottom: 1px dotted var(--line-faint);
}

.readout:last-child {
  border-bottom: none;
}

.readout__label {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-dim);
}

/* A label that is also a button. Styled as the label it sits in line with
 * rather than as a button, because a full button here would out-shout the four
 * readouts above it - and this one is used about once a week. The underline on
 * hover is the whole affordance. */
.readout__label--action {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--teal);
}

.readout__label--action:hover:not(:disabled) {
  text-decoration: underline;
}

.readout__label--action:disabled {
  color: var(--text-dim);
  cursor: default;
}

.readout__value {
  font-family: var(--font-mono);
  font-size: var(--fs-data);
  color: var(--text-bright);
  font-variant-numeric: tabular-nums;
  text-align: right;
  overflow-wrap: anywhere;
}

.readout__value--dim {
  color: var(--text-dim);
  font-size: var(--fs-label);
}

.readout__value--accent {
  color: var(--amber);
}

/* ---- Status strip --------------------------------------------------------- */
.statusbar {
  display: flex;
  align-items: center;
  gap: var(--gap-lg);
  padding-top: var(--gap-sm);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-wide);
  color: var(--text-dim);
}

.statusbar__spacer {
  flex: 1;
}

.link-state {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-sm);
  text-transform: uppercase;
}

.link-state__dot {
  width: calc(7px * var(--scale));
  height: calc(7px * var(--scale));
  border-radius: 50%;
  background: var(--text-faint);
  transition: background var(--dur) var(--ease-mech);
}

.link-state[data-state="online"] .link-state__dot {
  background: var(--teal);
  box-shadow: 0 0 0 3px var(--teal-glow);
}

.link-state[data-state="online"] {
  color: var(--teal);
}

.link-state[data-state="offline"] .link-state__dot {
  background: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-glow);
}

.link-state[data-state="offline"] {
  color: var(--danger);
}

/* ---- Scrollbars ----------------------------------------------------------- */
.panel__body::-webkit-scrollbar,
.hud__column--side::-webkit-scrollbar {
  width: 8px;
}

.panel__body::-webkit-scrollbar-track,
.hud__column--side::-webkit-scrollbar-track {
  background: var(--bg-inset);
}

.panel__body::-webkit-scrollbar-thumb,
.hud__column--side::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: var(--radius);
}

.panel__body::-webkit-scrollbar-thumb:hover,
.hud__column--side::-webkit-scrollbar-thumb:hover {
  background: var(--line-bright);
}

/* ---- Narrow windows -------------------------------------------------------
 * Phase 3 of the web client makes this a real responsive pass. For now it has one
 * job: keep the HUD usable when the window is dragged narrow.
 *
 * The wide layout gives each panel a share of a fixed-height screen and lets it
 * scroll internally. Stacked into one column that arithmetic collapses - the
 * directive ends up a few lines tall, clipping the task title and hiding the
 * Complete button behind its own scrollbar. So below this width panels size to
 * their content and the page scrolls instead. */
@media (max-width: 860px) {
  body {
    overflow: auto;
  }

  .hud {
    height: auto;
    min-height: 100vh;
  }

  .hud__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .panel,
  .panel--primary,
  .panel--queue,
  .panel--grow {
    flex: none;
    max-height: none;
  }

  .panel__body {
    overflow: visible;
  }

  /* The page is the scroll container down here. A sidebar that keeps its own
     one puts a second scrollbar inside the first, which is how you end up
     scrolling the wrong thing with the wheel over the wrong half of a window. */
  .hud__column--side {
    overflow: visible;
    padding-right: 0;
  }

  .topbar {
    flex-wrap: wrap;
    row-gap: var(--gap-sm);
  }
}

/* ---- Phase 2 additions ----------------------------------------------------- */

/* The directive panel takes what it needs; the queue keeps a modest floor and
 * scrolls rather than pushing the primary task off screen. */
.panel--queue {
  flex: none;
  max-height: 38%;
}

.panel--grow {
  flex: 1;
}

.directive__detail {
  color: var(--text-dim);
  margin: 0;
  max-width: 60ch;
}

.directive__actions {
  display: flex;
  align-items: center;
  gap: var(--gap);
  flex-wrap: wrap;
  margin-top: var(--gap-sm);
}


/* ---- Tabs ------------------------------------------------------------------ */
.tabs {
  display: flex;
  gap: var(--gap-sm);
  border-bottom: 1px solid var(--line);
}

.tab {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-dim);
  background: none;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  padding: var(--gap-sm) var(--gap);
  margin-bottom: -1px;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-mech);
}

.tab:hover {
  color: var(--text);
}

.tab:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

/* The selected tab joins the panel below it: lit border on three sides, and the
 * bottom edge erased against the body background. */
.tab[aria-selected="true"] {
  color: var(--amber);
  background: var(--bg-panel);
  border-color: var(--line-bright);
  border-bottom: 1px solid var(--bg-panel);
}

/* Appended as a sibling node, so the gap has to be CSS - there is no text
 * whitespace between the tab label and its count. */
.tab__badge {
  color: var(--text-faint);
  letter-spacing: 0;
  margin-left: var(--gap-sm);
}

.tab__badge:empty {
  margin-left: 0;
}

.tab[aria-selected="true"] .tab__badge {
  color: var(--teal);
}

/* ---- Views ----------------------------------------------------------------- */

/* A container, so plugin tab views can be appended without landing after the
 * status bar in the page grid. */
.hud__views {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.hud__views > .view {
  flex: 1;
}

/* Sidebar slot: plugin panels stack here like any other panel. */
.slot {
  display: contents;
}

.view {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* .view sets display, which would win over the hidden attribute on its own. */
.view[hidden] {
  display: none;
}

.view > .hud__body {
  flex: 1;
}

/* ---- Alarm ----------------------------------------------------------------
 *
 * For the one class of problem where every other part of the UI looks fine and
 * is lying: a database that cannot be read reports zero of everything. Loud on
 * purpose, and above the tabs so no view can hide it.
 */
/* Same trap as `.view` above: setting `display` here beats the `hidden`
 * attribute, because any author rule wins over the browser's `[hidden]`
 * default. Without this the banner is on screen permanently, announcing a
 * problem that is not there - which is worse than not having it, because an
 * alarm nobody can silence is one nobody reads. */
.alarm[hidden] {
  display: none;
}

.alarm {
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
  margin: var(--gap-sm) var(--gap) 0;
  padding: var(--gap-sm) var(--gap);
  background: var(--danger-glow);
  border: 1px solid var(--danger-dim);
  border-left: 3px solid var(--danger);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1.5;
}

.alarm__mark {
  color: var(--danger);
  font-size: var(--fs-data);
  font-weight: 700;
  line-height: 1.2;
}

.alarm__text strong {
  display: block;
  color: var(--danger);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.alarm__text span {
  color: var(--text);
}
