/* ================================================================
   FSM Explorer · style.css
   USAFA ECE — Finite State Machine teaching demo

   Built on the design system's light theme: ../_shared/ece-tokens.css
   (GENERATED --ece-* variables) and ../_shared/ece-base.css (the shared
   header, tab strip, range sliders, scrollbars and focus ring), both loaded
   before this file. This file keeps the demo's own layout and maps its
   long-standing variable names onto the tokens. The one deliberate set of
   color literals is the traffic light's lamps (--lamp-*), which depict a
   physical object.
   ================================================================ */

/* ── Variables (mapped onto --ece-*) ────────────────────────────── */
:root {
  --bg:      var(--ece-bg);
  --bg2:     var(--ece-paper);
  --bg3:     var(--ece-bg-2);
  --glass:   var(--ece-paper);     /* cards and the control bar */
  --glass-b: var(--ece-rule);      /* their borders and dividers */
  --fg:      var(--ece-ink);
  --muted:   var(--ece-ink-3);     /* the quietest TEXT token (tokens.ts contract) */
  --acc-m:   var(--ece-brand);     /* Moore accent */
  --acc-f:   var(--ece-brand);     /* Mealy accent: one brand blue for both tabs */
  --ok:      var(--ece-ok);
  --err:     var(--ece-alert);
  --warn:    var(--ece-warn-dk);   /* warn itself is ~2.6:1 on paper: text uses warn-dk */
  --r14: var(--ece-radius-card); --r10: var(--ece-radius-card); --r8: var(--ece-radius-chip);

  /* The traffic light's lit lamps, the same hexes as TL_LIGHTS `on` in app.js:
     a real object's colors, kept on purpose. The R / G / Y legend dots wear
     them inside an ink-2 rim, which carries the 3:1 edge on paper. */
  --lamp-r: #ef5350;
  --lamp-g: #4caf50;
  --lamp-y: #ffb300;
}

/* ── Reset ──────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: var(--ece-font-sans);
  background: var(--bg);
  color: var(--fg);
  min-height: 100vh;
  font-size: 14px;
}
sub { font-size: .75em; vertical-align: baseline; position: relative; bottom: -.3em; }

/* ── App Header ─────────────────────────────────────────────────── */
/* The look (.app-header, .back-btn, .header-title, .header-subtitle) comes
   from ece-base.css; this page keeps the header pinned while it scrolls. */
.app-header { position: sticky; top: 0; z-index: 50; }
.header-subtitle { transition: opacity .15s; }   /* app.js fades it on a tab switch */

/* ── Tab Bar ────────────────────────────────────────────────────── */
/* The strip, the tabs and the brand underline on the open one come from
   ece-base.css; this keeps the demo's spacing. */
.tab-bar { gap: 2px; padding: 10px 20px 0; }
.tab-btn { padding: 9px 18px; }
.tab-icon { font-size: 16px; }

/* ── Tab Panels ─────────────────────────────────────────────────── */
.tab-panel { display: none; padding: 14px 20px 20px; }
.tab-panel.active { display: block; }

/* ── Panel Header ───────────────────────────────────────────────── */
.panel-header {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 12px;
}
/* The Badge recipe: the -lt fill carries the -dk text, a faint -dk border. */
.badge {
  font-size: 10px; font-weight: 700; letter-spacing: .14em;
  padding: 3px 10px; border-radius: 20px; white-space: nowrap;
}
.badge-moore,
.badge-mealy { background: var(--ece-brand-lt); color: var(--ece-brand-dk); border: 1px solid rgb(var(--ece-brand-dk-rgb) / 0.25); }
.panel-desc        { font-size: 13px; color: var(--ece-ink-2); }
.panel-desc strong { color: var(--fg); }

/* ── Main Grid ──────────────────────────────────────────────────── */
/* Mealy tab: stretch right column so the truth table fills all available height */
#panel-mealy .main-grid        { align-items: stretch; }
#panel-mealy .col:last-child   { height: 100%; }
/* The truth table card grows; the student logic card stays auto */
#panel-mealy .col:last-child .card:first-child {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
}
#panel-mealy .col:last-child .card:first-child .tt-tall {
  flex: 1; max-height: none; min-height: 0;
}

.main-grid {
  display: grid;
  grid-template-columns: 1fr 390px;
  gap: 14px;
  margin-bottom: 12px;
}
.col { display: flex; flex-direction: column; gap: 12px; }

