/* The twin page: the plant on the left (about two thirds), the maqia Stratum chat on the right. maqia's operations
   console over the plant: flat and square, hairline edges, maqia's ink, graphite and canvas, and volt as the one
   accent (maqia's own work, the control that is on, the keyboard's focus). Status colours only mark: a square or a
   rule, never a box. Only what the room needs is on it. One typeface: IBM Plex Sans (served here, as in maqia Stratum),
   with tabular figures where a number ticks (the clock, the counts). Readable from the back of a meeting
   room. maqia keeps its lowercase m: nothing that can say "maqia" is set in capitals. */
@font-face { font-family: 'Inter'; font-weight: 400; font-display: swap; src: url('/fonts/Inter-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 600; font-display: swap; src: url('/fonts/Inter-SemiBold.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 400; font-display: swap; src: url('/fonts/ibm-plex-sans/IBMPlexSans-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 500; font-display: swap; src: url('/fonts/ibm-plex-sans/IBMPlexSans-500.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 600; font-display: swap; src: url('/fonts/ibm-plex-sans/IBMPlexSans-600.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 700; font-display: swap; src: url('/fonts/ibm-plex-sans/IBMPlexSans-700.woff2') format('woff2'); }

:root {
  --bg: #0f0f10;
  --bar: #111112f2;
  --panel: #18181af2;
  --solid: #18181afa;
  --hover: #ffffff0d;
  /* maqia's graphite for every edge, a softer one inside lists. */
  --line: #3a3a3a;
  --line-soft: #2a2a2c;
  /* maqia's canvas, a dimmer canvas for running text, and a warm grey. */
  --text: #f5f4f1;
  --text-2: #c9c7c1;
  --muted: #8e8c86;
  --run: #3dcc91;
  --warn: #ec9a3c;
  --down: #e5484d;
  --maint: #f2b33d;
  --idle: #6b6a66;
  /* maqia's volt: its badge, its toasts, the morning summary, the control that is on, the keyboard's focus. */
  --maqia: #bfff00;
  --maqia-wash: #bfff0012;
  font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
  font-size: 13px;
  -webkit-font-smoothing: antialiased;
  color: var(--text);
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
html, body { margin: 0; height: 100%; background: var(--bg); overflow: hidden; }
* { scrollbar-width: inherit; scrollbar-color: inherit; }

/* Controls: square and hairline. The states sit in :where() so a class of its own (a card's head, the summary's
   head, a close button) overrides them. */
button, select, input { font: inherit; font-size: 12px; color: var(--text); background: transparent; border: 1px solid var(--line); border-radius: 0; padding: 6px 11px; }
button { cursor: pointer; font-weight: 600; color: var(--text-2); }
button:where(:hover) { background: var(--hover); border-color: #5a5a5a; color: var(--text); }
button:where([aria-pressed='true'], [aria-expanded='true']) { color: var(--maqia); border-color: var(--maqia); background: var(--maqia-wash); }
button:where(:disabled) { opacity: .45; cursor: default; }
select, input { background: var(--bg); padding: 6px 9px; }
select option { background: var(--bg); }
input::placeholder { color: var(--muted); }
:focus-visible { outline: 1px solid var(--maqia); outline-offset: 1px; }
a { color: var(--maqia); }
.muted { color: var(--muted); }
/* maqia's name keeps its lowercase m under an upper-case style. */
.maqia-name, .panel h3.maqia-here { text-transform: none; }

#layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(340px, 1fr); height: 100vh; }
#layout.no-chat { grid-template-columns: minmax(0, 1fr) 0; }
#layout.no-chat #chat { display: none; }
/* Inside maqia Stratum: Stratum is the chat and shows the alerts, so the plant takes the whole frame. */
#layout.embed { grid-template-columns: minmax(0, 1fr); }
#layout.embed #chat, #layout.embed #chat-toggle, #layout.embed .toasts { display: none; }
/* Stratum's panel header carries the demo's clock and maqia at work; the twin's own would repeat them or disagree. */
#layout.embed #maqia-badge, #layout.embed #clock, #layout.embed #speed { display: none !important; }
/* Stratum's header already carries maqia's wordmark, and the frame is about half a screen: the bar keeps to the plant. */
#layout.embed .brand .wordmark { display: none; }
#layout.embed .brand .site { padding-left: 0; border-left: 0; }
#layout.embed .stat { padding: 0 12px; }

#twin { position: relative; overflow: hidden; min-width: 0; }
#stage { position: absolute; inset: 0; }
#stage canvas { display: block; }
/* The label layer is a stacking context of its own at level 0: the z-indices the label renderer sets on
   every label each frame stay inside it, and the overlays paint above it wherever they sit in the page. */
.labels { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
#topbar, .notice, .toasts, .panel, .drawer, .summary { z-index: 1; }

/* The top bar, three strips split by hairlines: the plant, the clock, the pace and the buttons; the scores and what
   maqia does; the open problems. maqia's badge comes and goes in the second strip, so the first keeps
   its height. On a narrow screen each strip wraps, the buttons as one group, and the overlays below start under its
   last row (--bar-h, measured by the top bar). */
#topbar { position: absolute; left: 0; right: 0; top: 0; display: flex; flex-wrap: wrap; align-items: stretch; padding: 0 14px;
  background: var(--bar); border-bottom: 1px solid var(--line); font-size: 12px; }
.actions { order: 5; display: flex; margin-left: auto; }
.brand { order: 1; display: flex; align-items: center; gap: 12px; min-height: 40px; padding-right: 14px; white-space: nowrap; }
/* The wordmark is ink on transparent: inverted, it reads as canvas. */
.brand .wordmark { display: block; height: 15px; filter: invert(1) brightness(1.15); }
.brand .site { padding-left: 12px; border-left: 1px solid var(--line); font-weight: 600; font-size: 13px; line-height: 16px; }
.clock { order: 2; display: flex; align-items: center; padding: 0 14px; border-left: 1px solid var(--line); font-size: 13px;
  font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.badge { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 0 14px; border-left: 1px solid var(--line);
  white-space: nowrap; font-size: 12px; color: var(--text-2); }
.badge::before { content: ''; flex: none; width: 7px; height: 7px; background: var(--idle); }
#speed { order: 3; }
.badge[data-mode='playing']::before { background: var(--run); }
.badge[data-mode='skipping']::before { background: var(--text); }
.badge[data-mode='paused']::before { background: var(--warn); }
/* maqia's badge takes the room left beside the scores and ends a long label in an ellipsis. */
#maqia-badge { order: 21; flex: 1 1 200px; min-height: 52px; box-sizing: border-box; border-left: 0; color: var(--text); }
#maqia-badge[hidden] { display: none; }
#maqia-badge:has(~ .score[hidden]) { padding-left: 0; }
#maqia-badge .what { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#maqia-badge a { flex: none; font-weight: 600; text-decoration: none; }
#maqia-badge a:hover { text-decoration: underline; }
.badge[data-mode='working']::before { background: var(--maqia); animation: maqia-blink 1.2s steps(1, end) infinite; }
.badge[data-mode='done']::before { background: var(--maqia); }
.badge[data-mode='failed']::before { background: var(--down); }
.badge[data-mode='off'] { color: var(--muted); }
@keyframes maqia-blink { 50% { opacity: .2; } }
/* The buttons are the first strip's full height, split by hairlines; the one that is on is volt, underlined. */
#topbar button { min-height: 40px; padding: 0 13px; border: 0; border-left: 1px solid var(--line); background: none; }
#topbar button:last-child { border-right: 1px solid var(--line); }
#topbar button:hover { background: var(--hover); }
#topbar button:is([aria-pressed='true'], [aria-expanded='true']) { background: var(--maqia-wash); box-shadow: inset 0 -2px var(--maqia); }
#topbar button:focus-visible { outline-offset: -2px; }
.bar-rule { order: 10; flex: 0 0 calc(100% + 28px); height: 1px; margin: 0 -14px; background: var(--line); }
.bar-rule.soft { order: 25; background: var(--line-soft); }

/* The scoreboard: five cells of the session, a label over its value, the profit green or red by its sign. */
.score { order: 20; display: flex; flex-wrap: wrap; }
.score[hidden] { display: none; }
.stat { display: flex; flex-direction: column; justify-content: center; gap: 2px; min-height: 52px; padding: 0 18px;
  border-right: 1px solid var(--line); white-space: nowrap; }
.stat:first-child { padding-left: 0; }
.stat .label { font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.stat .value { font-size: 18px; font-weight: 400; letter-spacing: -.01em; line-height: 1.2; }
.stat.good .value { color: var(--run); }
.stat.bad .value { color: var(--down); }

/* The open problems by type: a square red when one of them is high, amber otherwise, and the count. */
.problems { order: 30; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; min-height: 34px; box-sizing: border-box;
  padding: 6px 0; }
.problems:empty::before { content: 'No open problems'; color: var(--muted); }
.chip { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; white-space: nowrap; color: var(--text-2); }
.chip::before { content: ''; width: 7px; height: 7px; background: var(--warn); }
.chip.high::before { background: var(--down); }
.chip b { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text); }

.notice { position: absolute; left: 50%; top: calc(var(--bar-h, 48px) + 10px); transform: translateX(-50%); background: var(--solid);
  border: 1px solid var(--line); border-left: 2px solid var(--down); padding: 9px 14px; font-size: 13px; }

/* Toasts: the newest at the bottom left, a rule in their tone, the factory time in the corner; a long title or reason
   ends after two lines (the whole of it stays in the toast's text, and the decision's card has it). */
.toasts { position: absolute; left: 14px; bottom: 14px; width: 380px; margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column-reverse; gap: 6px; }
.toast { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; background: var(--solid); border: 1px solid var(--line);
  border-left: 2px solid var(--text-2); padding: 9px 12px 10px; font-size: 12px; line-height: 1.45; color: var(--text-2); animation: toast-in .2s ease-out; }
.toast b { grid-column: 1; margin-bottom: 2px; font-size: 13px; font-weight: 600; line-height: 1.35; color: var(--text); }
.toast span { grid-column: 1 / -1; }
.toast b, .toast span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }

.toast small { grid-row: 1; grid-column: 2; padding-top: 1px; font-size: 11px; color: var(--muted); }
.toast.warn { border-left-color: var(--warn); }
.toast.down { border-left-color: var(--down); }
.toast.good { border-left-color: var(--run); }
.toast.maqia { border-left-color: var(--maqia); }
.toast.link { cursor: pointer; }
.toast.link:hover { background: #222224fa; }
.toast.link:focus-visible { outline-offset: -1px; }
@keyframes toast-in { from { opacity: 0; transform: translateX(-8px); } }

/* The right-hand side: the machine panel or the decisions timeline, docked under the top bar. */
.panel { position: absolute; right: 0; top: var(--bar-h, 48px); bottom: 0; width: 400px; box-sizing: border-box; overflow-y: auto;
  background: var(--panel); border-left: 1px solid var(--line); padding: 14px 16px 18px; font-size: 13px; line-height: 1.45; }
.panel h2 { margin: 0 40px 2px 0; font-weight: 600; font-size: 17px; line-height: 1.3; letter-spacing: -.01em; }
.panel h3 { margin: 20px 0 8px; padding-bottom: 6px; border-bottom: 1px solid var(--line); font-size: 10px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.panel .close { position: absolute; right: 0; top: 0; width: 40px; height: 40px; padding: 0; border: 0; border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line); font-size: 13px; }
#panel ul { list-style: none; margin: 0; padding: 0; }
#panel li { padding: 5px 0; border-bottom: 1px solid var(--line-soft); color: var(--text-2); }
#panel li:last-child { border-bottom: 0; }
.bar { height: 4px; background: var(--line-soft); overflow: hidden; margin-top: 6px; }
.bar > i { display: block; height: 100%; background: var(--run); }
#panel-signal { width: 100%; }
.ranges { display: flex; margin: 8px 0; flex-wrap: wrap; }
.ranges button { padding: 5px 10px; font-size: 12px; }
.ranges button + button { margin-left: -1px; }
.ranges button[aria-pressed='true'] { position: relative; }
/* The chart's colours come from these tokens (ui/chart.js). */
.chart { width: 100%; height: 170px; display: block; background: var(--bg); border: 1px solid var(--line-soft); box-sizing: border-box;
  --chart-grid: var(--line-soft); --chart-text: var(--muted); --chart-value: var(--text); --chart-signal: var(--maqia); --chart-warn: var(--down); }

/* The decisions timeline: a row per decision, the newest first, split by hairlines and ruled green (as predicted or
   better), red (worse) or grey (waiting, or no prediction); a suggestion waiting for its answer says so in volt. */
.cards { list-style: none; margin: 14px -16px 0; padding: 0; border-top: 1px solid var(--line); }
.card { padding: 11px 16px 13px 14px; border-bottom: 1px solid var(--line); border-left: 2px solid var(--idle); }
.card.good { border-left-color: var(--run); }
.card.bad { border-left-color: var(--down); }
.card.link { cursor: pointer; }
.card.link:hover { background: var(--hover); }
.card-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; width: 100%; padding: 0; border: 0; background: none;
  text-align: left; font: inherit; color: inherit; }
.card-head b { font-size: 12px; font-weight: 600; }
.card-head .muted { font-size: 12px; }
.card .status { flex-basis: 100%; font-size: 11px; color: var(--muted); }
.card[data-status='Suggested'] .status { color: var(--maqia); }
.card .about { margin-top: 6px; font-size: 12px; }
.card .choice { margin-top: 4px; font-weight: 600; }
.card .reason, .card .prediction { margin-top: 5px; font-size: 12px; color: var(--text-2); }
.card .items { list-style: none; margin: 9px 0 0; padding: 0; display: grid; gap: 6px; }
.item { padding-left: 9px; border-left: 2px solid var(--idle); font-size: 12px; }
.item.good { border-left-color: var(--run); }
.item.bad { border-left-color: var(--down); }
.item small { display: block; color: var(--muted); }

/* The plant-wide morning summary, docked under the top bar on the left: folded to its title until opened. */
.summary { position: absolute; left: 0; top: var(--bar-h, 48px); width: 380px; max-height: 40%; overflow-y: auto; box-sizing: border-box;
  background: var(--panel); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); border-left: 2px solid var(--maqia); font-size: 13px; }
.summary-head { display: flex; align-items: baseline; gap: 10px; width: 100%; padding: 11px 14px; border: 0; background: none; text-align: left;
  font: inherit; color: var(--text); }
.summary-head:hover { background: var(--hover); }
.summary-head b { font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.summary-head .muted { font-size: 12px; }
.summary-head::after { content: '+'; margin-left: auto; color: var(--muted); }
.summary-head[aria-expanded='true']::after { content: '−'; }
.summary-text { padding: 0 14px 13px; line-height: 1.5; white-space: pre-line; color: var(--text-2); }

/* The presenter drawer: a row per control group, each named on its left. */
.drawer { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); width: min(960px, calc(100% - 28px)); box-sizing: border-box;
  background: var(--solid); border: 1px solid var(--line); font-size: 13px; display: grid; }
.drawer[hidden] { display: none; }
.drawer::before { content: 'Presenter'; padding: 9px 14px; border-bottom: 1px solid var(--line); font-weight: 600; font-size: 13px; }
.drawer .row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; padding: 8px 14px; border-bottom: 1px solid var(--line-soft); }
.drawer .row > .label { min-width: 100px; font-size: 10px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.drawer .row > .maqia-name { font-size: 12px; letter-spacing: 0; text-transform: none; color: var(--maqia); }
.drawer .status { padding: 8px 14px; min-height: 1.2em; font-size: 12px; color: var(--muted); }

#chat { display: flex; flex-direction: column; border-left: 1px solid var(--line); background: var(--bg); min-width: 0; }
.chat-bar { display: flex; align-items: stretch; justify-content: space-between; min-height: 40px; padding-left: 14px;
  border-bottom: 1px solid var(--line); background: #111112; }
.chat-title { align-self: center; font-weight: 600; font-size: 13px; }
.chat-bar a { display: flex; align-items: center; padding: 0 14px; border-left: 1px solid var(--line); font-size: 12px; font-weight: 600;
  text-decoration: none; color: var(--text-2); }
.chat-bar a:hover { background: var(--hover); color: var(--text); }
#chat-frame { flex: 1; width: 100%; border: 0; background: #fff; }

/* Labels over the plant (CSS2DRenderer): square tags with a status square; a down or warned machine's tag is edged.
   Far from the camera a label is its status square alone (.far, plant.js), edged in ink so it reads on any surface;
   the machines that need attention keep their whole tag. The areas' names are lettered on the floor (hall.js). */
.lbl { display: flex; align-items: center; gap: 6px; padding: 4px 8px 4px 7px; background: #111112e6; border: 1px solid var(--line);
  color: var(--text); font-size: 11px; font-weight: 600; line-height: 1.2; white-space: nowrap; }
.lbl::before { content: ''; flex: none; width: 6px; height: 6px; background: var(--idle); }
.lbl.running::before, .lbl.setup::before { background: var(--run); }
.lbl.waiting::before { background: var(--warn); }
.lbl.down::before { background: var(--down); }
.lbl.maintenance::before { background: var(--maint); }
.lbl i { font-style: normal; font-weight: 400; color: var(--text-2); }
.lbl.waiting i { color: var(--warn); }
.lbl.down { border-color: var(--down); }
.lbl.down i { color: #ff6b6f; }
.lbl.maintenance i { color: var(--maint); }
.lbl.warn { border-color: var(--warn); }
.lbl b { color: var(--warn); }
.lbl.far { padding: 0; gap: 0; background: none; border: 0; }
.lbl.far::before { width: 7px; height: 7px; outline: 2px solid #0f0f10b3; }
.lbl.far span, .lbl.far i { display: none; }

@media (prefers-reduced-motion: reduce) {
  .toast, .badge::before { animation: none; }
}
