/* Observatory unification layer.
   Loads after 90-observatory.css and re-homes the observatory inside
   CuperOS: teal dotted desktop, window chrome, indigo title bar, taskbar,
   Pixelify display type, and the portfolio status-light palette. The
   observatory's evidence grammar (shape-coded glyphs, hairline rules,
   direct labels) is deliberately preserved; only its brand surface moves.

   Per DESIGN.md: this page is a child window of CuperOS, not a second
   brand. The No New Brand Rule is enforced here. */

/* ------------------------------------------------------------------ */
/* Token remap: the --obs-* palette now resolves to CuperOS tokens.     */
/* Evidence classes keep distinct hues, but every hue is a CuperOS one:  */
/*   OBSERVED -> indigo, MODELED -> deep cyan, ASSUMED -> deep gold,     */
/*   UNMEASURED/failure -> red. Shape and label stay the primary        */
/*   carriers, so this remap cannot change any meaning.                 */
/* ------------------------------------------------------------------ */

:root {
  /* Pixelify carries everything here too, matching the portfolio and the
     index. --font-reading stays as the one-line seam to soften long prose
     back to Plex Sans if that ever becomes the call. */
  --font-reading: "Pixelify Sans", "VT323", monospace;
  --font-value: "VT323", "Pixelify Sans", monospace;
  --font-identity: "Pixelify Sans", "VT323", monospace;
  --obs-paper: var(--window-body);
  --obs-paper-raised: var(--pane-bright);
  --obs-paper-deep: var(--chrome-well);
  --obs-ink: var(--text-dark);
  --obs-ink-soft: var(--text-soft);
  --obs-rule: var(--chrome-border);
  --obs-rule-soft: oklch(0.40 0.005 250 / 0.28);
  --obs-grid: oklch(0.40 0.15 260 / 0.05);
  --obs-teal: var(--accent-cyan-deep);
  --obs-teal-dark: oklch(0.34 0.10 195);
  --obs-orange: oklch(0.52 0.12 88);
  --obs-cobalt: var(--title-bar);
  --obs-red: oklch(0.50 0.19 28);
  --obs-focus: var(--accent-gold);
  --obs-event-compute: var(--accent-cyan-deep);
  --obs-event-collective: var(--title-bar);
  --obs-event-checkpoint: var(--link-hover);
  --obs-event-failure: oklch(0.50 0.19 28);
  --obs-event-recovery: oklch(0.52 0.12 88);
  --obs-event-power: oklch(0.45 0.09 88);
}

/* ------------------------------------------------------------------ */
/* Desktop surface: the paper page becomes a window on the teal desktop */
/* ------------------------------------------------------------------ */

body {
  background-color: var(--desktop-bg);
  background-image: radial-gradient(circle, var(--desktop-dot) 1px, transparent 1px);
  background-size: 4px 4px;
  padding-bottom: 62px;
}

/* The full-viewport paper grid belonged to the standalone brand. */
body::before {
  display: none;
}

.obs-desktop {
  width: min(100% - 20px, 1400px);
  margin: 0 auto;
  padding-top: 14px;
}

.desktop-logo {
  display: grid;
  justify-items: end;
  gap: 2px;
  margin: 0 4px 10px 0;
}

.logo-text {
  color: var(--text-light);
  font: 700 26px/1 var(--font-display);
  text-shadow: 2px 2px 0 var(--pixel-ink);
}

.logo-version {
  color: var(--gold-soft);
  font: 600 11px/1 var(--font-display);
  text-shadow: 1px 1px 0 var(--pixel-ink);
}

/* ------------------------------------------------------------------ */
/* Window chrome (mirrors the index shell)                              */
/* ------------------------------------------------------------------ */

.obs-app-window {
  background: var(--window-chrome);
  border: 2px outset var(--button-face);
  box-shadow: var(--shadow);
  max-width: 100%;
  min-width: 0;
  margin-bottom: 26px;
}

.title-bar {
  background: linear-gradient(90deg, var(--title-bar), var(--title-bar-end));
  color: var(--text-light);
  padding: 5px 7px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  user-select: none;
  border-bottom: 2px solid var(--inset-dark);
  min-width: 0;
}

