/* studio-ui.css — the ONE house standard shared by every Eco-Architect version
   (v1 · v2 · v3 · v4 + shell.html).
   =========================================================================
   The four versions grew separately and drifted: four palettes, four button
   shapes, four slider looks, and three different ways of saying "this section
   opens". This file is the single definition of the three controls the
   versions actually share — TOOLBARS, SLIDERS, COLLAPSIBLE SECTIONS — plus the
   layout invariants that stop panels painting over each other.

   Load order matters: every version links this FIRST, then its own stylesheet,
   so a version can still specialise. Rules here are written at low specificity
   (:where(), bare element selectors) so that stays true.

   House language (CLAUDE.md): bold + graphic. Archivo Black for headings, nav,
   buttons. ALL visible text is BLACK (var(--ui-ink)) — never grey, and never faked with
   opacity on a text node (see .ui-quiet). Colour is for status fills, links
   and slider tracks only. */

:root {
  --font-display: "Archivo Black", system-ui, sans-serif;
  --ui-ink: #111;
  --ui-line: #111;
  --ui-paper: #fff;
  --ui-wash: #f6f4ef;        /* panel / header fill */
  --ui-track: #e7e3d8;       /* inert bar + hairline */
  --ui-accent: #b0451f;      /* warm rust — the studio's one accent */
  --ui-ok: #1c7d3f;
  --ui-warn: #b07a13;
  --ui-bad: #b0291f;
  --ui-focus: #0b57d0;
}

/* ---------------------------------------------------------------- text ----
   Rule 4: no grey body text. Versions used `opacity` on text to mean
   "secondary"; opacity greys the glyphs. .ui-quiet is the sanctioned way to
   step text back — smaller and letter-spaced, still full-black. */
.ui-quiet { opacity: 1; color: var(--ui-ink); font-size: .92em; }

/* ------------------------------------------------------------- toolbar ----
   ONE toolbar: a wrapping row of pill buttons on a hairline-ruled bar, with
   .ui-tbsep dividers and .ui-tbgrow pushing the status line to the right.
   Buttons never shrink below their label, and the bar wraps instead of
   clipping — a toolbar that hides its own controls is the bug we keep hitting.
*/
:where(.ui-toolbar) {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  padding: 7px 14px; border-bottom: 1.5px solid var(--ui-line);
  background: var(--ui-paper);
}
:where(.ui-tbsep) { width: 1.5px; align-self: stretch; background: var(--ui-track); margin: 2px 4px; }
:where(.ui-tbgrow) { flex: 1 1 0; min-width: 0; }

/* The house button: pill, 1.5px black rule, black label. `.solid` inverts it
   for the one primary action per bar; `.ghost` softens the rule for tertiary
   actions. Shared by <button> and <select> so a dropdown reads as a control of
   the same family. */
:where(.ui-btn) {
  font-family: var(--font-display); text-transform: uppercase; letter-spacing: -.01em;
  font-size: 11px; line-height: 1;
  padding: 7px 11px; border: 1.5px solid var(--ui-line); border-radius: 999px;
  background: var(--ui-paper); color: var(--ui-ink); cursor: pointer;
  white-space: nowrap; max-width: 100%;
}
:where(.ui-btn:hover) { background: var(--ui-wash); }
/* NOT wrapped in :where(): a version's own `button { color: … }` reset would
   otherwise win and paint a black label on the black fill — an invisible
   button. Legibility is the one thing a version may not override. */
.ui-btn.solid { background: var(--ui-ink); color: var(--ui-paper); }
.ui-btn.solid:hover { background: var(--ui-ink); }
:where(.ui-btn.ghost) { border-color: var(--ui-track); }
:where(.ui-btn:active) { transform: translateY(1px); }
:where(.ui-btn:disabled) { opacity: .45; cursor: not-allowed; transform: none; }
:where(select.ui-btn) { padding-right: 8px; }

/* -------------------------------------------------------------- sliders ---
   Every range input in every version reads the same: a full-width rust track
   with a black-ruled thumb, on its own line under its label + value. Sized so
   the hit target clears the 24px pointer-target guidance. */
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 24px; margin: 0; padding: 0;
  background: transparent; cursor: pointer; color: var(--ui-accent);
  accent-color: var(--ui-accent);
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px;
  background: var(--ui-track); border: 1px solid rgba(17, 17, 17, .35);
}
input[type="range"]::-moz-range-track {
  height: 6px; border-radius: 999px;
  background: var(--ui-track); border: 1px solid rgba(17, 17, 17, .35);
}
input[type="range"]::-moz-range-progress { height: 6px; border-radius: 999px; background: var(--ui-accent); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 15px; height: 15px; margin-top: -5.5px; border-radius: 50%;
  background: var(--ui-accent); border: 1.5px solid var(--ui-ink);
}
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%; box-sizing: border-box;
  background: var(--ui-accent); border: 1.5px solid var(--ui-ink);
}
input[type="range"]:disabled { cursor: not-allowed; }
input[type="range"]:disabled::-webkit-slider-thumb { background: var(--ui-track); }
input[type="range"]:disabled::-moz-range-thumb { background: var(--ui-track); }

/* The standard slider ROW: label and value share a line, the track spans the
   full width beneath them. Value is tabular so digits don't jitter on drag. */
:where(.ui-slider) { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 0 8px; margin: 2px 0; }
:where(.ui-slider) > label, :where(.ui-slider) > span:first-child { font-size: 12px; }
:where(.ui-slider) .ui-val { font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }
:where(.ui-slider) input[type="range"] { grid-column: 1 / -1; }

