/* Minhocário — reusable UI components.
   Cascade position 3 of 5: tokens → base → components → screens → motion.
   index.html is the source of truth for that order; never use @import.

   Widgets that are not tied to one screen: cards, panels, readouts, gauges,
   the modal chooser, the colony-dead banner. Rules keep their original relative
   order within this file, because several pairs rely on it (`.gauge__fill` then
   its `--warn`/`--alert` variants).

   Appearance only: where a widget sits on a screen belongs to screens.css. The
   internals panel is the case that makes the rule visible — it is styled here
   but placed by the game screen's `grid-area: readouts`, declared alongside the
   grid that defines that area rather than split away from it. */

/* --- Icons --- */
/* The sprite lives at the top of <body>. It must stay in the render tree for
   <use> to resolve, so it is taken out of LAYOUT rather than hidden:
   `display: none` on the sprite breaks every reference to it in some engines. */
.ico-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Sized in `em` so an icon tracks the type size of whatever it sits in, and
   painted in `currentColor` by the symbols themselves — which is what makes an
   icon inside a warn/alert button pick up that tier for free. */
.ico {
  flex: none;
  width: 1.15em;
  height: 1.15em;
}

/* Parametric glyphs (js/ui/icons.js). Their colours cannot live in the symbol,
   because the whole point is that they change with a value. */
.ico-volume {
  flex: none;
  width: 1.6em;
  height: 1.6em;
}
.ico-volume__vessel { fill: none; stroke: var(--ink-dim); stroke-width: 1.5; }
.ico-volume__level { fill: var(--accent); }

.ico-ring {
  flex: none;
  width: 1.5em;
  height: 1.5em;
}
.ico-ring__track { fill: none; stroke: var(--surface-2); stroke-width: 3; }
.ico-ring__arc {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linecap: round;
  /* Sweeps to the new fraction on each repaint instead of jumping, matching the
     gauge marker's glide. */
  transition: stroke-dashoffset var(--dur-slow) var(--ease);
}

/* --- Shop card --- */
.shop-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--surface-1);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
}
.shop-card h3 { margin: 0; font-size: var(--text-base); }
.shop-card__desc { color: var(--ink-dim); font-size: var(--text-md); margin: 0; }
/* Capacity and price are the two numbers a player compares across cards, so they
   line up column-wise down the grid rather than drifting with the digit widths. */
.shop-card__stats { font-size: var(--text-sm); margin: 0; font-variant-numeric: tabular-nums; }
.shop-card__buy { margin-top: auto; background: var(--accent); color: var(--accent-ink); }
.shop-card--disabled { opacity: 0.6; }
.shop-card--disabled .shop-card__buy { background: var(--surface-2); color: var(--ink); }
.shop-card__reason { color: var(--state-alert-ink); font-size: var(--text-xs); margin: 0; }

/* --- Internals panel --- */
/* The game screen's left grid column since V12 — no longer an overlay on the
   stage. Always present (the x-ray toggle no longer hides it), so the player
   collapses it themselves via the <details> disclosure; collapsing shrinks the
   whole grid column, handing the 3D scene its area back exactly as the overlay
   did (see the `:has()` rule in screens.css).
   `min-height: 0` lets it scroll inside the `minmax(0, 1fr)` stage row rather
   than stretching the row to fit the queue. */
.internals {
  min-height: 0;
  overflow-y: auto;
  padding: var(--space-3);
  font-size: var(--text-sm);
  background: var(--surface-1);
  border-right: 1px solid var(--surface-2);
}
.internals:not([open]) { overflow: visible; }
/* Mirrors `.stats > summary` — the same disclosure affordance in the other box. */
.internals > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--text-base);
  color: var(--ink-dim);
}
.internals[open] > summary { margin-bottom: var(--space-2); }
.internals h4 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--ink-dim);
}
/* No margin: #internals-body is a grid (screens.css) and its `gap` does the
   stacking. A margin here would ADD to that gap, and `:last-child` stops
   meaning "the bottom one" as soon as the groups flow into two columns. */