.title-text {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font: 700 14px var(--font-display);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.window-controls {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
}

.window-btn {
  width: 22px;
  height: 22px;
  display: inline-grid;
  place-items: center;
  border: 2px outset var(--button-face);
  border-radius: 0;
  background: var(--button-face);
  color: var(--text-dark);
  padding: 0;
  font: 700 12px var(--font-display);
}

.obs-window-content {
  background: var(--obs-paper);
  border: 2px inset var(--window-chrome);
  margin: 4px;
  max-width: calc(100% - 8px);
  min-width: 0;
}

/* Main already draws its own hairline side rules; the window supplies the
   outer boundary now. */
main {
  border-right: 0;
  border-left: 0;
}

/* ------------------------------------------------------------------ */
/* Header: paper toolbar inside the window                              */
/* ------------------------------------------------------------------ */

.obs-header {
  background: var(--obs-paper-raised);
  border-bottom: 2px solid var(--inset-dark);
}

.obs-wordmark {
  color: var(--title-bar);
  font-weight: 700;
}

.obs-nav a.is-current::after {
  background: var(--title-bar);
}

.obs-nav a:hover,
.share-state:hover {
  color: var(--title-bar);
}

/* ------------------------------------------------------------------ */
/* Display typography: Pixelify carries titles, Plex carries reading    */
/* ------------------------------------------------------------------ */

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  letter-spacing: 0;
  font-weight: 700;
}

/* Long research questions stay readable: cap the pixel face size. */
h1 {
  line-height: 1.12;
}

/* ------------------------------------------------------------------ */
/* Portfolio type rule: Pixelify carries every label, control, and      */
/* nav item. Plex Sans stays only on multi-sentence reading             */
/* paragraphs; mono stays only on values, intervals, identifiers,       */
/* and tables.                                                          */
/* ------------------------------------------------------------------ */

.obs-nav a {
  font: 600 0.95rem var(--font-display);
}

.experiment-picker select {
  font: 600 0.9rem var(--font-display);
}

.share-state {
  font: 600 0.9rem var(--font-display);
}

.control-label {
  font: 700 0.8rem/1.2 var(--font-display);
  letter-spacing: 0.04em;
}

.experiment-kicker,
.stage-boundary,
.equal-work-eyebrow {
  font-family: var(--font-display);
}

.obs-product {
  font: 600 0.85rem var(--font-display);
}

.obs-footer,
.obs-footer span {
  font-family: var(--font-display);
  font-size: 0.85rem;
}

.site-button .site-name,
.site-name {
  font-family: var(--font-display);
  font-weight: 700;
}

/* Multi-sentence verdicts and translations follow the reading rule. */
.plain-answer {
  font-family: var(--font-reading);
}

.obs-window-content p.plain-words.has-text {
  font-family: var(--font-reading);
}

/* ------------------------------------------------------------------ */
/* Pixel sweep: 90-observatory used mono as its label-and-heading font. */
/* Every heading, label, kicker, note, summary, and control flips to    */
/* the pixel face (family only; sizes and weights stay). Mono remains   */
/* on values, intervals, identifiers, tables, stamps, and small SVG     */
/* plot annotations where pixel would be illegible.                     */
/* ------------------------------------------------------------------ */

.causal-reading h2,
.evidence-key h3,
.section-line-heading h2,
.section-line-heading h3,
.section-line-heading > span,
.inspector-header h2,
.inspector-section h3,
.source-observations h3,
.residual-panel h3,
.decision-ledger h3,
.equal-work-section-header h3,
.equal-work-clue h3,
.equal-work-boundary h3,
.equal-work-policy-card h4,
.equal-work-effect-card h4,
.equal-work-bridge-columns h4,
.checkpoint-power-section-header h3,
.checkpoint-power-redirect h3,
.checkpoint-power-boundary h3,
.checkpoint-power-logger h4,
.checkpoint-power-control-card h4,
.checkpoint-power-contrast-card h4,
.checkpoint-energy-section-header h3,
.checkpoint-energy-boundary h3,
.checkpoint-energy-effect-card h4,
.checkpoint-energy-exploratory-grid h4,
.checkpoint-energy-gate-groups h4,
.learning-policy-card h3,
.learning-figure h3,
.learning-gates h3,
.learning-boundary h3,
.recovery-measure-heading h3,
.recovery-learning-boundary h3,
.recovery-measure-heading span,
.transfer-boundary h4,
.resolve-list h4,
.semantic-consistency-evidence-grid h4,
.rack-dephasing-section-header h3,
.rack-dephasing-boundary h3 {
  font-family: var(--font-display);
}