/* ── Card ───────────────────────────────────────────────────────── */
.card {
  background: var(--glass);
  border: 1px solid var(--glass-b);
  border-radius: var(--r14);
  padding: 12px 14px;
}
.card-lbl {
  font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
  margin-bottom: 9px;
  display: flex; align-items: center; gap: 8px;
}
.tt-hint {
  font-size: 9px; text-transform: none; font-weight: 400;
  color: var(--muted); letter-spacing: 0;
}

/* ── FSM SVG State Diagram ──────────────────────────────────────── */
/* max-width caps the Moore viewBox (465×265) so height never exceeds ~275px on wide screens */
.fsm-svg { display: block; width: 100%; max-width: 480px; height: auto; overflow: visible; margin: 0 auto; }
/* The radar diagram carries nine arcs and multi-line labels: viewBox 500×346 */
#mealy-svg { max-width: 560px; }
.state-node { transition: stroke .3s, stroke-width .3s; }
/* app.js gives the present state an inline drop-shadow glow in the accent
   color; the light theme has no glows (the brand ring and tint mark it). */
.fsm-svg .state-node { filter: none !important; }

/* ── Traffic Light Visual ───────────────────────────────────────── */
.tl-wrap {
  display: flex; justify-content: center; align-items: center;
  padding: 10px 0 4px;
}
/* display:block + width:100% required — without them inline SVG collapses to 0 */
.tl-svg { display: block; width: 100%; max-width: 190px; height: auto; margin: 0 auto; }

/* ── Radar Canvas ───────────────────────────────────────────────── */
/* app.js paints the scope on paper; the frame is a box-shadow ring rather
   than a border so the canvas box (and the font scaling app.js derives from
   its clientWidth) stays exactly as it was. */
.radar-canvas {
  display: block; width: 100%; height: auto;
  background: var(--ece-paper); border-radius: var(--ece-radius-chip);
  box-shadow: 0 0 0 1px var(--ece-rule);
}

/* ── Sim Info ───────────────────────────────────────────────────── */
.sim-info {
  font-family: var(--ece-font-mono);
  font-size: 11px; color: var(--ece-ink-2);
  padding: 7px 2px 0; line-height: 1.75;
  white-space: pre;
}

/* ── Radar tab: status line, launch indicator, events ───────────── */
.status-row { display: flex; align-items: center; gap: 12px; padding-top: 7px; }
.status-row .sim-info { padding-top: 0; white-space: pre-wrap; min-width: 0; }   /* one line; wraps only on a phone */
#panel-mealy .ctrl-section { flex-wrap: wrap; }
#panel-mealy .pill-lbl     { white-space: nowrap; }
.launch-ind { display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0; cursor: default; }
.launch-dot {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--ece-bg-2); border: 1px solid var(--ece-ink-4);
}
/* flashLaunchIndicator(): 10 flashes, 50 ms on / 50 ms off (10 Hz), 1.0 s */
.launch-dot.strobing { animation: launch-strobe 100ms step-end 10; }
.launch-lbl { font: 700 8px/1 var(--ece-font-sans); letter-spacing: .1em; color: var(--muted); }
.sim-event {
  font-family: var(--ece-font-mono); font-size: 11px;
  min-height: 19px; line-height: 1.7; padding: 0 2px 0 44px;
  white-space: pre-line; color: var(--muted);
}
.sim-event.ev-fire { color: var(--warn); font-weight: 700; }
.sim-event.ev-deny { color: var(--err); }