/* -------------------------------------------------- collapsible sections --
   ONE disclosure: a <details class="ui-sec"> whose <summary> is a full-width
   header with a ▸/▾ marker that rotates open. Used for every "this opens"
   affordance so a section never *looks* collapsible without being it — v3's
   decorative "▸ The site & forces" headings were exactly that trap.

   The body is the section's own scroll container, so an open section can never
   push its neighbours out of the panel (or paint over them). */
/* `flex: none` by default: stacked in a scrolling panel, an accordion section
   must keep its natural height and let the PANEL scroll. As a shrinkable flex
   item it would instead be squeezed to nothing and its body would paint over
   the section above it. The few sections that own a slice of the layout
   (V2's MAKE, V4's brainstormer, the series bands) set their own flex/height. */
:where(.ui-sec) { flex: none; border-bottom: 1.5px solid var(--ui-line); min-height: 0; }
:where(.ui-sec) > summary {
  display: flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  list-style: none; padding: 7px 10px; background: var(--ui-wash);
  font-family: var(--font-display); text-transform: uppercase; font-size: 11px;
  letter-spacing: -.01em; color: var(--ui-ink);
}
:where(.ui-sec) > summary::-webkit-details-marker { display: none; }
:where(.ui-sec) > summary::before {
  content: "▸"; font-family: system-ui, sans-serif; font-size: 10px;
  width: 10px; flex: none; transition: transform .12s ease;
}
:where(.ui-sec[open]) > summary::before { transform: rotate(90deg); }
:where(.ui-sec) > summary:hover { background: var(--ui-track); }
/* A hint riding along in the summary — house style, not grey. */
:where(.ui-sec) > summary .ui-sechint {
  font-family: system-ui, sans-serif; font-weight: 400; text-transform: none;
  letter-spacing: 0; font-size: 11px; margin-left: auto; text-align: right;
}
:where(.ui-sec-body) { padding: 9px 10px; overflow: auto; min-height: 0; }

/* Chromium (131+) wraps a <details>'s non-summary children in a UA-generated
   box, ::details-content. That box SEVERS a flex chain running from the
   <details> down to its body: the body stops shrinking, so its content is
   clipped with no scrollbar to reach it — text cut off at the bottom, which is
   the exact symptom this pass exists to remove. Making the wrapper a
   transparent flex passthrough restores the chain. Engines that don't
   implement the pseudo-element lay the children out as direct flex items
   already, so both paths end up identical.

   `flex: 1 1 auto` (not `1 1 0`) is deliberate: with an `auto` basis the
   wrapper still reports the body's natural height, so a section that should
   size to its content — capped by its own max-height — keeps doing that, while
   a section given an explicit height still shrinks the wrapper to fit. Both
   shapes are in use across the four versions. */
.ui-sec[open]::details-content {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden;
}

/* ------------------------------------------------------------- focus ------
   One visible focus ring everywhere — several versions had none. */
:where(a, button, select, input, textarea, summary):focus-visible {
  outline: 2px solid var(--ui-focus); outline-offset: 2px; border-radius: 4px;
}

/* ------------------------------------------------------- layout guards ----
   The overlap bugs across all four versions were the same two mistakes:
     1. a flex/grid CHILD with no `min-height: 0`, which refuses to shrink and
        pushes its content out of the panel;
     2. a scroll/stage container with no `overflow` containment, so whatever
        overflows paints straight over the panel below.
   These guards make both structural, so no version can regress into it.

   .ui-stage is the 3D viewport wrapper: `overflow: hidden` plus an absolutely
   positioned canvas means the WebGL canvas is sized BY the stage and never
   contributes its own intrinsic size back to the grid — the exact loop that
   let V4's canvas grow over the brainstormer. */
:where(.ui-stage) { position: relative; overflow: hidden; min-width: 0; min-height: 0; }
:where(.ui-stage) > canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
:where(.ui-col) { min-width: 0; min-height: 0; overflow: hidden; }
:where(.ui-scroll) { overflow: auto; min-height: 0; overscroll-behavior: contain; }

/* -------------------------------------------------------------- notices ---
   Handoff banners / warnings. Colour is a background wash only; text is black.
   Long notes are a scrollable list rather than an unbounded stack, so a chatty
   handoff can never eat the tool's own height. */
:where(.ui-notice) {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  padding: 7px 14px; border-bottom: 1.5px solid var(--ui-line);
  background: var(--ui-wash); font-size: 12.5px; line-height: 1.35; color: var(--ui-ink);
}
:where(.ui-notice) b {
  font-family: var(--font-display); text-transform: uppercase; font-size: 11px;
  letter-spacing: -.01em; flex: none;
}
:where(.ui-notice-body) { flex: 1 1 320px; min-width: 0; max-height: 6.5em; overflow: auto; }
:where(.ui-notice-x) {
  margin-left: auto; flex: none; border: 1.5px solid var(--ui-line); border-radius: 8px;
  background: var(--ui-paper); cursor: pointer; font-size: 12px; padding: 2px 8px; line-height: 1.2;
}
:where(.ui-notice-x:hover) { background: var(--ui-track); }

/* ------------------------------------------------------------ reduced -----
   Respect the OS "reduce motion" setting for the disclosure marker. */
@media (prefers-reduced-motion: reduce) {
  :where(.ui-sec) > summary::before { transition: none; }
}
