/* NC Zoning Academy: base + shared primitives.
 *
 * Layout and component styles. Uses native CSS nesting (like the map).
 * Colour comes from the semantic roles in theme.css, either directly
 * (var(--primary)) or as a tint/line/glow via relative colour syntax
 * (rgb(from var(--primary) r g b / 0.25)). Re-binding a role re-skins every
 * derived value. A few non-theme colours remain literal on purpose: pure-black
 * shadows and two one-off near-black wells that match no role.
 *
 * View-specific styles (dashboard, module player, radio panel, certificate)
 * live in their own files under assets/css/ and are added as views are rebuilt.
 */

/* ---- reset ---- */
*,
*::before,
*::after {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px; /* monolith base; the app shell scrolls internally */
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* post-login app shell: header + view; each view owns its scroll container */
.app-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

button,
a,
input,
label,
[role="button"] {
  touch-action: manipulation;
}

/* ---- links (invert on hover, like the shell) ---- */
a {
  color: var(--primary);
  text-decoration: none;
  border-bottom: 1px solid var(--line-strong);

  &:hover {
    color: var(--bg);
    background: var(--primary);
    border-bottom-color: var(--primary);
  }
}

/* touch devices must not keep the inverted state after a tap */
@media (hover: none) {
  a:hover {
    color: var(--primary);
    background: transparent;
    border-bottom-color: var(--line-strong);
  }
}

/* ---- form fields ---- */
input::placeholder {
  color: var(--placeholder);
}

/* ---- scrollbars ---- */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: var(--scrollbar-track);
}
::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border: 1px solid var(--line);

  &:hover {
    background: var(--scrollbar-thumb-hover);
  }
}

/* ---- global CRT overlays ---- */
#scanlines {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-scanlines);
  background: repeating-linear-gradient(
    0deg,
    var(--scanline) 0px,
    var(--scanline) 1px,
    transparent 1px,
    transparent 3px
  );
}

#vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-vignette);
  background: radial-gradient(ellipse at center, transparent 55%, var(--vignette) 100%);
}

/* ---- app-wide micro-animations ---- */
@keyframes cursorblink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
.cursor {
  display: inline-block;
  width: 9px;
  height: 1.05em;
  background: var(--primary);
  margin-left: 2px;
  vertical-align: -2px;
  animation: cursorblink 1s steps(1) infinite;
}

@keyframes ledblink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.2; }
}
.ledblink {
  animation: ledblink 1.1s steps(2, jump-none) infinite;
}

@keyframes statusblink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
.statusled {
  animation: statusblink 2s ease infinite;
}

/* radio pill EQ bars (duration/delay set inline per bar off the track bpm) */
@keyframes eqbar {
  0% { transform: scaleY(0.18); }
  100% { transform: scaleY(1); }
}

/* bouncing marquee for overflowing track names; --mqd set from measured overflow */
@keyframes mqbounce {
  0%, 14% { transform: translateX(0); }
  86%, 100% { transform: translateX(var(--mqd, 0)); }
}

/* ---- accessibility ---- */
@media (prefers-reduced-motion: reduce) {
  #scanlines { display: none; }
  .ledblink,
  .cursor { animation: none !important; }
}

/* ---- app header (shared chrome, renders on every view) ---- */
.app-header {
  /* Dense chrome in a 62px bar, not a reading surface: the ladder steps down.
     Re-binding the ROLE here means every rule below still says var(--fs-label)
     and needs no knowledge of the context it lands in. */
  --fs-heading: 20px; /* wordmark */
  --fs-ui:      14px; /* balance figure */
  --fs-label:   11px; /* nav tabs, clearance, glossary */
  --fs-micro:    9px; /* the caps above each figure */

  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  padding: 0 var(--space-5xl);
  background: rgb(from var(--bg) r g b / 0.9);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid rgb(from var(--primary) r g b / 0.2);
}
.hdr-brand { display: flex; align-items: center; gap: var(--space-2xl); flex: none; }
.hdr-logo {
  height: 40px;
  width: auto;
  display: block;
  filter: brightness(0) invert(1) drop-shadow(0 0 6px rgb(from var(--primary) r g b / 0.35));
}
.hdr-brand-title {
  font-family: var(--font-identity);
  font-weight: 400;
  font-size: var(--fs-heading);
  letter-spacing: var(--tracking-mid);
  color: var(--text);
  line-height: 1;
}
.hdr-sub {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-mid);
  color: var(--muted);
  margin-top: 3px;
  white-space: nowrap;
}