/* ── Radar tab: instructor reveal ───────────────────────────────── */
#panel-mealy [hidden] { display: none !important; }
#panel-mealy .panel-header { flex-wrap: wrap; }
.reveal-box  { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.reveal-msg  { font-size: 11px; color: var(--muted); }
.reveal-msg.ok  { color: var(--warn); }
.reveal-msg.err { color: var(--err); }
.drive-box { margin-left: auto; display: flex; align-items: center; gap: 9px; }
.drive-tag {
  font: 700 8px/1 var(--ece-font-sans); letter-spacing: .1em; flex-shrink: 0;
  color: var(--ece-warn-dk); background: var(--ece-warn-lt);
  border: 1px solid rgb(var(--ece-warn-dk-rgb) / 0.25); border-radius: 10px; padding: 3px 6px;
}
/* "Transition Table" stays on one line; the long input key wraps under it */
#panel-mealy .col:last-child .card:first-child .card-lbl { flex-wrap: wrap; row-gap: 3px; }
.tt-locked {
  font-size: 12px; color: var(--muted); text-align: center;
  padding: 10px 6px; border: 1px dashed var(--glass-b); border-radius: 8px;
}
/* The 96-row table and the Test All report scroll inside the card: height 0 +
   flex-grow keeps their content from sizing the grid row (the left column does). */
#panel-mealy #f-tt-wrap { flex: 1 1 auto; height: 0; min-height: 220px; }
.tt-report {
  flex: 1 1 auto; height: 0; min-height: 220px; overflow-y: auto; margin-top: 10px;
  font: 400 11px/1.6 var(--ece-font-mono); color: var(--fg);
}
.rep-head { font-family: var(--ece-font-sans); font-size: 12px; color: var(--ece-ink-2); margin-bottom: 6px; }
.rep-head.rep-idle { color: var(--muted); }
.rep-list { padding-left: 30px; color: var(--err); white-space: pre; }
/* Shown under the list only when every disagreeing row is one that overlapping
   first-match rows explain (fOverlapRow in app.js). */
.rep-hint {
  margin-top: 10px; padding: 7px 10px;
  font: 400 12px/1.5 var(--ece-font-sans); color: var(--ece-ink-2); white-space: normal;
  background: var(--ece-brand-lt); border-left: 3px solid var(--ece-brand); border-radius: 0 6px 6px 0;
}
/* A queued one-shot (L or P waiting for the next step): a brand ring. */
.btn-pickle.pending .pickle-guard {
  border-color: var(--ece-brand);
  box-shadow: 0 0 0 2px var(--ece-brand);
}
#mealy-tt th, #mealy-tt td { padding-left: 3px; padding-right: 3px; }
/* 96 rows scroll under the sticky header: it stays opaque (the .tt th fill)
   so rows do not show through it */
#mealy-tt th { background: var(--ece-bg); }

/* ── Truth Table ────────────────────────────────────────────────── */
.tt-scroll {
  overflow-y: auto; max-height: 210px; border-radius: 8px;
}
.tt-tall { max-height: 320px; }
.tt {
  width: 100%; border-collapse: collapse;
  font-family: var(--ece-font-mono); font-size: 11px;
}
.tt th {
  background: var(--ece-bg);
  padding: 5px 5px; text-align: center;
  color: var(--muted); font-size: 10px;
  position: sticky; top: 0; z-index: 1;
  border-bottom: 1px solid var(--ece-rule);
}
.tt td {
  padding: 3px 5px; text-align: center;
  border-bottom: 1px solid var(--ece-bg-2);
  transition: background .15s;
}
.tt tr.tt-dc td     { color: var(--muted); font-style: italic; }
.tt tr.tt-sep td    {
  background: var(--ece-bg);
  color: var(--muted); font-size: 9px;
  text-align: left; padding: 2px 7px; font-style: normal;
}
/* The row being simulated: a light brand tint (ink, ink-3 and the ok / alert
   check marks all keep AA on it). */
.tt tr.tt-active td   { background: rgb(var(--ece-brand-rgb) / 0.12) !important; }
.tt tr.tt-active-m td { background: rgb(var(--ece-brand-rgb) / 0.12) !important; }
.tt tr.tt-pass        { background: rgb(var(--ece-ok-rgb) / 0.08); }
.tt tr.tt-fail        { background: rgb(var(--ece-alert-rgb) / 0.08); }
.tt tr.tt-pass td.chk { color: var(--ok); }
.tt tr.tt-fail td.chk { color: var(--err); }

/* ── SOP Term Builder ───────────────────────────────────────────── */
.sop-section  { display: flex; flex-direction: column; gap: 7px; margin-bottom: 10px; }
.sop-row      { display: flex; align-items: flex-start; gap: 8px; }
.sop-lbl      {
  font-size: 12px; font-family: var(--ece-font-mono);
  color: var(--ece-brand-dk); text-align: right; min-width: 52px;
  padding-top: 6px; white-space: nowrap; flex-shrink: 0;
}
.fire-lbl     { color: var(--err); }
.sop-builder  { flex: 1; min-width: 0; }
.sop-terms    { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-bottom: 4px; }

/* Individual AND-term block */
.sop-term {
  display: flex; align-items: center; gap: 3px;
  background: var(--ece-bg);
  border: 1px solid var(--ece-rule);
  border-radius: var(--ece-radius-card);
  padding: 4px 6px 4px 5px;
}

/* Variable chip — 3 states via data-state attr */
.sop-chip {
  height: 26px; min-width: 30px;
  padding: 0 5px;
  border-radius: 6px;
  border: 1px solid var(--ece-rule);
  background: var(--ece-paper);
  color: var(--muted);
  font: 600 11px/1 var(--ece-font-mono);
  cursor: pointer; letter-spacing: 0.02em;
  transition: background .13s, color .13s, border-color .13s;
  user-select: none;
}
.sop-chip:hover { background: var(--ece-bg-2); color: var(--ece-ink-2); }
/* Positive (included as-is) */
.sop-chip[data-state="1"] {
  background: var(--ece-brand-lt);
  border-color: var(--ece-brand);
  color: var(--ece-brand-dk);
}
.sop-chip[data-state="1"]:hover { border-color: var(--ece-brand-dk); }
/* Complement (included inverted) */
.sop-chip[data-state="2"] {
  background: var(--ece-alert-lt);
  border-color: var(--ece-alert);
  color: var(--ece-alert-dk);
}
.sop-chip[data-state="2"]:hover { border-color: var(--ece-alert-dk); }

/* × delete button on each term */
.sop-term-del {
  width: 18px; height: 18px; border-radius: 50%; border: none;
  background: var(--ece-bg-2); color: var(--muted);
  font-size: 12px; cursor: pointer; margin-left: 3px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  transition: background .13s, color .13s;
}
.sop-term-del:hover { background: var(--ece-alert-lt); color: var(--ece-alert-dk); }

/* OR (+) separator between terms */
.sop-or {
  font-size: 16px; font-weight: 700;
  color: var(--muted);
  padding: 0 1px; user-select: none;
}

/* + Add Term ghost button */
.sop-add {
  height: 26px; padding: 0 10px; border-radius: var(--ece-radius-chip);
  border: 1px dashed var(--ece-ink-4);
  background: transparent; color: var(--muted);
  font: 600 11px/1 var(--ece-font-mono);
  cursor: pointer; transition: all .15s;
}
.sop-add:hover { border-color: var(--acc-m); color: var(--ece-brand-dk); background: var(--ece-paper); }

/* Live SOP preview text */
.sop-preview {
  font: 400 10px/1.5 var(--ece-font-mono);
  color: var(--muted);
  padding: 1px 3px;
  min-height: 15px;
}


/* ── Moore Output Equations ─────────────────────────────────────── */
.moore-out-box { border-top: 1px solid var(--glass-b); margin: 6px 0 10px; padding-top: 9px; }
.out-eq-title  { font-size: 10px; color: var(--muted); margin-bottom: 5px; }
.out-eqs       { display: flex; flex-direction: column; gap: 3px; }
.out-eq {
  display: flex; align-items: center; gap: 7px;
  font: 400 11px/1 var(--ece-font-mono); color: var(--ece-ink-2);
}
.dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
  box-shadow: 0 0 0 1px var(--ece-ink-2);
}
.dot-r { background: var(--lamp-r); } .dot-g { background: var(--lamp-g); } .dot-y { background: var(--lamp-y); }