.skip-link,
.causal-reading > ol li > span,
.resolve-list li > span,
.causal-reading > ol p,
.causal-svg .node-title,
.structured-fallback summary,
.causal-fallback-button,
.equal-work-plain-kicker,
.checkpoint-power-plain-label,
.checkpoint-energy-plain-label,
.equal-work-metric dt,
.equal-work-metric small,
.checkpoint-power-arm-metrics dt,
.learning-primary-metric dt,
.learning-primary-metric small,
.learning-supporting-metrics dt,
.semantic-consistency-evidence-grid dt,
.equal-work-gate-label,
.checkpoint-energy-gate-label,
.learning-gate-label,
.equal-work-trace summary,
.checkpoint-power-trace summary,
.checkpoint-energy-trace summary,
.learning-trace summary,
.rack-dephasing-trace summary,
.raw-trace summary,
.checkpoint-power-run-selector label,
.checkpoint-energy-run-selector label,
.rack-dephasing-controls label,
.timeline-controls > label,
.timeline-control-row button,
.event-legend,
.evidence-key li,
.recovery-measure-label,
.recovery-stack-legend,
.recovery-completion-note,
.comparison-boundary,
.empty-residual-message strong,
.checkpoint-power-boundary-badge,
.checkpoint-power-inadmissible,
.checkpoint-power-insight > div:last-child strong,
.checkpoint-energy-insight > div:last-child strong,
.semantic-consistency-insight > div:last-child strong,
.rack-dephasing-insight > div:last-child strong,
.checkpoint-energy-boundary p + p,
.rack-dephasing-boundary p + p,
.semantic-mode-label,
.learning-paired-summary,
.checkpoint-power-eyebrow,
.checkpoint-energy-eyebrow,
.learning-eyebrow,
.rack-dephasing-eyebrow,
.event-legend li,
.equal-work-bridge-class,
.checkpoint-power-invalidator div,
.checkpoint-power-invalidator strong,
.checkpoint-power-contrast-warning,
.checkpoint-power-contrast-warning strong,
.checkpoint-power-trace-warning,
.checkpoint-energy-effect-meaning,
details p[role="status"] {
  font-family: var(--font-display);
}

/* ------------------------------------------------------------------ */
/* Legibility floor: pixel faces break down under ~11px. The densest    */
/* instrument details ran 9 to 10.5px; raise them to the floor. VT323   */
/* is narrow, so these bumps do not threaten the layouts.               */
/* ------------------------------------------------------------------ */

.equal-work-eyebrow,
.checkpoint-power-eyebrow,
.checkpoint-energy-eyebrow,
.learning-eyebrow,
.rack-dephasing-eyebrow {
  font-size: 0.78rem;
}

.checkpoint-power-plain-label,
.checkpoint-energy-plain-label {
  font-size: 0.74rem;
}

.equal-work-effect-status,
.checkpoint-energy-gate-state,
.equal-work-gate-state,
.learning-gate-state {
  font-size: 0.7rem;
}

.equal-work-effect-interval,
.equal-work-effect-bound {
  font-size: 0.72rem;
}

.equal-work-trace-table,
.checkpoint-energy-trace-table,
.checkpoint-power-trace-table,
.learning-trace-table,
.policy-comparison,
.source-observations table,
.decision-ledger table,
.recovery-stack-legend span,
.checkpoint-energy-run-selector select,
.checkpoint-power-run-selector select,
.rack-dephasing-controls select {
  font-size: 0.72rem;
}

.checkpoint-power-run-selector label,
.checkpoint-energy-run-selector label,
.rack-dephasing-controls label,
.timeline-controls > label {
  font-size: 0.72rem;
}

.timeline-svg .axis-text,
.timeline-svg .policy-label,
.timeline-svg .event-label,
.timeline-svg .empty-label,
.timeline-svg text,
.recovery-timeline-svg text,
.semantic-ranking-tick,
.semantic-ranking-label,
.semantic-mode-label,
.semantic-mode-event,
.recovery-tick,
.recovery-event-id,
.residual-axis-labels,
.residual-axis-labels text,
.rack-dephasing-axis-label,
.rack-dephasing-direct-label,
.rack-dephasing-rail-label,
.rack-dephasing-event-label {
  font-size: 11px;
}

.equal-work-section-header > span,
.checkpoint-power-section-header > span,
.checkpoint-energy-section-header > span,
.rack-dephasing-section-header > span,
.semantic-consistency-evidence-grid dt,
.evidence-key li b,
.evidence-key li span,
.wan-link-button span,
.wan-link-button small,
.site-outage-chip,
.checkpoint-energy-raw-panel p,
.checkpoint-power-raw-panel p {
  font-size: 0.7rem;
}

.equal-work-trace pre,
.checkpoint-energy-trace pre,
.checkpoint-power-trace pre,
.learning-trace pre,
.raw-trace pre {
  font-size: 0.72rem;
}

/* Unstyled <small> shrinks to ~0.83em of already-small parents; pin it
   to the floor. Classed small rules above still win. */
main small {
  font-size: 0.7rem;
}

/* Hard legibility floor for chart text. The !important is deliberate:
   90-observatory sets dozens of 0.56 to 0.6rem tick and annotation sizes
   behind high-specificity scoped selectors, and pixel faces are simply
   unreadable down there. Nothing in a chart may render below 11px. */
main svg text {
  font-size: 11px !important;
}

/* ------------------------------------------------------------------ */
/* Controls: OS buttons, not outline pills                              */
/* ------------------------------------------------------------------ */

