/* ==========================================================================
   Mistral Agent Workflow — token block
   Every colour used anywhere in this system is declared here.
   No hex literal may appear outside this block (see BUILD_BRIEF.md rule 1).
   ========================================================================== */

/* All three typefaces are bundled in fonts/. Nothing here touches the network,
   so the piece renders identically offline and in a headless capture run.
   Inter and Space Mono are Mistral's own fonts, both SIL OFL; N27 is Mikael's.
   Only weight 400 is used for the two Google faces, and only weight 200 for N27,
   so the bundle stays at six files. latin + latin-ext cover every glyph on stage.
   font-display is "block", not "swap": a fallback frame would change the typing
   measurements, and the piece measures glyph advances from the live text. */

@font-face {
  font-family: "N27";
  src: url("fonts/n27-extralight-webfont.woff2") format("woff2");
  font-weight: 200;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: "Inter";
  src: url("fonts/inter-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Inter";
  src: url("fonts/inter-400-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: "Space Mono";
  src: url("fonts/spacemono-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Space Mono";
  src: url("fonts/spacemono-400-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

:root {
  /* Agent palette — identical in both themes (spec §17) */
  --mother:          #FA3A04;  /* fixed. deep orange-red. also the typing caret */
  --birth:           #FF9D06;  /* temporary birth state */

  --agent-red:       #E30F00;
  --agent-crimson:   #E2002C;
  --agent-vermilion: #F7560D;
  --agent-orange:    #FC7D02;
  --agent-amber:     #FF6C02;

  --idle-opacity:    0.4;

  /* Geometry (spec §2, §20) */
  --S:   72px;                  /* primary agent edge */
  --M:   calc(var(--S) / 2);    /* micro agent edge, also primary-to-primary gap */
  --gap: var(--M);

  --approval-outline-w: 5px; /* heavier than the 3px scale note — matches the art */

  /* Caret metrics (spec §20), ratios against S */
  --caret-w: calc(var(--S) * 0.16);
  --caret-h: calc(var(--S) * 0.57);

  /* Typography (spec §20) */
  --font-body: "Inter", sans-serif;
  --font-mono: "Space Mono", monospace;
  --font-credit: "N27", sans-serif;

  /* Text column (spec §20): 22.7% of stage width -> 436px at 1920 */
  --text-x: 436px;
  --text-line-height: 43.2px;
  --text-font-size: 32px;

  /* Transition durations (spec §16.1) — reserved for later batches */
  --dur-structural: 275ms;
  --dur-layout: 425ms;

  /* Bubble does NOT invert (spec §11). It is a light panel in both themes and
     everything inside it is fixed dark ink. Never use --text in the bubble:
     in dark mode --text equals --bubble and the content disappears. */
  --bubble:     #ECE9E1;
  --bubble-ink: #161525;
}

:root[data-theme="dark"] {
  --bg:             #161525;   /* dark blue-gray */
  --text:           #ECE9E1;
  --tool-ground:    #EFEFE7;
  --tool-mark:      #161525;
  --hollow:         #2C2B39;   /* approval-square interior: faint lift on dark */
  --bubble-outline: transparent; /* dark bubble has no visible stroke */
}

:root[data-theme="light"] {
  --bg:             #ECEAE1;   /* warm off-white */
  --text:           #020202;
  --tool-ground:    #161525;
  --tool-mark:      #ECEAE1;
  --hollow:         #ECE9E1;   /* same as ground in light */
  --bubble-outline: var(--bubble-ink);
}

/* ==========================================================================
   Base / stage
   ========================================================================== */

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  background: var(--bg);
  overflow: hidden;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
}

#stage-viewport {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Embed mode positions the stage itself, so the viewport must not also centre
   it or the two offsets fight. See fitStage() in script.js. */
:root[data-embed="1"] #stage-viewport {
  display: block;
  overflow: hidden;
}

:root[data-embed="1"] #stage {
  position: absolute;
  top: 0;
  left: 0;
}

#stage {
  position: relative;
  width: 1920px;
  height: 1080px;
  background: var(--bg);
  flex: none;
  transform-origin: center center;
  overflow: hidden;
}

/* ==========================================================================
   Positioning helper
   Elements are placed via the --x / --y custom properties, set inline
   per-element from JS. No coordinate is ever written into this stylesheet.
   ========================================================================== */

.pos {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(var(--x, 0px), var(--y, 0px));
}

.loop-credit {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-credit);
  font-weight: 200;
  font-size: 28px;
  letter-spacing: 0.14em;
  color: var(--text);
  pointer-events: none;
  z-index: 30;
  white-space: nowrap;
  opacity: 0;
}

