/* Gamma Lab — one board, one slider. Deliberately quiet: the only thing on this page that should
   pull the eye is the bar chart and the sign of the number above it. */
:root {
  --gl-bg: #080b10;
  --gl-panel: #0f141c;
  --gl-line: #1e2632;
  --gl-line-2: #2b3644;
  --gl-ink: #f2f6fb;
  --gl-ink-2: #93a2b4;
  /* small text sits on --gl-panel at 10-12px; #5d6b7c measured below AA there */
  --gl-ink-3: #8fa0b3;
  --gl-pos: #3987e5;
  --gl-pos-glow: #7fb6ff;
  --gl-neg: #e66767;
  --gl-neg-glow: #ff9b9b;
  --gl-spot: #ffd23f;
  --gl-warn: #fab219;
  /* A frozen board is a STATE, not a warning: cool and calm, deliberately not the amber that
     means "this number may be wrong". Measured at 7.9:1 on --gl-panel. */
  --gl-frozen: #7fb6ff;
  --gl-ink-4: #64707e;   /* decorative only — never text that must be read */
  --gl-mono: ui-monospace, "SF Mono", Menlo, "Cascadia Mono", monospace;
}

body {
  margin: 0;
  background: var(--gl-bg);
  color: var(--gl-ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.gl-wrap {
  max-width: 1120px;
  margin: 0 auto;
  padding: 16px 16px 40px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.gl-top { display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap; }
.gl-sym { display: flex; gap: 8px; }
.gl-input {
  font: inherit;
  font-family: var(--gl-mono);
  text-transform: uppercase;
  width: 8rem;
  padding: 7px 10px;
  color: var(--gl-ink);
  background: var(--gl-panel);
  border: 1px solid var(--gl-line-2);
  border-radius: 7px;
}
.gl-btn {
  font: inherit;
  font-size: 13px;
  padding: 7px 14px;
  color: var(--gl-ink-2);
  background: var(--gl-panel);
  border: 1px solid var(--gl-line-2);
  border-radius: 7px;
  cursor: pointer;
}
.gl-btn:hover { color: var(--gl-ink); border-color: var(--gl-ink-3); }
.gl-input:focus-visible, .gl-btn:focus-visible, #glSlider:focus-visible {
  outline: 2px solid var(--gl-spot);
  outline-offset: 2px;
}
.gl-asof { font-size: 12px; color: var(--gl-ink-3); }

.gl-hud { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.gl-r { background: var(--gl-panel); border: 1px solid var(--gl-line); border-radius: 8px; padding: 10px 13px; }
.gl-k { font-size: 10px; letter-spacing: .13em; text-transform: uppercase; color: var(--gl-ink-3); }
.gl-v {
  font-family: var(--gl-mono);
  font-variant-numeric: tabular-nums;
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -.02em;
  margin-top: 2px;
  line-height: 1.1;
}
/*
 * The Regime value carries more words than the numeric readouts beside it, so it sets its own size
 * rather than inheriting .gl-v's. This was a style="font-size:19px" attribute inside the HUD's
 * innerHTML string; it moved here so the public surface can enforce `style-src 'self'` — a style
 * attribute in parsed markup is blocked outright without 'unsafe-inline'.
 */
.gl-v-regime { font-size: 19px; }

.gl-v.pos { color: var(--gl-pos-glow); }
.gl-v.neg { color: var(--gl-neg-glow); }
.gl-v.spot { color: var(--gl-spot); }
.gl-sub { font-size: 11px; color: var(--gl-ink-2); margin-top: 3px; }
.gl-stale { color: var(--gl-warn); font-weight: 600; }

.gl-stage {
  position: relative;
  background: var(--gl-panel);
  border: 1px solid var(--gl-line);
  border-radius: 10px;
  padding: 10px 10px 4px;
}
#glCanvas { display: block; width: 100%; height: 400px; border-radius: 6px; }
.gl-hint { position: absolute; left: 16px; top: 13px; font-size: 11.5px; color: var(--gl-ink-3); pointer-events: none; }

.gl-ctl { background: var(--gl-panel); border: 1px solid var(--gl-line); border-radius: 9px; padding: 11px 14px 13px; }
.gl-ctl-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 7px; }
.gl-val { font-family: var(--gl-mono); font-size: 14px; font-weight: 600; }
#glSlider { width: 100%; accent-color: var(--gl-spot); height: 22px; }
.gl-ticks { display: flex; justify-content: space-between; font-family: var(--gl-mono); font-size: 10px; color: var(--gl-ink-3); }

.gl-notes { font-size: 12px; color: var(--gl-warn); min-height: 1.2em; }

/* The same rows the canvas draws, for readers who are not looking at pixels. Not hidden: a
   screen reader gets the numbers, and so does anyone who prefers them. */
.gl-table { border-collapse: collapse; width: 100%; font-size: 12px; margin-top: 4px; }
.gl-table caption { text-align: left; font-size: 11px; color: var(--gl-ink-2); padding-bottom: 6px; }
.gl-table th, .gl-table td {
  text-align: right;
  padding: 3px 8px;
  border-bottom: 1px solid var(--gl-line);
  font-family: var(--gl-mono);
  font-variant-numeric: tabular-nums;
}
.gl-table th { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--gl-ink-3); font-family: inherit; }
.gl-v.warn { color: var(--gl-warn); }

/* A frozen board is CORRECT, not degraded — it must not wear the stale warning colour. It is
   marked at all so the reader never mistakes a closing picture for a live one that stopped
   moving, which looks identical on a chart. */
.gl-frozen { color: var(--gl-frozen); font-weight: 600; }

/* The table mirrors the DRAWN rows, and that count is a property of the selection: 8 strikes on
   the nearest expiry, 90 across the whole board. Letting the page grow with it moved the document
   from 1179px to 2725px as the slider travelled — so returning to a position put the reader
   somewhere else on the page, which reads as the chart having changed. The rows scroll inside
   their own box instead; the page keeps its height, and the chart stays where the eye left it. */
.gl-tablewrap {
  /* FIXED, not max-height: a box that only caps tall tables still grows from 3 rows to 12, so
     the page kept moving for every selection below the cap. A constant height is the whole
     point — the chart stays where the eye left it, whatever the slider does. */
  height: 320px;
  overflow-y: auto;
  overflow-x: auto;
  margin-top: 4px;
}
/* The rows below the fold must be reachable without a pointer, so the region is focusable and
   announced. A scroll container that only a mouse can move makes content that used to be on the
   page unreachable — a worse bug than the one being fixed. */
.gl-tablewrap:focus-visible { outline: 2px solid var(--gl-spot); outline-offset: 2px; }
.gl-tablewrap thead th {
  position: sticky;
  top: 0;
  background: var(--gl-panel);
}

/* Pan and zoom. The stage is the control surface, so it says so: grab cursor, a focus ring for
   keyboard users, and no text selection fighting the drag. */
.gl-stage { cursor: grab; touch-action: none; user-select: none; }
.gl-stage.gl-grabbing { cursor: grabbing; }
.gl-stage:focus-visible { outline: 2px solid var(--gl-spot); outline-offset: 2px; }
.gl-zoom { position: absolute; right: 12px; top: 11px; display: flex; gap: 5px; }
.gl-zb {
  font: inherit;
  font-size: 13px;
  line-height: 1;
  min-width: 26px;
  padding: 4px 6px;
  color: var(--gl-ink-2);
  background: var(--gl-bg);
  border: 1px solid var(--gl-line-2);
  border-radius: 6px;
  cursor: pointer;
}
.gl-zb:hover { color: var(--gl-ink); border-color: var(--gl-ink-3); }
.gl-zb:focus-visible { outline: 2px solid var(--gl-spot); outline-offset: 2px; }
.gl-zb-wide { min-width: auto; font-size: 11px; letter-spacing: .04em; }
/* What the window is showing — the reader should never have to guess whether they are looking
   at the whole board or a slice of it. */
.gl-range {
  position: absolute;
  left: 16px;
  /* UNDER THE HINT, not at the bottom: the canvas draws its strike labels at H-6, so a readout
     anchored to the bottom sat on top of them — "185 - 470 · 90 of 202" and "185 240 270" in the
     same pixels, both unreadable. */
  top: 31px;
  font-family: var(--gl-mono);
  font-size: 10.5px;
  color: var(--gl-ink-3);
  pointer-events: none;
}

/* What the last expiry added on its own. Without it, a slider that moves the total by 0.1% reads
   as a broken control rather than as a board whose gamma lives in two days. */
.gl-marginal { font-size: 11.5px; color: var(--gl-ink-2); margin-top: 2px; min-height: 1.2em; }
.gl-marginal.pos { color: var(--gl-pos-glow); }
.gl-marginal.neg { color: var(--gl-neg-glow); }