/* ── Action Row ─────────────────────────────────────────────────── */
.action-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }

/* ── Buttons ────────────────────────────────────────────────────── */
/* The design system's Button: secondary = paper + rule border (hover bg-2),
   primary = brand fill + paper text (hover brand-dk). Run / Stop wear the
   Badge recipe in ok / alert. */
.btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 7px 13px;
  border-radius: var(--r8); border: 1px solid var(--ece-rule);
  background: var(--ece-paper); color: var(--fg);
  font: 500 12px/1 var(--ece-font-sans);
  cursor: pointer; white-space: nowrap;
  transition: background-color var(--ece-dur) var(--ece-ease), border-color var(--ece-dur) var(--ece-ease), transform .1s;
  -webkit-appearance: none;
}
.btn:hover { background: var(--ece-bg-2); }
.btn:active { transform: scale(.97); }
.btn-sm     { padding: 5px 10px; font-size: 11px; }
.btn-acc-m,
.btn-acc-f  { background: var(--ece-brand); border-color: var(--ece-brand); color: var(--ece-paper); }
.btn-acc-m:hover,
.btn-acc-f:hover { background: var(--ece-brand-dk); border-color: var(--ece-brand-dk); }
.btn-run    { background: var(--ece-ok-lt); border-color: rgb(var(--ece-ok-dk-rgb) / 0.25); color: var(--ece-ok-dk); }
.btn-run:hover   { background: var(--ece-ok-lt); border-color: var(--ece-ok-dk); }
.btn-run.running { background: var(--ece-alert-lt); border-color: rgb(var(--ece-alert-dk-rgb) / 0.25); color: var(--ece-alert-dk); }
.btn-run.running:hover { border-color: var(--ece-alert-dk); }
.btn-fire   { border-color: var(--ece-alert); color: var(--ece-alert-dk); }
.btn-fire:hover  { background: var(--ece-alert-lt); }
.btn-on     { background: var(--ece-ok-lt); border-color: rgb(var(--ece-ok-dk-rgb) / 0.25); color: var(--ece-ok-dk); }