.hdr-nav { display: flex; align-items: center; gap: var(--space-xs); }
.hdr-nav-btn {
  font-family: var(--font-display);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--tracking-mid);
  padding: var(--space-sm) var(--space-xl);
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent; /* inactive tabs are borderless text */
  color: var(--muted);

  &.active {
    background: rgb(from var(--primary) r g b / 0.1);
    border-color: var(--primary);
    color: var(--primary);
  }
}

.hdr-meta { display: flex; align-items: center; gap: var(--space-3xl); flex: none; }
.hdr-clearance { text-align: right; }
.hdr-clearance-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-mid);
  color: var(--muted);
}
.hdr-clearance-val {
  font-family: var(--font-display);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--tracking-mid);
  color: var(--primary);
}

/* balance is a button (opens transaction history) */
.hdr-balance {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  background: rgb(from var(--tertiary) r g b / 0.05);
  border: 1px solid rgb(from var(--tertiary) r g b / 0.5);
  padding: var(--space-xs) var(--space-lg);
  cursor: pointer;
  transition: box-shadow 0.3s, border-color 0.3s, background 0.15s;

  &:hover {
    background: rgb(from var(--tertiary) r g b / 0.12);
    border-color: rgb(from var(--tertiary) r g b / 0.85);
  }
}
.hdr-balance-row { display: flex; align-items: center; gap: var(--space-xs); }
.hdr-balance-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-mid);
  color: var(--muted);
}
.hdr-balance-icon { display: block; flex: none; opacity: 0.85; }
.hdr-balance-val {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--fs-ui);
  letter-spacing: var(--tracking-label);
  color: var(--tertiary);

  &.negative { color: var(--danger); }
}

/* header glossary button: desktop hides it (the FAB shows instead);
   the ≤640px block in style.css swaps them */
.gloss-hdr {
  display: none;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-lg);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-mid);
  cursor: pointer;
  background: transparent;
  border: 1px solid rgb(from var(--primary) r g b / 0.55);
  color: var(--primary);

  &:hover { background: rgb(from var(--primary) r g b / 0.12); border-color: var(--primary); }
}

/* JACK OUT: ends the session and returns to the lock. Quiet chrome at rest,
   danger accent on hover: an exit, not a feature. */
.hdr-logout {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-lg);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-mid);
  cursor: pointer;
  background: transparent;
  border: 1px solid rgb(from var(--muted) r g b / 0.4);
  color: var(--muted);

  &:hover {
    background: rgb(from var(--danger) r g b / 0.08);
    border-color: var(--danger);
    color: var(--danger);
  }
}

/* ---- SYSTEM BROADCAST feed (shared: lock screen + dashboard, issue #10).
   Declarations moved verbatim from lock.css; context sizing stays with the
   caller (.lock-stack .broadcast, .dash-broadcast). ---- */
.broadcast {
  border: 1px solid rgb(from var(--primary) r g b / 0.28);
  background: rgb(from var(--bg) r g b / 0.6);
}
.broadcast-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-3xl);
  border-bottom: 1px solid rgb(from var(--primary) r g b / 0.18);
  background: rgb(from var(--primary) r g b / 0.04);
}
.broadcast-led {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--primary);
  box-shadow: 0 0 8px var(--primary);
}
.broadcast-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-caps);
  color: var(--primary);
}
.broadcast-list {
  max-height: 220px;
  overflow-y: auto;
}

.bc-msg {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-3xl);
  border-bottom: 1px solid rgb(from var(--muted) r g b / 0.12);

  &:last-child { border-bottom: 0; }
}
/* per-level accent: drives the dot and the tag colour.
 * `alert` is also pinned to the top of the panel (by level, not by date);
 * `resolved` is its green counterpart and sorts by date like the rest. */