/* ==========================================================================
   Text response (primitive)
   ========================================================================== */

.text-response {
  position: absolute;
  left: var(--text-x);
  /* top is set inline from JS: the container top is calibrated from the
     measured glyph-top offset (spec §20), not a fixed value here. */
  font-family: var(--font-body);
  font-size: var(--text-font-size);
  line-height: var(--text-line-height);
  color: var(--text);
  white-space: pre;
}

.text-response .line {
  opacity: var(--line-opacity, 1);
}

/* ==========================================================================
   Typing caret (primitive)
   ========================================================================== */

.caret {
  position: absolute;
  width: var(--caret-w);
  height: var(--caret-h);
  background: var(--mother);
}

/* ==========================================================================
   Primary / micro agent squares (primitive)
   Hue is supplied per-instance via the --hue custom property, which is
   always assigned one of the palette tokens above — never a literal.
   ========================================================================== */

.agent {
  background: var(--hue);
  z-index: 2;
  position: absolute;
}

.agent-front { z-index: 5; }
.agent-behind { z-index: 1; }

.agent-primary {
  width: var(--S);
  height: var(--S);
}

.agent-micro {
  width: var(--M);
  height: var(--M);
}

.agent-idle {
  opacity: var(--idle-opacity);
}

/* ==========================================================================
   Tool module (primitive)
   Ground and mark are theme-inverted per the rule in spec §17.
   ========================================================================== */

.tool {
  background: var(--tool-ground);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 6;
}

.tool.pos {
  transform: translate(var(--x), var(--y)) scale(var(--tool-scale, 1));
  transform-origin: 50% 100%;
}

.tool-primary {
  width: var(--S);
  height: var(--S);
}

.tool-micro {
  width: var(--M);
  height: var(--M);
}

.tool svg {
  width: 64%;
  height: 64%;
  fill: var(--tool-mark);
}

.tool-micro svg {
  display: none; /* micro tools omit the logo per spec §9 */
}

/* ==========================================================================
   Approval square + "!" (primitive)
   Outline and glyph both take the requesting agent's own hue.
   ========================================================================== */

.agent-approval {
  width: var(--M);
  height: var(--M);
  background: var(--hue);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3;
  cursor: pointer;
}

/* The interior is a real centred child (not a CSS border) so Batch D can
   animate it scaling from 0 without restructuring. Its size leaves the
   outline ring showing on all four sides. */
.agent-approval .hollow {
  width: calc(var(--M) - 2 * var(--approval-outline-w));
  height: calc(var(--M) - 2 * var(--approval-outline-w));
  background: var(--hollow);
  transform-origin: center center;
  transform: scale(var(--hollow-scale, 1));
}