button,
select {
  border: 2px outset var(--button-face);
  border-radius: 0;
  background: var(--button-face);
}

button:active {
  border-style: inset;
}

.depth-control button {
  font: 600 13px var(--font-display);
  color: var(--text-dark);
}

.depth-control button[aria-pressed="true"] {
  border-style: inset;
  border-color: var(--button-face);
  background: var(--title-bar);
  color: var(--text-light);
}

/* Header controls sit flush in the toolbar strip. */
.experiment-picker select,
.share-state,
.icon-button {
  border: 0;
  background: transparent;
}

.share-state:hover {
  background: var(--obs-paper-deep);
}

button:focus-visible,
select:focus-visible,
input:focus-visible,
a:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent-gold);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ */
/* Freshman translation companions                                      */
/* The artifact verdict stays verbatim above; this box restates it in   */
/* plain words at freshman depth only. Marked visually as commentary,   */
/* never as data: gold well, labeled, no evidence tag.                  */
/* ------------------------------------------------------------------ */

.plain-words {
  display: none;
  margin: 10px 0 0;
  padding: 10px 12px;
  border: 2px inset var(--window-chrome);
  background: var(--gold-wash);
  color: var(--text-dark);
  font: 500 15px/1.55 var(--font-body);
  max-width: 70ch;
}

body[data-depth="freshman"] .plain-words.has-text {
  display: block;
}

/* Dark insight cards set light text on their paragraphs with selectors like
   .semantic-consistency-insight > div:last-child p (0,2,2). The translation
   box is always gold, so its ink must always be dark regardless of the card
   it sits in; three classes plus the element outrank every card rule. */
.obs-window-content p.plain-words.has-text {
  color: var(--text-dark);
  font-size: 15px;
  line-height: 1.55;
}

.plain-words.has-text::before {
  content: "In plain words";
  display: block;
  margin-bottom: 4px;
  font: 700 11px/1.2 var(--font-display);
  text-transform: uppercase;
  color: oklch(0.45 0.09 88);
}

/* ------------------------------------------------------------------ */
/* Taskbar labels                                                       */
/* ------------------------------------------------------------------ */

.taskbar .task-button {
  text-decoration: none;
}

.taskbar .task-button.is-active {
  border-style: inset;
  background: var(--chrome-well);
}

/* ------------------------------------------------------------------ */
/* Scenario band micro-motion                                           */
/* The curtailment event and WAN traffic become something you watch.    */
/* Meaning never depends on the motion: the outage chip and evidence    */
/* tags carry it statically.                                            */
/* ------------------------------------------------------------------ */

.site-outage-chip {
  justify-self: start;
  margin-top: 4px;
  padding: 2px 6px;
  border: 2px dashed oklch(0.52 0.12 88);
  color: oklch(0.45 0.09 88);
  font: 700 11px/1.2 var(--font-value);
  text-transform: uppercase;
}

/* The assumed interruption: the site periodically drops dark for a
   slice of the loop, matching the scenario's outage-then-recovery shape. */
@keyframes site-curtail {
  0%,
  58%,
  92%,
  100% {
    filter: none;
    opacity: 1;
  }
  64%,
  84% {
    filter: grayscale(0.9);
    opacity: 0.45;
  }
}

.site-button.has-assumed-outage {
  animation: site-curtail 7200ms linear infinite;
}

/* WAN traffic: a gold packet sweeps along the link. Paint-only
   background-position animation on a 14px strip. */
.wan-packet {
  position: absolute;
  right: 6px;
  bottom: 6px;
  left: 6px;
  height: 6px;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    transparent 0%,
    transparent 42%,
    var(--accent-gold) 46%,
    var(--accent-gold) 54%,
    transparent 58%,
    transparent 100%
  );
  background-size: 220% 100%;
  background-position: 120% 0;
  animation: wan-packet-sweep 2600ms linear infinite;
}

.wan-link-button {
  position: relative;
}

@keyframes wan-packet-sweep {
  from {
    background-position: 120% 0;
  }
  to {
    background-position: -20% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-button.has-assumed-outage,
  .wan-packet {
    animation: none;
  }

  .wan-packet {
    background-position: 50% 0;
  }
}

/* ------------------------------------------------------------------ */
/* Small screens: the desktop margin collapses, the window fills        */
/* ------------------------------------------------------------------ */

@media (max-width: 620px) {
  .obs-desktop {
    width: min(100% - 10px, 1400px);
    padding-top: 8px;
  }

  .desktop-logo {
    justify-items: start;
    margin: 0 0 8px 2px;
  }

  .obs-window-content {
    margin: 3px;
    max-width: calc(100% - 6px);
  }

  .taskbar .task-button {
    max-width: min(34vw, 200px);
  }
}