.internals__empty { margin: 0; color: var(--ink-faint); }

/* --- Readouts --- */
.stat { display: flex; justify-content: space-between; gap: var(--space-2); padding: var(--space-05) 0; }
/* Flex so an optional leading glyph (the queue's decomposition ring) sits on the
   text baseline row rather than pushing the label onto its own line. */
.stat__label { display: flex; align-items: center; gap: var(--space-2); color: var(--ink-dim); }
.stat__value { font-variant-numeric: tabular-nums; }
.stat--warn .stat__value { color: var(--state-warn-ink); font-weight: 600; }
.stat--alert .stat__value { color: var(--state-alert-ink); font-weight: 600; }

/* A gauge: label + value on one line, then a bar whose highlighted zone is the
   species' comfort band and whose marker is the current value. */
.gauge {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-05) var(--space-2);
  padding: var(--space-1) 0;
}
.gauge__label { color: var(--ink-dim); }
.gauge__value { font-variant-numeric: tabular-nums; }
.gauge__bar {
  grid-column: 1 / -1;
  position: relative;
  height: 8px;
  background: var(--surface-0);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.gauge__comfort {
  position: absolute;
  top: 0;
  height: 100%;
  background: var(--accent-soft);
  transition: left var(--dur-slow) var(--ease), width var(--dur-slow) var(--ease);
}
.gauge__marker {
  position: absolute;
  top: -1px;
  width: 3px;
  height: calc(100% + 2px);
  margin-left: -1px;
  background: var(--ink);
  border-radius: 2px;
  /* Glide to the new value each tick instead of jumping (T22 polish). */
  transition: left var(--dur-slow) var(--ease), background-color var(--dur) var(--ease);
}
.gauge--warn .gauge__value { color: var(--state-warn-ink); font-weight: 600; }
.gauge--warn .gauge__marker { background: var(--state-warn); }
.gauge--alert .gauge__value { color: var(--state-alert-ink); font-weight: 600; }
.gauge--alert .gauge__marker { background: var(--state-alert); }

/* A band-less gauge: the bar is filled from the left to the current level. Used
   by the statistics box for the humus tray / leachate tank, which have no
   comfort band — only a "filling up" tier and a "full" edge that stops
   production (§2.8). */
.gauge__fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: var(--accent-soft-strong);
  transition: width var(--dur-slow) var(--ease), background-color var(--dur) var(--ease);
}
.gauge--warn .gauge__fill { background: var(--state-warn); }
.gauge--alert .gauge__fill { background: var(--state-alert); }

/* --- Statistics box (score detail) --- */
/* Sits in the .actions sidebar flow, not over the stage — see js/ui/stats.js. */
.stats {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  background: var(--surface-2);
  border-radius: var(--radius);
}
.stats > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ink-dim);
}
.stats h4 {
  margin: 0 0 var(--space-1);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--ink-dim);
}
.stats__group { margin-top: var(--space-3); }
/* The bar's own track reads as a hole against the lighter box background, so it
   borrows the panel color here instead of the page background it uses on the
   (darker) internals overlay. */
.stats .gauge__bar { background: var(--surface-1); }