.bc-msg { --lvl: var(--muted); }
.bc-msg.update   { --lvl: var(--primary); }
.bc-msg.alert    { --lvl: var(--secondary); }
.bc-msg.resolved { --lvl: var(--success); }
.bc-msg.info     { --lvl: var(--muted); }

.bc-msg-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  margin-top: var(--space-2xs);
  background: var(--lvl);
  box-shadow: 0 0 7px var(--lvl);
}
.bc-msg-body { min-width: 0; flex: 1; }
.bc-msg-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
  flex-wrap: wrap;
}
.bc-msg-tag {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-caps);
  color: var(--lvl);
}
.bc-msg-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-label);
  color: var(--text);
}
.bc-msg-date {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-mid);
  color: var(--placeholder);
}
.bc-msg-text {
  margin-top: var(--space-2xs);
  font-family: var(--font-body);
  font-size: var(--fs-secondary);
  line-height: 1.45;
  color: var(--muted);
}

/* Header broadcast bell (issue #10): opens the feed popover from any view.
   Amber blinking dot while an alert is live (read state does not clear an
   unresolved incident); otherwise an unread count since this page load. */
.hdr-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: var(--space-sm) var(--space-md);
  background: transparent;
  border: 1px solid rgb(from var(--muted) r g b / 0.4);
  color: var(--muted);
  cursor: pointer;

  &:hover, &.open { border-color: var(--primary); color: var(--primary); }
}
.hdr-bell-dot {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--secondary);
  box-shadow: 0 0 7px var(--secondary);
}
/* cyan on purpose: amber is the ALERT colour and belongs to the dot only */
.hdr-bell-count {
  position: absolute;
  top: -7px;
  right: -7px;
  min-width: 15px;
  padding: 1px 3px;
  border-radius: 8px;
  background: var(--primary);
  color: var(--bg);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 9px;
  line-height: 13px;
  text-align: center;
}

/* the popover: the shared .broadcast panel anchored under the header */
.broadcast-pop-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-broadcast);
  background: transparent;
}
.broadcast-pop {
  position: fixed;
  top: 70px;
  right: 22px;
  width: 430px;
  max-width: calc(100vw - 44px);
  z-index: var(--z-broadcast);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
}
.broadcast-pop-empty {
  border: 1px solid rgb(from var(--primary) r g b / 0.28);
  background: rgb(from var(--bg) r g b / 0.92);
  padding: var(--space-xl) var(--space-3xl);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-label);
  color: var(--muted);
}
/* the popover panel sits over solid page content; go opaque */
.broadcast-pop .broadcast { background: rgb(from var(--bg) r g b / 0.97); backdrop-filter: blur(6px); }

/* Shell alert strip (issue #10): renders under the header ONLY while an
   alert-level broadcast is live; visible from every view, dismissible per
   message for the current page load (an active incident returns on refresh). */
.alert-strip {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-5xl);
  background: rgb(from var(--secondary) r g b / 0.1);
  border-bottom: 1px solid rgb(from var(--secondary) r g b / 0.5);
}
.alert-strip-tag {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-caps);
  color: var(--secondary);
  flex: none;
}
.alert-strip-text {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-label);
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.alert-strip-dismiss {
  margin-left: auto;
  flex: none;
  background: transparent;
  border: none;
  color: var(--secondary);
  font-size: var(--fs-label);
  line-height: 1;
  font-weight: 700;
  cursor: pointer;
  padding: 0 var(--space-2xs);

  &:hover { color: var(--text); }
}

/* Session restore (issue #9): brief stand-in main while the course fetch
   lands on a refreshed in-app route. */
.restore-wait {
  flex: 1;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-mid);
  color: var(--muted);
}

/* ---- fixed satellites (shared chrome, render on every view) ---- */

/* Both are position:fixed and mount at App root, so they inherit from :root,
   NOT from .app-header. They need their own binding to match its chrome ladder. */
.sys-readout,
.gloss-fab {
  --fs-label: 11px;
  --fs-micro: 10px;
}