/* ── Pickle joystick button ───────────────────────────────── */
/* A guard ring around a round cap: P (pickle) is the alert-red cap, L (lock)
   the ink one. Flat, no glow; the cap still dips when pressed. */
.btn-pickle {
  background: transparent; border: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 2px 6px;
}
.pickle-guard {
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--ece-bg-2);
  border: 1.5px solid var(--ece-ink-4);
  display: flex; align-items: center; justify-content: center;
  transition: box-shadow .15s, border-color .15s;
}
.btn-pickle:hover .pickle-guard { border-color: var(--ece-ink-3); }
.pickle-cap {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--ece-alert);
  border: 1px solid var(--ece-alert-dk);
  transition: transform .1s;
}
.btn-pickle:active .pickle-cap { transform: scale(.87); }
.pickle-lbl {
  font: 700 8px/1 var(--ece-font-sans);
  letter-spacing: .1em; color: var(--ece-alert);
  text-transform: uppercase;
}

/* Lock button — the ink "pickle" variant */
.btn-pickle-lock .pickle-cap {
  background: var(--ece-ink-2);
  border-color: var(--ece-ink);
}
.btn-pickle-lock .pickle-lbl { color: var(--muted); }

/* ── Control Bar ────────────────────────────────────────────────── */
.ctrl-bar {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  padding: 10px 14px;
  background: var(--glass); border: 1px solid var(--glass-b); border-radius: var(--r14);
}
.ctrl-section   { display: flex; align-items: center; gap: 9px; }
.ctrl-lbl       { font-size: 10px; color: var(--muted); font-weight: 600; white-space: nowrap; text-transform: uppercase; letter-spacing: .08em; }
.ml-auto        { margin-left: auto; }
.ctrl-div {
  width: 1px; align-self: stretch;
  background: var(--glass-b); margin: 0 4px;
}
.pill-lbl       { display: flex; align-items: center; gap: 5px; font-size: 12px; cursor: pointer; }
.pill-lbl input[type="checkbox"] { accent-color: var(--acc-m); width: 14px; height: 14px; cursor: pointer; }
.pill-lbl input[type="radio"]    { accent-color: var(--acc-m); }
.speed-val      { font: 400 11px var(--ece-font-mono); color: var(--muted); min-width: 32px; }
/* Track and thumb come from ece-base.css; the demo keeps its narrow slider. */
input[type="range"] { width: 100px; }

/* ── Keyframe animations ────────────────────────────────────────── */
@keyframes shake {
  0%,100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}
@keyframes launch-strobe {
  0%  { background: var(--ece-alert); border-color: var(--ece-alert-dk); }
  50% { background: var(--ece-bg-2); border-color: var(--ece-ink-4); }
}

/* ── Radar tab on a phone: a legibility floor for the diagram text ── */
/* The 500-unit viewBox shrinks to ~330 px at a 400 px viewport, which would
   put the 9-unit arc labels near 6 px; these sizes keep them at ~8.5 px.
   `.arc-lbl` is an arc label's group (its text inherits the size; app.js
   measures the overbars from the rendered glyphs, so they follow it);
   `g[data-sid] text` is the three lines in each bubble. */
@media (max-width: 520px) {
  #mealy-svg .arc-lbl                        { font-size: 13px; }
  #mealy-svg g[data-sid] text:nth-of-type(1) { font-size: 13px; }
  #mealy-svg g[data-sid] text:nth-of-type(2),
  #mealy-svg g[data-sid] text:nth-of-type(3) { font-size: 11px; }
}

/* ── Responsive ─────────────────────────────────────────────────── */
@media (max-width: 920px) {
  .main-grid { grid-template-columns: 1fr; }
  .tt-scroll { max-height: 180px; }
  .tt-tall   { max-height: 220px; }
  .ctrl-bar  { flex-direction: column; align-items: flex-start; }
  .ml-auto   { margin-left: 0; }
}