/* --- Modal chooser (add waste / portion / worm pack) --- */
.chooser {
  min-width: 260px;
  max-width: 90vw;
  /* Many rows of tiles must scroll INSIDE the dialog rather than growing it off
     a short screen. */
  max-height: 88vh;
  overflow-y: auto;
  padding: var(--space-4);
  color: var(--ink);
  background: var(--surface-1);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius-lg);
}
/* A <dialog> is `width: fit-content`, and `auto-fit`/`auto-fill` inside an
   intrinsically-sized box can NEVER resolve to more than one column — the track
   count is computed against the available inline size, and here that size is
   itself derived from the content. The 14-food chooser therefore laid out as a
   single tall column and scrolled. The grid needs a DEFINITE width to divide up.
   660px less 32px of padding leaves 628px, which fits five 112px tracks with
   8px gaps — so 14 foods land in three rows instead of fourteen.

   THE CAP IS DELIBERATE, and it makes this look unresponsive on a desktop.
   `min()` only lets the 90vw term win below a 734px viewport, so dragging a
   1920px window down to ~800px changes NOTHING — the dialog stays pinned at
   660px and the first column drop is at 694px. That is not a bug to "fix": the
   modal is capped so it stays a dialog rather than sprawling into a page, and
   14 foods already fit without scrolling on any normal desktop screen. Column
   counts below the cap: 5 >= 694px, 4 >= 560, 3 >= 427, 2 >= 294. Reviewed and
   kept at 660px on 2026-07-20. */
.chooser--grid { width: min(90vw, 660px); }
.chooser::backdrop { background: var(--scrim); }
.chooser h3 { margin: 0 0 var(--space-3); font-size: var(--text-lg); }
.chooser__options {
  display: grid;
  /* 112px suits a tile (a 52px glyph over a centred, wrapping name) and still
     holds the text-only worm-pack options comfortably. `auto-fit` rather than
     `auto-fill` so a prompt with fewer options than tracks (the four portion
     rungs) stretches to fill instead of leaving dead columns. */
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
/* The food grid is the one place the icon set is judged as a SET: 14 options in
   an auto-fill grid. Every cell gets identical geometry — same icon box, same
   gap, same alignment — so nothing about the layout can group them either. */
.chooser__option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  text-align: left;
}
/* Tiles: glyph stacked above the label. In the add-waste chooser the icon IS the
   content, not an ornament on a label, so it gets the room to say what it is —
   at chrome size (1.15em) the drawing inside the frame lands under 11px, which
   is what made the set unreadable. Fixed icon box + centred label also keeps
   all 14 cells geometrically identical however long the name runs. */
.chooser__option--tile {
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-2);
  text-align: center;
  line-height: var(--leading-tight);
}
.chooser__option--tile .ico { width: 3.25em; height: 3.25em; }
.chooser__option--tile .ico-volume { width: 3em; height: 3em; }
.chooser__cancel { width: 100%; }

/* --- Colony-dead banner (§2.1) --- */
/* Centered over the stage: production has stopped, so it should interrupt.
   The 340px cap was sized against a full-width stage; V12 put the stage in the
   centre column between two sidebars, where 340px can exceed the whole track at
   narrow widths and the banner would bleed under them. `min()` keeps the
   original size wherever it fits and falls back to the track width less a
   margin, so it stays inside the stage at every width. */
.banner {
  position: absolute;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  max-width: min(340px, calc(100% - var(--space-6)));
  padding: var(--space-3) var(--space-4);
  text-align: center;
  background: var(--surface-1);
  border: 1px solid var(--state-alert);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
.banner strong { color: var(--state-alert-ink); display: block; margin-bottom: var(--space-1); }
.banner p { margin: 0 0 var(--space-3); font-size: var(--text-md); color: var(--ink-dim); }
.banner button { background: var(--accent); color: var(--accent-ink); }

/* --- Shop: mid-farm upgrade extras --- */
.shop-card__tradein { margin: 0; font-size: var(--text-sm); color: var(--accent); }
.shop-card--current { border-color: var(--accent); }

.internals__model {
  margin: calc(var(--space-1) * -1) 0 var(--space-3);
  padding-bottom: var(--space-2);
  font-weight: 600;
  color: var(--accent);
  border-bottom: 1px solid var(--surface-2);
}

/* --- Author credit --- */
/* Appears on two screens that share nothing else — the home screen and the
   desktop-only notice — which is why it is a component rather than a rule in
   either. A signature: small, quiet, and never competing with the Play button
   above it. Colour comes from the bare `a` rule in base.css. */
.site-credit {
  margin: var(--space-6) 0 0;
  font-size: var(--text-xs);
  text-align: center;
}