/* bottom-left telemetry readout, one line: status text, LED, offset */
.sys-readout {
  position: fixed;
  left: 18px;
  bottom: 14px;
  z-index: var(--z-sys-readout);
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-xs) var(--space-2xs);
  pointer-events: none;
  font-family: var(--font-display);
  font-size: var(--fs-micro);
  opacity: 0.9;
  transition: left 0.35s cubic-bezier(0.22, 1, 0.36, 1);

  /* the player rail occupies the left edge; the readout slides beside it */
  &.player { left: 306px; }
}
.sys-status {
  letter-spacing: 1px;
  transition: color 0.5s ease;
  display: inline-block;
  white-space: nowrap;
  flex-shrink: 0;
  color: var(--primary);
}
.sys-led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  background: var(--success);
  box-shadow: 0 0 8px var(--success);
  transition: background 0.5s ease, box-shadow 0.5s ease;
}
/* ELEVATED / CRITICAL escalation (85/10/5 telemetry roll) */
.sys-readout.elevated .sys-status { color: var(--secondary); }
.sys-readout.elevated .sys-led { background: var(--secondary); box-shadow: 0 0 8px var(--secondary); }
.sys-readout.critical .sys-status { color: var(--danger); }
.sys-readout.critical .sys-led { background: var(--danger); box-shadow: 0 0 8px var(--danger); }
.sys-offset {
  font-family: var(--font-mono);
  letter-spacing: var(--tracking-label);
  color: var(--primary);
  opacity: 0.75;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* glossary floating button (desktop) */
/* the alert strip adds a chrome row under the header; shift the fab clear
   of it (and of its dismiss ✕) while an alert is showing */
.app-shell.has-alert .gloss-fab { top: 112px; }
.gloss-fab {
  position: fixed;
  top: 76px;
  right: 22px;
  z-index: var(--z-gloss-fab);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-xl);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-mid);
  cursor: pointer;
  background: rgb(from var(--bg) r g b / 0.92);
  border: 1px solid rgb(from var(--primary) r g b / 0.55);
  color: var(--primary);
  backdrop-filter: blur(8px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);

  &:hover { background: rgb(from var(--primary) r g b / 0.14); border-color: var(--primary); }
}
.gloss-fab svg { display: block; flex: none; }


/* ---- responsive (values measured from the monolith's media blocks) ---- */
/* Tablet (≤1024px): drop the clearance cluster, tighten the dash padding */
@media (max-width: 1024px) {
  .hdr-clearance { display: none !important; }
  .dash-scroll { padding: 36px var(--space-6xl) 54px !important; }
}

/* Phone (≤640px): wrapping header, single-column grids, finger targets */
@media (max-width: 640px) {
  .app-header {
    height: auto !important;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-xl);
    padding: var(--space-md) var(--space-xl) !important;
  }
  .sys-readout { display: none !important; }
  .hdr-sub { display: none !important; }
  .hdr-clearance { display: none !important; }
  /* re-bind the role, don't !important the call site */
  .app-header { --fs-heading: 15px; }
  .hdr-brand { width: 100%; }
  .hdr-nav {
    order: 2;
    flex: 1;
    min-width: 0;
    justify-content: flex-start;
    gap: var(--space-xs);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .hdr-nav button { min-height: 40px; white-space: nowrap; }
  .hdr-meta { order: 3; margin-left: auto; gap: var(--space-md) !important; }
  /* glossary moves into the header row; the fixed floater hides */
  .gloss-fab { display: none !important; }
  .gloss-hdr { display: inline-flex !important; padding: var(--space-xs) var(--space-md) !important; min-height: 40px; }
  /* icon-only jack-out: the label doesn't fit the wrapped meta row */
  .hdr-logout { padding: var(--space-xs) var(--space-md) !important; min-height: 40px; }
  .hdr-logout-txt { display: none; }
  /* the wrapped header is taller; anchor the bell popover below it */
  .broadcast-pop { top: 118px; right: 10px; left: 10px; width: auto; }

  .dash-scroll {
    padding: var(--space-5xl) var(--space-xl) 46px !important;
    --fs-title: 25px;
    --fs-body:  14px;
  }
  .course-grid { grid-template-columns: 1fr !important; }

  button { min-height: 44px; }
  input:not([type="file"]) { min-height: 44px; }
}