.approval-bang {
  width: 6px;
  z-index: 4;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.approval-bang.pos {
  transform: translate(var(--x), var(--y)) scale(var(--bang-scale, 1));
  transform-origin: 50% 100%;
}

.approval-bang .bang-stem {
  width: 6px;
  height: 20px;
  background: var(--hue);
}

.approval-bang .bang-dot {
  width: 6px;
  height: 6px;
  background: var(--hue);
}

/* ==========================================================================
   Approval bubble (primitive)
   Sharp-edged thought bubble, Space Mono, anchored to the requesting agent.
   ========================================================================== */

.approval-bubble {
  position: absolute;
  z-index: 15;
  box-sizing: border-box;
  width: 481px;
  background: var(--bubble);
  /* Stroke sits outside the 481×131 fill (prroval.pdf has no inset border). */
  box-shadow: 0 0 0 2px var(--bubble-outline);
  font-family: var(--font-mono);
  padding: 28px 53px 29px;
  text-align: center;
  transition: opacity 280ms ease;
}

.approval-bubble.is-leaving {
  opacity: 0;
}

.approval-bubble .question {
  color: var(--bubble-ink);
  font-size: 24px;
  line-height: 24px;
  letter-spacing: -0.24px;
  margin: 0 0 15px 0;
  white-space: nowrap;
  text-align: center;
}

.approval-bubble .actions {
  display: flex;
  gap: 16px;
  justify-content: center;
}

.approval-bubble button {
  box-sizing: border-box;
  font-family: var(--font-mono);
  font-size: 21px;
  /* Optical, not metric. line-height 31 in a 31px content box centres the em
     box, but Space Mono carries a deep descender, so the visible mass of a
     word sits low in the button. 28 + 3px of bottom padding fills the same
     31px and lifts the label to where it looks centred. */
  line-height: 28px;
  padding: 0 0 3px;
  letter-spacing: -0.21px;
  width: 140px;
  height: 35px;
  margin: 0;
  background: none;
  cursor: pointer;
}

.approval-bubble button.approve {
  color: var(--bubble-ink);
  border: 2px solid var(--bubble-ink);
}

.approval-bubble button.approve.is-pressed {
  background: var(--bubble-ink);
  color: var(--bubble);
}

.approval-bubble button.decline {
  color: var(--agent-red);
  border: 2px solid var(--agent-red);
}

.verify-report {
  position: fixed;
  left: 8px;
  top: 8px;
  z-index: 9999;
  margin: 0;
  padding: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
  background: var(--bg);
}

/* Stepped tail, built as two stacked silhouettes rather than as strokes.
   .tail-ink is 2px wider on each side and sits 2px lower, so after .tail-fill
   is laid over it the only ink still showing is a clean 2px step down both
   sides and across the bottom. The mouth stays open because the fill starts
   2px higher than the ink and covers the panel's own bottom stroke. */

.approval-bubble .tail-steps {
  position: absolute;
  left: 50%;
  top: calc(100% - 2px);
  /* Keep the stepped silhouette at its final geometry throughout. Scaling it
     vertically squeezed the fill and outline into each other, creating a dark
     overlap against the bubble face midway through arrival/retraction. */
  width: 24px;
  height: 19px;
  transform: translateX(-50%);
  clip-path: inset(0 0 var(--tail-clip, 0%) 0);
  transition: clip-path 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

.approval-bubble .tail-ink,
.approval-bubble .tail-fill {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.approval-bubble .tail-ink { top: 2px; }
.approval-bubble .tail-fill { top: 0; }

.approval-bubble .tail-row {
  height: 5px;
  margin-top: -1px;
}

.approval-bubble .tail-row:first-child {
  margin-top: 0;
}

.approval-bubble .tail-ink .tail-row {
  width: calc(var(--n) * 5px + 4px);
  background: var(--bubble-outline);
}

.approval-bubble .tail-fill .tail-row {
  width: calc(var(--n) * 5px);
  background: var(--bubble);
}

/* ==========================================================================
   Custom pixel cursor (primitive)
   A blocky, axis-aligned outline arrow drawn to match the pixel language,
   never the native OS pointer. Outline colour reuses --text, which already
   contrasts --bg correctly in both themes.
   ========================================================================== */

.pixel-cursor {
  width: 36px;
  height: 57px;
  overflow: visible;
  z-index: 20;
  pointer-events: none;
}

.pixel-cursor .cursor-ink {
  fill: var(--text);
}

.pixel-cursor .cursor-hollow {
  fill: var(--bg);
}

/* ==========================================================================
   Debug mode overlay (Phase 3.5) — bounds box and pixel grid, toggled with
   the "G" key. Uses only existing tokens (--text) at low opacity, so it
   adds no new colour literal.
   ========================================================================== */

.debug-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.debug-grid-line {
  position: absolute;
  background: var(--text);
  opacity: 0.06;
}

.debug-grid-v {
  top: 0;
  bottom: 0;
  width: 1px;
}

.debug-grid-h {
  left: 0;
  right: 0;
  height: 1px;
}

.debug-bounds {
  position: absolute;
  outline: 1px dashed var(--text);
  opacity: 0.6;
  pointer-events: none;
}

.debug-center-line {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--text);
  opacity: 0.25;
  pointer-events: none;
}

/* ==========================================================================
   Opening-transition timeline scrubber (Phase 4/5) — debug mode only.
   Drives Clock.seek() -> renderOpening(t) directly; not part of the stage
   coordinate system, so it is laid out with ordinary flow CSS rather than
   the --x/--y positioning helper.
   ========================================================================== */

.debug-scrubber {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 20px;
  background: var(--bg);
  border-top: 1px solid var(--text);
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--text);
  z-index: 10;
}

.debug-scrubber input[type="range"] {
  flex: 1;
}

.debug-scrubber-label {
  white-space: nowrap;
  min-width: 180px;
}

/* ==========================================================================
   Selection band (Phase 5.5, the writing close-up)
   Sits behind the glyphs and grows left to right, so the loop restarts by
   selecting and clearing the line rather than cutting or fading. Uses the
   agent orange at low alpha rather than a system blue: nothing in this system
   is allowed a colour from outside the palette.
   ========================================================================== */

.selection {
  position: absolute;
  background: var(--agent-orange);
  opacity: 0;
  z-index: 1;
}


