/* Forked from assets/css/concept-mint.css at 8172f25 (Standard, wave 1). Mint's copy is frozen; this one is Standard's. */
/* Standard's scoped chrome and shared screen primitives.
   Colour roles come from concept-std-colours.css; this sheet owns geometry.
   Mint's files remain frozen. No braces in comments: tests parse the rules. */

/* ---------- 1. Tokens ------------------------------------------------------
   Straight from the pack's ui/tokens.json. The names are prefixed --st- so
   they can never collide with game.css's, and the game.css tokens are retuned
   FROM them just below, so there is exactly one place a colour is decided.

   EVERY COLOUR IN THIS FILE IS ONE OF THESE, and that is not tidiness — it is
   what lets core/colours.js repaint the whole layout. Every scheme, the Astral
   default and the themeless black set are nothing but other values for these
   same names, written through assets/css/colours.css, so a hex code written
   anywhere else in this file is a colour no scheme can reach.
   tests/concept_std_theme.test.js fails on one.

   TWO ACCENT FAMILIES, and they mean different things. --st-accent is the
   ACTION colour: the CTA, the selected segment, the destination you are on,
   the meter. --st-link is the INFORMATION colour: links, glyphs, the info
   chip. In the mint palette they are the same mint cyan, which is why mint is
   unchanged by the split; in the Astral palette they are orange and blue,
   which is the whole point of it. */

.concept-std,
.concept-std ~ dialog.modal,
.concept-std ~ #toasts {
  /* The COLOUR tokens are not here. tools/std-colours.mjs writes them into
     concept-std-colours.css under #app.concept-std, from Standard's own scheme
     (ui/concept/standard/colours/schemes.js). What stays is the layout's own:
     the sizes, the font and the safe areas. */

  /* Phone chrome totals 130px before any device safe-area insets.
     Table sizes are shared with the table lane through these tokens. */
  --st-size-topbar: 44px;
  --st-size-strip: 34px;
  --st-size-bottombar: 52px;
  --st-size-sidebar: 208px;
  --st-size-row: 32px;
  --st-size-row-desktop: 28px;
  --st-size-th: 28px;
  --st-size-button: 26px;
  --st-size-control: 32px;
  --st-size-chip: 24px;
  --st-size-touch: 44px;
  --st-radius: 8px;
  --st-radius-sm: 6px;
  --st-radius-control: 999px;
  --st-font-table: 12.5px;
  --st-font-th: 11.5px;
  --st-font-title: 17px;
  --st-font-section: 13.5px;
  --st-tap: 44px;
  --st-header-icon: 26px;
  --st-nav-h: 52px;
  --st-hover: var(--st-panel-raised);
  --st-font:          system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* The safe areas, resolved once. index.html has no viewport-fit=cover today,
     so every env() below reads 0 — these are what make the frame correct the
     day it does, and the max() is what stops a 0 inset becoming a hairline. */
  --st-safe-top:      env(safe-area-inset-top, 0px);
  --st-safe-bottom:   env(safe-area-inset-bottom, 0px);
}

/* game.css's own tokens, retuned to the mint palette. Same trick
   preset-command.css plays, and the reason it is safe: every one of these is a
   colour, none is a size, and the semantic three (warning, danger, success)
   keep their MEANING and only change their exact hue. */
.concept-std,
.concept-std ~ dialog.modal,
.concept-std ~ #toasts {
  --bg-0:      var(--st-bg);
  --bg-1:      var(--st-bg-1);
  --bg-2:      var(--st-bg-2);
  --panel:     var(--st-panel);
  --panel-2:   var(--st-panel-raised);
  --panel-3:   var(--st-panel-3);

  --line:      var(--st-line-mid);
  --line-soft: var(--st-line-soft);
  --line-lit:  var(--st-line);
  --edge-ui:   var(--st-edge-ui);

  /* game.css's blue is the colour a classic screen LINKS and labels in, so it
     takes the information family, not the action one. --tab-current is the
     exception three lines down: "the tab you are on" is a destination marker,
     which is the action family's job in both palettes. */
  --blue:      var(--st-link);
  --blue-lit:  var(--st-link);
  --blue-deep: var(--st-link-deep);
  --blue-dim:  var(--st-link-dim);

  --amber:     var(--st-warning);
  --amber-dim: var(--st-warning-dim);
  --cyan:      var(--st-link);
  --cyan-dim:  var(--st-link-dim);
  --green:     var(--st-success);
  --green-dim: var(--st-success-dim);
  --danger:    var(--st-danger);
  --danger-dim: var(--st-danger-dim);

  --text:      var(--st-text);
  --text-2:    var(--st-muted);
  --text-3:    var(--st-text-3);
  --text-4:    var(--st-text-4);

  --rad:       var(--st-radius-sm);
  --rad-sm:    8px;
  --tab-current: var(--st-accent);

  /* The ink ON a filled control. game.css sets both to white, which is the
     right answer for ITS accent and the wrong one here: inside this scope
     --blue is --st-link, and white on a mint-cyan or a pale-blue fill measures
     under 2:1. The darkest surface this skin has is the ink that works in every
     palette it will ever be given, including a monochrome one. */
  --on-accent: var(--st-bg);
  --on-danger: var(--st-bg);

  /* The chrome is OUTSIDE the scroller in this frame, so nothing inside a
     screen has to be pushed down past it. Both of these are read by game.css
     rules that live inside <main> — the designer's vitals bar, the map stage —
     and both would otherwise reserve height for bars that are not there. */
  /* THE SEMANTICS, unchanged by the density pass and worth restating because
     the header really did get shorter: these are what a screen must SUBTRACT
     for chrome, and in this frame the answer is still zero however tall the
     bands are. --header-game-h is 0 because the header is outside the
     scroller, not because it has no height; --tabbar-h is 0 because the bar is
     outside it too. A screen that wants the real numbers is asking the wrong
     question — <main>'s own box is already the space it has. */
  --chrome-h:        0px;
  --header-game-h:   0px;
  --tabbar-h:        0px;
  --strips-h:        0px;
  --shutdown-strip-h: 0px;
  /* And the section strip, for the same reason and with the same caveat: a
     screen inside this frame subtracts nothing for it, while this file's own
     rules — which are about <main>'s box, not a screen's — read the measured
     --subtab-measured that game.css resolves on <html>. */
  --subtab-h:        0px;

  background: var(--st-bg);
  color: var(--st-text);
  font-family: var(--st-font);
  /* 15px is game.css's body size and it is one step too big for this layout at
     360px — the owner's verdict was "everything is huge". 14px is the
     reference's own body measure and it reaches the classic screens rendered
     inside this frame too, which is the point: one voice, one size. */
  font-size: 14px;
}

/* ---------- 1b. Typography, normalised -------------------------------------
   The Command preset speaks in UPPERCASE with wide tracking — a console voice,
   and a good one. It is not THIS skin's voice: the concept references are set
   in sentence case with tight tracking, and a heading that reads "EXAMPLE
   EMPIRE" across a hero banner is a different design language wearing the same
   words.

   preset-command.css rides on <html> and this rides on #app, so the two are not
   in a scope contest — they are in a SPECIFICITY contest, and the selectors
   below are written to match the preset's exactly (`.card > h2`,
   `details.card--fold > summary h2` and the rest) so that this file, which
   loads later, wins the tie. Enumerated rather than swept with `*`, because a
   sweep would sit at (0,1,0) and lose every one of these.

   It applies to the CLASSIC screens rendered inside this frame too, which is
   the point: one voice per look. */
.concept-std h1,
.concept-std h2,
.concept-std h3,
.concept-std .card > h2,
.concept-std details.card--fold > summary h2,
.concept-std ~ dialog.modal .modal-head h2,
.concept-std ~ dialog.modal .btn,
.concept-std .card h3,
.concept-std .btn,
.concept-std .pill,
.concept-std .chip,
.concept-std .kv dt,
.concept-std .tbl th,
.concept-std .tabbar a,
.concept-std .map-key > summary,
.concept-std .sub-tabbar a {
  text-transform: none;
  letter-spacing: normal;
}
.concept-std h1,
.concept-std h2 { letter-spacing: -.01em; }
/* The preset also draws a glowing hairline under every card heading, which is
   its panel language rather than this one's. */
.concept-std .card > h2 { background: none; padding-bottom: 0; }

/* ---------- 1c. Retired: the ASTRAL theme block ----------------------------
   This was a second set of values for section 1's tokens, selected by a class
   (`concept-std--astral`) that ui/concept/standard/shell.js put beside
   `.concept-std` — the owner's "Astral's blue and orange look" for this
   layout. It stopped deciding anything the day the colour system landed:
   assets/css/colours.css re-points every token here at the scheme in force, at
   a specificity this block could never beat, on every page that has
   `data-colours` on html — which is every page, from the pre-paint read on. So
   it was dead weight beside a second palette mechanism, and the one-layout
   decision (2026-10-31) retired the axis outright. The Astral values live on as
   the default scheme in core/colours.js and as colours.css's fallbacks; the
   plain look the owner asked for is `data-look`, styled by
   assets/css/look-themeless.css. */

/* ---------- 2. The frame ---------------------------------------------------
   #app becomes the window: exactly one viewport tall, fixed bands top and
   bottom, one scrolling band in the middle. Same shape as the app shell, and
   the same two reasons — the chrome must not scroll away, and the bottom bar
   must survive a pull-down. */

.concept-std { height: 100dvh; }
/* The same class on the wrapper ui/concept/standard/dialog.js puts inside a pop-up,
   so the component rules below reach kit markup in a <dialog> (which lives
   outside #app); the root height above is the one rule it must not inherit. */
.modal-body > .concept-std.st-dialog-scope, .modal-foot > .concept-std.st-dialog-scope { height: auto; background: none; }

/* A pull that starts on the chrome has no scrollable ancestor short of the
   viewport, so Chrome answers it itself and translates the whole document —
   which slides a static bottom bar off the screen mid-gesture. `contain` stops
   pull-to-refresh and the Android stretch without killing ordinary scrolling. */
html:has(> body > #app.concept-std),
body:has(> #app.concept-std) { overscroll-behavior-y: contain; }

/* The bands keep their own height; the screen absorbs the rest. Listed one by
   one rather than as `> *` so a screen's own positioned children can never pick
   this up. The alert strips are matched as DESCENDANTS: both fill themselves
   inside a display:contents mount point, so the strip is a grandchild while
   still laying out as a direct flex item. */
.concept-std > .shell-header,
.concept-std .shard-shutdown-strip,
.concept-std .combat-strip,
.concept-std > .sub-tabbar,
.concept-std > .st-nav { flex: 0 0 auto; }

/* Nothing in this frame scrolls, so nothing in it needs to be sticky. The
   strips keep every other rule game.css gives them — this only unpins them. */
.concept-std > .shell-header,
.concept-std .shard-shutdown-strip,
.concept-std .combat-strip { position: static; }

/* backdrop-filter costs a composited layer per bar and buys nothing when
   nothing scrolls behind it. */
.concept-std > .shell-header { backdrop-filter: none; }

/* ---------- 3. Top bar: app-owned controls retain their handlers and ids. */
.concept-std .shell-header--game {
  position: static; display: flex; flex-wrap: nowrap; align-items: center;
  height: calc(var(--st-size-topbar) + var(--st-safe-top)); min-height: var(--st-size-topbar);
  box-sizing: border-box; padding: var(--st-safe-top) 8px 0; gap: 4px;
  background: var(--st-bg); border-bottom: 1px solid var(--st-line);
  backdrop-filter: none; flex: none;
}
.concept-std .shell-header--game .header-break,
.concept-std .shell-header--game .tick-chip,
.concept-std .shell-header--game .empire-id,
.concept-std .shell-header--game .brand,
.concept-std .shell-header--game .mail-btn,
.concept-std .shell-header--game .st-exit { display: none; }
.concept-std .shell-header--game .menu-btn { order: 0; }
.concept-std .shell-header--game .st-tick { order: 1; margin-right: auto; }
.concept-std .shell-header--game .st-needs { order: 2; }
.concept-std .shell-header--game .st-orders-badge { order: 3; }
.concept-std .shell-header--game .st-chat { order: 4; }
.concept-std .shell-header--game [data-part="refresh"] { order: 5; }
.concept-std .shell-header--game .spacer { display: none; }
/* The one part of the bar that gives way: the buttons beside it are fixed, and at 360 px a live session's
   chat button leaves no room for "next 5:00 · lock 4:00" in full. The title attribute carries the whole line. */
.concept-std .st-tick { display: flex; flex-direction: column; gap: 1px; flex: 0 1 auto; min-width: 0; line-height: 1.2; }
.concept-std .st-tick__title { font-size: 12px; font-weight: 700; white-space: nowrap; }
.concept-std .st-tick__context { font-size: 10px; color: var(--st-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.concept-std .st-tick, .concept-std .st-orders-badge, .concept-std .st-needs {
  font-variant-numeric: tabular-nums lining-nums;
}
.concept-std .shell-header--game .icon-btn,
.concept-std .st-orders-badge, .concept-std .st-needs {
  box-sizing: content-box; flex: none; display: inline-flex; align-items: center; justify-content: center;
  height: var(--st-size-button); min-height: var(--st-size-button); min-width: 26px;
  padding: 0 4px; border: 0; border-radius: var(--st-radius-sm);
  background: var(--st-panel); color: var(--st-text); text-decoration: none; gap: 3px;
}
.concept-std .shell-header--game .icon-btn { width: 26px; padding-inline: 0; }
.concept-std .st-orders-badge .st-icon { width: 16px; height: 16px; }
.concept-std .st-orders-badge__count, .concept-std .st-needs__count { font-size: 11px; font-weight: 700; }
.concept-std .st-orders-badge__count[hidden], .concept-std [hidden] { display: none !important; }
.concept-std .st-breadcrumb { display: none; }
.concept-std .st-exit__label { white-space: nowrap; }

/* ---------- 4. The alert strips -------------------------------------------
   Unpinned in section 2 and repainted here. They keep their order and their
   content: an alert that a player learned to recognise in one look must look
   the same in both skins. */

.concept-std .shard-shutdown-strip,
.concept-std .combat-strip { border-bottom-color: var(--st-danger); }
/* On a phone, or sideways, the battle strip is a headline. With every fleet, empire and system spelled out it took a
   third of the glass, on every screen, for as long as a battle ran. It says who in two lines; the chevron gives the
   rest, with the links to each system, and the fleets' own pages say it all too. */
@media (max-width: 700px), (max-height: 500px) {
  .concept-std .combat-strip { align-items: center; padding-block: 2px; font-size: 12px; line-height: 1.35; }
  .concept-std .combat-strip-body {
    display: -webkit-box; flex: 1 1 0; min-width: 0; overflow: hidden; overflow-wrap: anywhere;
    -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  }
  .concept-std .combat-strip--open .combat-strip-body { display: block; }
  .concept-std .combat-strip:not(.combat-strip--open) .combat-strip-detail,
  .concept-std .combat-strip:not(.combat-strip--open) .combat-strip-place,
  .concept-std .combat-strip:not(.combat-strip--open) .combat-strip-why { display: none; }
  .concept-std .combat-strip-more {
    display: inline-flex; align-items: center; justify-content: center; flex: none;
    min-width: var(--tap); min-height: var(--tap); margin-block: calc((1.4rem - var(--tap)) / 2); padding: 0;
    border: 0; background: none; color: var(--st-muted); font-size: 14px; cursor: pointer;
  }
  .concept-std .combat-strip-dismiss { flex: none; margin-left: 0; }
}

/* ---------- 5. Section/detail strip. Overflow is measured, never guessed. */
.concept-std .st-strip {
  position: relative; flex: none; height: var(--st-size-strip); min-width: 0;
  border-bottom: 1px solid var(--st-line); box-sizing: border-box;
}
.concept-std .st-strip > nav, .concept-std .st-strip > .sub-tabbar {
  position: static; display: flex; align-items: center; gap: 4px; width: 100%; height: 100%;
  box-sizing: border-box; overflow-x: auto; scrollbar-width: none;
  margin: 0; padding: 0 8px; border: 0; border-radius: 0;
  background: var(--st-bg); mask-image: none; -webkit-mask-image: none;
}
.concept-std .st-strip > nav::-webkit-scrollbar { display: none; }
.concept-std .st-strip a {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  box-sizing: content-box; min-height: var(--st-size-chip); height: var(--st-size-chip);
  padding: 0 7px; font-size: 12px; font-weight: 600; white-space: nowrap;
  border: 0; border-radius: 0; background: var(--st-bg); color: var(--st-muted);
}
.concept-std .st-strip a[aria-current="page"] { color: var(--st-accent); box-shadow: inset 0 -2px var(--st-accent); }
.concept-std .st-strip[data-overflow] > nav {
  mask-image: linear-gradient(to right, var(--st-text) calc(100% - 24px), transparent);
}
.concept-std .st-overflow-cue {
  position: absolute; right: 0; top: 0; height: 100%; width: 18px;
  display: grid; place-items: center; pointer-events: none;
  color: var(--st-accent); background: var(--st-bg); font-size: 22px;
}

/* ---------- 6. The screen --------------------------------------------------
   The only thing on the page that scrolls. */

.concept-std > main.game-main {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
  width: 100%;
  max-width: none;
  padding: 10px 10px calc(12px + var(--st-safe-bottom));
  margin: 0;
  background: var(--st-bg);
  animation: none;
}

@keyframes st-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .concept-std > main.game-main { animation: none; }
  .concept-std .st-fold__chevron { transition: none; }
  .concept-std .st-toggle__knob { transition: none; }
}

/* ---------- 7. The bottom bar ----------------------------------------------
   Five destinations, built by ui/concept/standard/shell.js from core/nav.js's own
   mainNavItems — the same labels, hrefs and landing rules the classic strip
   uses, so the two navigations can never disagree about where a tap goes.

   SINCE 2026-09-10 ALL FIVE ARE PLACES. core/nav.js publishes five groups, the
   bar has five slots, and the last one is Social rather than a More button —
   so every destination the game has is one tap from every screen and the sheet
   in section 8 is not built at all. Those rules are kept for the day a sixth
   group arrives: mintNavPlan() folds the overflow away automatically and the
   fifth slot becomes More again. The grid below is repeat(5) either way. */

/* Above the More sheet, not under it: the bar is how the sheet is closed again,
   and a sheet that covers its own switch is a sheet with no way out. */
.concept-std > .st-nav {
  position: relative; z-index: 70;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0;
  height: calc(var(--st-size-bottombar) + var(--st-safe-bottom)); box-sizing: border-box;
  padding: 0 4px var(--st-safe-bottom);
  background: var(--st-bg);
  border-top: 1px solid var(--st-line);
}
.concept-std .st-nav__item {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  min-height: 0;
  padding: 4px 2px;
  border: 0; border-radius: 10px;
  background: none;
  color: var(--st-muted);
  font-family: inherit; font-size: 12px; line-height: 1.2; font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  position: relative;
}
.concept-std .st-nav__item:hover { color: var(--st-text); text-decoration: none; }
.concept-std .st-nav__label {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.concept-std .st-nav__item .st-icon { width: 22px; height: 22px; }
.concept-std .st-nav__item[aria-current="page"],
.concept-std .st-nav__item[aria-expanded="true"] { color: var(--st-accent); }
/* The mark under the active destination, exactly as the reference draws it. */
.concept-std .st-nav__item[aria-current="page"]::after {
  content: ""; position: absolute; left: 22%; right: 22%; bottom: -3px;
  height: 3px; border-radius: 3px; background: var(--st-accent);
}

/* ---------- 8. Sheets, and the overflow sheet ------------------------------
   .st-sheet is the kit's bottom sheet (ui/concept/standard/kit.js stSheet) and the
   map, the colony page and the order forms all open one — these rules are for
   every sheet in the layout.

   THE OVERFLOW SHEET IS THE ONE THAT IS NO LONGER BUILT. It used to be what the
   fifth slot opened: the way to the group with no slot of its own, holding
   app.js's own tab bar — the real node, not a copy. With five groups and five
   slots there is nothing to fold away, so the shell builds no sheet and no
   button for it. The `.st-sheet .tabbar` rules at the end of this section are
   the only ones that were only ever the overflow sheet's; they are kept beside
   the shell's own fold-away path, and they apply again the day core/nav.js
   grows a sixth group. */

.concept-std .st-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  max-height: 78dvh; overflow-y: auto; overscroll-behavior: contain;
  padding: 10px 12px calc(16px + var(--st-nav-h) + var(--st-safe-bottom));
  border: 1px solid var(--st-line); border-bottom: 0;
  border-radius: 24px 24px 0 0;
  background: var(--st-panel);
  color: var(--st-text);
  box-shadow: 0 -18px 40px rgba(0, 0, 0, .55);
}
.concept-std .st-sheet[hidden] { display: none; }
.concept-std .st-sheet__grabber {
  width: 44px; height: 5px; margin: 0 auto 10px;
  border-radius: 999px; background: var(--st-grabber);
}
.concept-std .st-sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin: 0 0 6px;
}
.concept-std .st-sheet__head .st-sheet__title { margin: 0; }
.concept-std .st-sheet__close { flex: none; }
.concept-std .st-sheet__title {
  margin: 0 0 8px; font-size: 17px; font-weight: 700; color: var(--st-text);
}
.concept-std .st-sheet__scrim {
  position: fixed; inset: 0; z-index: 55; background: var(--st-scrim);
  border: 0; padding: 0; cursor: pointer;
}
.concept-std .st-sheet__scrim[hidden] { display: none; }

/* app.js's own tab bar, inside the overflow sheet: a grid of rows rather than a
   sideways strip, because in a sheet there is width to spend and nothing to
   swipe. Inert while core/nav.js publishes five groups — see section 8's head. */
.concept-std .st-sheet .tabbar {
  position: static;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  overflow: visible;
  padding: 0; margin: 0 0 12px;
  background: none; border: 0; backdrop-filter: none;
}
.concept-std .st-sheet .tabbar a {
  display: flex; align-items: center; gap: 10px;
  min-height: var(--st-tap); padding: 0 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised);
  color: var(--st-text); font-size: 13px; font-weight: 600;
}
.concept-std .st-sheet .tabbar a[aria-current="page"] {
  border-color: var(--st-accent); color: var(--st-accent);
}
.concept-std .st-sheet .tabbar a img { width: 20px; height: 20px; }

/* ==========================================================================
   THE KIT — the primitives every mint screen is assembled from.
   Their DOM builders are ui/concept/standard/kit.js; the API is documented there.
   Prefer these over per-screen CSS: a screen that needs a new rule is a screen
   the kit is missing a piece for.
   ========================================================================== */

/* ---------- 9. Layout helpers ---------------------------------------------- */

.concept-std .st-stack { display: grid; gap: 6px; }
/* minmax(0, 1fr): the implicit `auto` track of a bare grid is as wide as the widest word in it. */
.concept-std .st-section { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; margin: 0 0 10px; }
.concept-std .st-section__title {
  margin: 0; font-size: var(--st-font-section); line-height: 1.25; font-weight: 750;
  letter-spacing: -.01em; color: var(--st-text);
}
.concept-std .st-section__sub { margin: 0; font-size: 13px; line-height: 1.35; color: var(--st-muted); }
.concept-std .st-muted { color: var(--st-muted); }
.concept-std .st-num { font-variant-numeric: tabular-nums lining-nums; }

.concept-std main.game-main .st-card { border-radius: var(--st-radius); }
.concept-std main.game-main .st-card__title { font-size: var(--st-font-section); }
.concept-std main.game-main .st-tile__value { font-size: 15px; font-variant-numeric: tabular-nums lining-nums; }
.concept-std .st-figure-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; }
.concept-std .st-figure-strip__value { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums lining-nums; }
/* Compact screen heads supersede the copied hero geometry while screens migrate.
   No art band or reserved image height on working screens. */
.concept-std main.game-main .st-hero {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 0; height: auto; padding: 0; border: 0; border-radius: 0;
  background: none; overflow: visible;
}
.concept-std main.game-main .st-hero::after,
.concept-std main.game-main .st-hero__img,
.concept-std main.game-main .st-hero__crest { display: none; }
.concept-std main.game-main .st-hero__body { position: static; padding: 0; }
.concept-std main.game-main .st-hero__title { font-size: var(--st-font-title); white-space: normal; overflow: visible; text-shadow: none; }
.concept-std main.game-main .st-hero__sub { color: var(--st-muted); text-shadow: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.concept-std .st-head { display: flex; align-items: center; gap: 4px; min-width: 0; }
.concept-std .st-head__title { flex: 0 1 auto; min-width: 0; margin: 0; font-size: var(--st-font-title); font-weight: 700; }
.concept-std .st-head__context { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--st-muted); }
.concept-std .st-head__actions { margin-left: auto; display: flex; gap: 4px; flex: none; }
.concept-std .st-head--detail { flex-wrap: wrap; }
.concept-std .st-head--detail .st-head__context { flex-basis: 100%; }
.concept-std .st-two-up { display: grid; gap: 8px; min-width: 0; }
@media (min-width: 1024px) {
  .concept-std .st-two-up { display: flex; flex-wrap: wrap; align-items: start; }
  #app.concept-std .st-two-up > * { flex: 1 1 max-content; min-width: calc(50% - 4px); max-width: 100%; }
}
.concept-std.st-print > .shell-header,
.concept-std.st-print > .st-strip,
.concept-std.st-print > .st-nav,
.concept-std.st-print .st-side,
.concept-std.st-print .st-desk > .shell-header,
.concept-std.st-print .st-detail-tabs,
.concept-std.st-print .shard-shutdown-strip,
.concept-std.st-print .combat-strip { display: none; }

/* ---------- 10. Hero -------------------------------------------------------
   A banner illustration with a gradient scrim and the title over it. The
   artwork is OPAQUE — the pack ships no alpha anywhere — so the scrim runs to
   the page background at the bottom edge and the image never floats. */

.concept-std .st-hero {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--st-radius);
  background: var(--st-panel);
  margin: 0 0 12px;
}
/* THE HEIGHT, measured off the reference rather than guessed. In
   references/02 the whole banner — art, back arrow, title, sub-line — is 405
   of 887px across a 360px-wide screen, i.e. 164 CSS px, and the art under it
   is about 132. It was 172px of art alone here, with the title's own band on
   top of that. */
.concept-std .st-hero__img {
  display: block; width: 100%;
  height: clamp(92px, 13vh, 128px);
  object-fit: cover;
}
.concept-std .st-hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(0deg, var(--st-bg) 2%, var(--st-hero-fade) 42%, transparent 78%);
}
.concept-std .st-hero__body {
  position: absolute; z-index: 1; left: 12px; right: 12px; bottom: 10px;
}
/* THE TOP ROW: back arrow, title, switcher — the shape reference 02 draws and
   the shape this kit had no slot for, which is why every detail screen was
   spending a 70px row of its own above the banner on a back link the hero
   should have carried. */
.concept-std .st-hero__head {
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.concept-std .st-hero__head .st-hero__title { flex: 1 1 auto; min-width: 0; }
/* The arrow and the switcher. A BARE GLYPH inside a full 48px tap box, which is
   how the reference draws them and how this skin's floor is kept at the same
   time: no chip, no border, nothing that reads as a second button beside the
   title. The words the arrow would have carried are its accessible name, which
   is where a back control's label belongs anyway. The negative margins pull the
   two hit boxes out to the hero's own edges, so the glyphs line up with the
   title rather than sitting 12px inside it. */
.concept-std .st-hero__back,
.concept-std .st-hero__switch > * {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--st-tap); height: var(--st-tap);
  min-width: var(--st-tap); min-height: var(--st-tap);
  padding: 0;
  border: 0; border-radius: 999px;
  background: none;
  color: var(--st-art-ink);
  text-decoration: none; cursor: pointer;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, .7));
}
.concept-std .st-hero__back { margin: 0 -4px 0 -10px; }
.concept-std .st-hero__switch > * { margin: 0 -10px 0 -4px; }
.concept-std .st-hero--plain .st-hero__back,
.concept-std .st-hero--plain .st-hero__switch > * {
  color: var(--st-text); filter: none;
}
.concept-std .st-hero__back:hover,
.concept-std .st-hero__switch > :hover { color: var(--st-accent); text-decoration: none; }
.concept-std .st-hero__back .st-icon,
.concept-std .st-hero__switch .st-icon { width: 26px; height: 26px; }
.concept-std .st-hero__switch { display: inline-flex; flex: none; }
/* 24px at 360px and 28 at 412, against the reference's 23.5. */
.concept-std .st-hero__title {
  margin: 0; font-size: clamp(19px, 5.6vw, 24px); line-height: 1.15;
  font-weight: 750; letter-spacing: -.02em; color: var(--st-art-ink);
  overflow-wrap: anywhere;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .7);
}
.concept-std .st-hero__sub {
  margin: 2px 0 0; font-size: 14px; line-height: 1.3; color: var(--st-art-ink-2);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .7);
}
.concept-std .st-hero__pills {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px;
}
/* A HERO WITH NO ARTWORK IS STILL A HEADER. The body is absolutely positioned
   over the banner and the height came entirely from the image, so a hero built
   with a title and no art — or with an art key the catalog does not carry,
   which is the same thing from the screen's side — collapsed to 0px and took
   the screen's own <h1> off the page with it.

   The plain form puts the body back in normal flow over a gradient backdrop
   and floors the block, so "title only" is a proper header rather than a gap.
   The crest joins the flow too: absolutely positioned it would have sat on top
   of the title once the body stopped being pinned to the bottom of an image. */
.concept-std .st-hero--plain {
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 104px;
  border: 1px solid var(--st-line);
  background:
    radial-gradient(120% 120% at 10% 0%, var(--st-hero-glow), transparent 60%),
    linear-gradient(160deg, var(--st-panel-raised), var(--st-panel) 62%, var(--st-bg));
}
/* The scrim exists to lift the title off a photograph. There is no photograph
   here, and over the gradient it only muddies it. */
.concept-std .st-hero--plain::after { background: none; }
.concept-std .st-hero--plain .st-hero__body {
  position: static; left: auto; right: auto; bottom: auto; padding: 12px;
}
.concept-std .st-hero--plain .st-hero__crest {
  position: static; margin: 10px 0 -4px 12px;
}

/* The empire's crest, dropped on the hero the way the reference drops a
   pennant on the banner.

   TOP-RIGHT, NOT TOP-LEFT, AND THIS IS A FIX. The body is pinned to the BOTTOM
   of the banner and the banner is `clamp(92px, 13vh, 128px)` tall, so on a
   short viewport the title's first line rises to within a few pixels of the
   top — and a crest at top-LEFT had the empire's name running straight through
   it. Measured on a 432x768 phone: banner 100px, body 80px, title top 10px,
   crest 10-50px. The same collision the `--plain` note below already describes,
   arriving from the other direction.

   The corner moves and the head row keeps the badge's width clear, so a name
   long enough to wrap still stops short of it instead of sliding underneath.
   `--plain` is excluded: its crest is in normal flow at the left and has no
   corner to collide in. */
.concept-std .st-hero:not(.st-hero--plain) .st-hero__crest { left: auto; right: 10px; }
.concept-std .st-hero:not(.st-hero--plain) .st-hero__crest ~ .st-hero__body > .st-hero__title,
.concept-std .st-hero:not(.st-hero--plain) .st-hero__crest ~ .st-hero__body > .st-hero__head {
  padding-right: 48px;
}
.concept-std .st-hero__crest {
  position: absolute; z-index: 1; top: 10px; left: 10px;
  width: 40px; height: 40px;
  padding: 4px;
  border: 1px solid var(--st-hero-edge);
  border-radius: 10px;
  background: var(--st-glass);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}
.concept-std .st-hero__crest img { width: 100%; height: 100%; object-fit: contain; }

/* ---------- 11. Cards ------------------------------------------------------ */

.concept-std .st-card {
  padding: 10px;
  border: 1px solid var(--st-line); border-radius: 8px;
  background: var(--st-panel);
  min-width: 0;
}
.concept-std .st-card--raised { background: var(--st-panel-raised); }
.concept-std .st-card--flush { padding: 6px 10px; }
.concept-std .st-card__title {
  margin: 0 0 6px; font-size: 13.5px; font-weight: 700; line-height: 1.25;
  color: var(--st-text);
  display: flex; align-items: center; gap: 6px;
}
.concept-std .st-card__title .st-icon { width: 20px; height: 20px; }
.concept-std .st-card__note {
  margin: 6px 0 0; font-size: 13px; line-height: 1.35; color: var(--st-muted);
}

/* ---------- 11b. Folds -----------------------------------------------------
   A card that is shut until it is tapped. <details>/<summary> rather than a
   button and a class, because the browser already owns "this is collapsed": it
   takes the hidden rows out of the tab order and out of the accessibility tree
   by itself, and it works before a line of this skin's JavaScript has run.

   Nothing is remembered between renders, on purpose. The card this exists for
   is the "not on this layout yet" honesty card, which on a 360px phone was the
   tallest block on several screens — and a fold that remembered would be a fold
   found open on a screen the player never opened it on.

   Loaded after .st-card at the same weight, so the padding reset below wins. */
.concept-std .st-fold { padding: 0; overflow: hidden; }
.concept-std .st-fold__summary {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--st-tap); padding: 4px 12px;
  list-style: none; cursor: pointer;
  color: var(--st-text); font-size: 15px; font-weight: 700; line-height: 1.25;
}
.concept-std .st-fold__summary::-webkit-details-marker { display: none; }
.concept-std .st-fold__summary::marker { content: ""; }
.concept-std .st-fold__title { min-width: 0; overflow-wrap: anywhere; }
.concept-std .st-fold__count {
  flex: none; font-size: 12px; font-weight: 600; color: var(--st-muted);
  font-variant-numeric: tabular-nums;
}
.concept-std .st-fold__chevron {
  flex: none; margin-left: auto; color: var(--st-muted);
  transition: transform .15s ease;
}
.concept-std .st-fold[open] .st-fold__chevron { transform: rotate(180deg); }
.concept-std .st-fold__body { padding: 0 12px 12px; }

/* ---------- 12. Tiles ------------------------------------------------------
   Icon, label, value, optional meter. Laid out 2-up or 3-up; below 340px they
   fall to one column rather than truncating a number. */

.concept-std .st-tiles {
  display: grid; gap: 8px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.concept-std .st-tiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Four across on a 360px phone leaves ~78px a tile, so this row spends less on
   the gap than the two- and three-up ones do. */
.concept-std .st-tiles--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }

.concept-std .st-tile {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 64px; padding: 8px 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised);
  color: var(--st-text); text-decoration: none;
  min-width: 0;
}
.concept-std a.st-tile:hover { border-color: var(--st-accent); text-decoration: none; }
/* A PRESSABLE TILE GOT NOTHING BACK. stTile turns an onclick into a <button>,
   and only the link form had a hover state — so the colony page's Population
   and Housing tiles, which open a pop-up each, looked like the blocks beside
   them. Same border as the link's, and the chevron below says it in ink. */
.concept-std button.st-tile:hover { border-color: var(--st-accent); }
/* AND A BUTTON CENTRES ITS TEXT. Every other tile is a div or an anchor, so the
   head row's label — the one box on a tile wide enough to show it, since the
   label carries the flex-grow — inherited the page's left. Turning the same
   tile into a button slid its label into the middle of the tile. The stacked
   picker is excluded rather than overridden: centred is what it is FOR. */
.concept-std button.st-tile:not(.st-tile--stacked) { text-align: left; }
/* The chevron on a tile that opens a pop-up. It rides in the head row, where the
   label's own flex-grow already pushes it to the right edge — not on a line of
   its own, which is what would cost a compact tile its height. Muted and 14px:
   the affordance is the shape, not a second accent colour on the tile. */
.concept-std .st-tile__more { flex: none; display: inline-flex; color: var(--st-muted); }
.concept-std .st-tile__more .st-icon { width: 14px; height: 14px; }
/* THE HEAD ROW is what makes a tile 88px rather than 150. The reference sets a
   tile in three lines — glyph and label together, the number under them, the
   change or the meter under that — and this kit was setting it in four, one of
   them a 32px glyph on a line of its own. */
.concept-std .st-tile__head {
  display: flex; align-items: center; gap: 6px;
  width: 100%; min-width: 0;
}
.concept-std .st-tile__head .st-tile__label { flex: 1 1 auto; }
.concept-std .st-tile__icon { flex: none; display: inline-flex; color: var(--st-link); }
.concept-std .st-tile__icon .st-icon { width: 18px; height: 18px; }
.concept-std .st-tile__value {
  font-size: 18px; line-height: 1.15; font-weight: 750; font-variant-numeric: tabular-nums;
}
/* Compact tiles: action pickers and condition strips, where the reference draws ~56px.
   Declared AFTER .st-tile and .st-tile__value on purpose: same specificity, later wins. */
.concept-std .st-tile--compact { min-height: 56px; padding: 6px 10px; }
.concept-std .st-tile--compact .st-tile__value { font-size: 16px; }
/* "10,600 / 17,000" is 165px at 20px bold and a two-up tile is 146px wide on a
   360px phone. The kit adds this from the string LENGTH, which is the only
   thing available before layout. */
.concept-std .st-tile__value--long { font-size: 16px; letter-spacing: -.01em; }
/* The label WRAPS to a second line rather than ellipsing on the first. At two
   and three columns on a 360px phone a tile is 78-160px wide and the labels the
   game hands it are things like "Orbital shipyard" and "Population growth" — an
   ellipsis there hides the word that says what the number is, which is the only
   part of a tile a player cannot infer. The tile floors at 84px, so a second
   line costs the grid nothing. */
.concept-std .st-tile__label {
  font-size: 13px; line-height: 1.2; color: var(--st-muted);
  max-width: 100%; overflow-wrap: anywhere;
}
/* The change line: "+7 last tick". Coloured BY SIGN and never by colour alone —
   the sign is in the text the caller formatted, which is what a screen reader
   and a colour-blind player both read. */
.concept-std .st-tile__delta {
  font-size: 12px; font-weight: 650; line-height: 1.2; color: var(--st-muted);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.concept-std .st-tile__delta--up   { color: var(--st-success); }
.concept-std .st-tile__delta--down { color: var(--st-danger); }
/* Locked: an action a player cannot take YET keeps its place in the picker and
   says so, instead of vanishing — a picker that hides what it cannot do teaches
   nobody how to unlock it. Dimmed with the muted TOKEN rather than with
   opacity, so the label stays above the contrast floor while looking off. */
.concept-std .st-tile--locked {
  background: var(--st-panel);
  border-style: dashed;
  color: var(--st-muted);
  cursor: default;
}
.concept-std .st-tile--locked .st-tile__icon,
.concept-std .st-tile--locked .st-tile__value { color: var(--st-muted); }
.concept-std .st-tile__lock {
  position: absolute; top: 6px; right: 6px;
  color: var(--st-muted);
}
.concept-std .st-tile__meter { width: 100%; margin-top: 2px; }
/* The reference's next-tick tiles: glyph over a centred label and count. The
   padding is 4px rather than 12px on the sides because at four across the tile
   is ~78px wide and "Construction" needs ~62px of it — at the card padding the
   word broke mid-syllable ("Constr / uction"), which reads as a bug. */
.concept-std .st-tile--stacked {
  align-items: center; justify-content: center; text-align: center;
  padding: 8px 4px;
}
/* The stacked tile keeps a bigger glyph: it is the only thing on it a player
   reads from across the screen. */
.concept-std .st-tile--stacked .st-tile__icon .st-icon { width: 26px; height: 26px; }
/* At four columns on a 360px phone each tile is ~72px wide and "Construction"
   is 88px. The label WRAPS rather than truncating: a category the player cannot
   read is a breakdown that explains nothing. */
.concept-std .st-tile--stacked .st-tile__label {
  font-size: 11px; line-height: 1.2; letter-spacing: -.01em; color: var(--st-text);
  white-space: normal; overflow: visible; overflow-wrap: normal; text-align: center;
}
.concept-std .st-tile--stacked .st-tile__value { font-size: 17px; color: var(--st-muted); font-weight: 650; }

/* ---------- 13. Meter ------------------------------------------------------ */

.concept-std .st-meter { display: flex; align-items: center; gap: 8px; min-width: 0; }
.concept-std .st-meter__track {
  flex: 1 1 auto; height: 6px; min-width: 0;
  border-radius: 999px; background: var(--st-track); overflow: hidden;
}
.concept-std .st-meter__fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--st-accent);
}
.concept-std .st-meter--warn .st-meter__fill   { background: var(--st-warning); }
.concept-std .st-meter--danger .st-meter__fill { background: var(--st-danger); }
.concept-std .st-meter--good .st-meter__fill   { background: var(--st-success); }
.concept-std .st-meter__pct {
  flex: none; font-size: 12px; color: var(--st-muted); font-variant-numeric: tabular-nums;
}

/* ---------- 14. Segmented control ------------------------------------------
   TWO SHAPES. The default is one row that scrolls sideways; `--wrap` is chips
   on as many rows as they need. Which one a screen wants is about how many
   items it has: four is where a 360px phone stops fitting them in a row, and
   past that a scroller hides options behind a gesture nobody makes. */

.concept-std .st-segment {
  position: relative;
  display: flex; gap: 3px; padding: 3px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel);
  overflow-x: auto; scrollbar-width: none;
}
.concept-std .st-segment::-webkit-scrollbar { display: none; }
/* The edge fade, on the strips that have more items than a phone shows at once
   (ui/concept/standard/kit.js adds the class from the item COUNT — CSS cannot ask
   whether a box overflows). A MASK and not a gradient background: a background
   image on this box would make every label inside it a contrast the render
   harness can no longer resolve, and an admitted-unknown is worse here than no
   fade at all. The strip is still fully reachable by scrolling; the fade only
   says there is more. */
.concept-std .st-segment--scroll {
  -webkit-mask-image: linear-gradient(90deg, rgba(0, 0, 0, 1) calc(100% - 22px), rgba(0, 0, 0, .25));
  mask-image: linear-gradient(90deg, rgba(0, 0, 0, 1) calc(100% - 22px), rgba(0, 0, 0, .25));
}
/* Chips. They keep their own width, wrap to a second row, and never shrink
   under the tap floor — 48px wide and 44px tall, whatever the label. */
.concept-std .st-segment--wrap {
  flex-wrap: wrap; overflow-x: visible;
  -webkit-mask-image: none; mask-image: none;
}
.concept-std .st-segment--wrap .st-segment__item { flex: 0 0 auto; min-width: 48px; }
.concept-std .st-segment__item {
  flex: 1 1 0; min-width: max-content;
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: content-box; min-height: 24px; height: 24px; padding: 0 12px;
  border: 0; border-radius: 8px;
  /* The panel again rather than `none`, and it is load-bearing: the strip's own
     background is what a contrast check would otherwise have to walk up to, and
     an opaque item makes every label's background answerable from the item
     itself. It is the same colour, so nothing moves. */
  background: var(--st-panel);
  color: var(--st-muted);
  font-family: inherit; font-size: 13px; font-weight: 650; white-space: nowrap;
  text-decoration: none; cursor: pointer;
}
/* The label carries the width floor, not the item: a 20px floor on the text
   plus the item's 28px of padding is 48px for a one- or two-character chip
   (`All`, `T7`, `x3`), without capping a long label or making equal-width items
   unequal when there is room for them. */
.concept-std .st-segment__label {
  display: inline-block; min-width: 20px; text-align: center;
  /* A chip can carry a fleet tag a player typed. The cap is the viewport's, because the item's
     min-width: max-content would beat any cap on the item itself. */
  max-width: calc(100vw - 64px); overflow: hidden; text-overflow: ellipsis;
}
/* THE COMPACT STRIP, for a screen whose tabs are the whole navigation of a page
   rather than a filter over one. The colony page has four of them — Overview,
   Build, Shipyard, Manager — and at the default 12px of side padding and 13px
   type they measured wider than a 360px phone and slid under the thumb. Tighter
   padding and one step down of type is the whole modifier; the 44px TAP box is
   untouched, because that is the number a thumb and the render harness both
   measure. */
.concept-std .st-segment--compact .st-segment__item {
  padding: 0 6px;
  font-size: 12px;
  letter-spacing: 0;
}
.concept-std .st-segment--compact .st-segment__label { min-width: 0; }

.concept-std .st-segment__item:hover { color: var(--st-text); text-decoration: none; }
.concept-std .st-segment__item[aria-selected="true"],
.concept-std .st-segment__item[aria-current="page"] {
  background: var(--st-accent); color: var(--st-accent-ink);
}

/* ---------- 15. Rows -------------------------------------------------------
   The workhorse: leading art or icon, a title, a sub-line, a trailing value or
   chevron. Every row is a full tap target. */

.concept-std .st-rows {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 6px;
}
.concept-std .st-row {
  display: flex; align-items: center; gap: 10px;
  min-height: var(--st-tap); padding: 4px 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel);
  color: var(--st-text); text-decoration: none;
  min-width: 0;
}
.concept-std a.st-row:hover,
.concept-std button.st-row:hover { border-color: var(--st-accent); text-decoration: none; }
.concept-std button.st-row { width: 100%; font: inherit; text-align: left; cursor: pointer; }
/* A ROW THAT IS NOT A TAP TARGET DOES NOT NEED A TAP TARGET'S HEIGHT. stRow
   returns a <div> when it is given neither an href nor a handler — a storage
   line, a construction summary, a meter row — and 48px on those was the tap
   floor being paid by things nobody taps. 40px is what reference 02 measures
   for the same rows. The element selector is what keeps this exact: an <a> or a
   <button> row keeps the full --st-tap floor above. */
.concept-std div.st-row { min-height: 40px; }
.concept-std .st-row--plain { border: 0; background: none; padding-left: 0; padding-right: 0; }
.concept-std .st-row__lead {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 8px; overflow: hidden;
  background: var(--st-panel-raised);
  color: var(--st-link);
}
.concept-std .st-row__lead img { width: 100%; height: 100%; object-fit: cover; }
/* A round mark in a row's lead (Profile's Portrait and Emblem) gets the whole disc it asks for. In the 30 px box it was
   40 px tall and 30 wide with `cover` on, which cut an eighth off each side of the art. */
.concept-std .st-row__lead:has(> .identity-round-mark) { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%; }
.concept-std .st-row__lead > .identity-round-mark[src*="identity/emblems/"] { object-fit: contain; }
/* The lead's glyph is asked for at `lg` by the kit; inside a 30px thumb it is
   this size instead, which is one rule rather than a change of argument at
   every call site. */
.concept-std .st-row__lead .st-icon { width: 20px; height: 20px; }
/* THE BODY IS A WRAPPING FLEX ROW, and that is what puts a storage row on one
   line at 360px the way reference 02 does: "Raw Ore" and "+9/tick" sit beside
   each other when they fit and the sub drops to its own line when they do not.
   It was a block, so a two-word sub always cost a second line — the single
   biggest reason a colony page ran to two and a half screens. */
.concept-std .st-row__body {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px;
}
/* Both lines are <span>s (a row may be an <a>, and a <div> inside a link is
   invalid), so they are made blocks here rather than run together. */
.concept-std .st-row__title {
  display: block; flex: 0 1 auto; min-width: 0;
  font-size: 15px; font-weight: 650; line-height: 1.3; overflow-wrap: anywhere;
}
.concept-std .st-row__sub {
  display: block; flex: 0 1 auto; min-width: 0;
  font-size: 13px; line-height: 1.3; color: var(--st-muted); overflow-wrap: anywhere;
}
/* A sub nested inside a sub — colonies.js builds one that way, a nowrap
   location over a status pill — is back to being a plain block: it is a line of
   its own inside its parent's flex item, not a second item on the row. */
.concept-std .st-row__sub .st-row__sub { flex: none; width: 100%; }
/* Pills get a LINE OF THEIR OWN under the sub-line, and that is the whole
   reason the slot exists. A pill is an inline-flex box, and a run of them
   dropped into wrapping prose makes the sentence break wherever the box lands —
   "Planet 1" came out as "Planet" on one line and "1" on the next at 360px. */
.concept-std .st-row__pills {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px;
  flex: 1 0 100%;
}
.concept-std .st-row__meter { display: block; margin-top: 4px; flex: 1 0 100%; }
/* The same, for the two screens that drop a bare stMeter into a row body
   instead of going through the slot (the battle report's meter rows). A meter
   is a box, and a box on a wrapping text line is the thing this row's flex was
   NOT for. */
.concept-std .st-row__body > .st-meter { flex: 1 0 100%; margin-top: 4px; }
/* A TITLE THAT CARRIES A PILL takes the whole line. The system page's
   suitability rows put the verdict inside the title and space-between it to the
   right edge, which needs the title to be the full width of the body — as a
   shrink-to-fit flex item the verdict simply wrapped under the axis name. */
.concept-std .st-row__title:has(.st-pill) { flex: 1 1 100%; }
/* Right-aligned, and it is a column rather than a word at the end of the body:
   the reference lines every amount up on the card's right edge. */
.concept-std .st-row__value {
  flex: none; margin-left: auto; text-align: right;
  /* A number stays whole; a name in this slot, which can be any player's, wraps at the cap. */
  max-width: 70%; overflow-wrap: anywhere;
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.concept-std .st-row__chevron { flex: none; color: var(--st-muted); }

/* A row with a control beside it. The control is a SIBLING of the row, never a
   child: the row is usually a link, and a button inside a link is a button
   neither a pointer nor a screen reader can reliably reach. */
.concept-std .st-rowset { display: flex; align-items: center; gap: 6px; min-width: 0; }
.concept-std .st-rowset > :first-child { flex: 1 1 auto; min-width: 0; }
.concept-std .st-icon-btn {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--st-tap); height: var(--st-tap);
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel);
  color: var(--st-muted);
  cursor: pointer;
}
.concept-std .st-icon-btn:hover { color: var(--st-text); }

/* ---------- 16. Attention rows --------------------------------------------
   The same row, toned. The tone is on the BORDER and a tint of the background,
   never on the text alone — colour is not a status for anyone who cannot
   separate the red from the amber, so the row always says what it is in words
   too. */

.concept-std .st-alert { border-width: 1px; }
/* A SOLID TINT, not a gradient of one opaque colour laid over the panel twice.
   The two paint identically — --st-*-bg is an opaque hex in both themes, so the
   panel underneath it was never visible — but a background-IMAGE is a background
   no contrast check can resolve from styles, and every toned row in the skin was
   coming back "contrast unknown" in the render harness. Same pixels, provable. */
.concept-std .st-alert--warn {
  border-color: var(--st-warning);
  background: var(--st-warning-bg);
}
.concept-std .st-alert--warn .st-row__lead  { color: var(--st-warning); background: var(--st-warning-dim); }
.concept-std .st-alert--danger {
  border-color: var(--st-danger);
  background: var(--st-danger-bg);
}
.concept-std .st-alert--danger .st-row__lead { color: var(--st-danger); background: var(--st-danger-dim); }
.concept-std .st-alert--info .st-row__lead   { color: var(--st-link); }

/* ---------- 17. Call to action --------------------------------------------- */

.concept-std .st-cta {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: var(--st-tap); padding: 8px 14px;
  border: 1px solid var(--st-accent); border-radius: var(--st-radius-sm);
  background: var(--st-accent);
  color: var(--st-accent-ink);
  font-family: inherit; font-size: 14px; font-weight: 750;
  text-decoration: none; cursor: pointer;
  touch-action: manipulation;
}
.concept-std .st-cta:hover { color: var(--st-accent-ink); text-decoration: none; filter: brightness(1.06); }
.concept-std .st-cta--quiet {
  background: var(--st-panel-raised); color: var(--st-text); border-color: var(--st-line);
}
/* A DISABLED CTA IS THE QUIET SHAPE, not the accent one faded out. The old
   rule dimmed --st-accent-ink on --st-accent to opacity .55, which measured
   3.16:1 — under the 4.5:1 floor — and a button whose label a player cannot
   read is a button that cannot tell them why it is off. Full opacity, panel
   under muted, 8:1. The reason for the disabling goes in the caption. */
.concept-std .st-cta[aria-disabled="true"] {
  opacity: 1;
  background: var(--st-panel-raised);
  border-color: var(--st-line);
  color: var(--st-muted);
  pointer-events: none;
  cursor: default;
}
/* AN ADVISED CTA IS DIMMED AND STILL PRESSABLE. It wears aria-disabled for the
   look and for the announcement, exactly as core/gate.js advisedAction() does —
   but the owner's rule is that the client never REFUSES an order it merely
   expects the server to reject, so the pointer-events lock above must not reach
   it. The warn border is what separates it from the ordinary quiet button: this
   one is dim because it is likely to fail, not because it is secondary. */
.concept-std .st-cta--advised[aria-disabled="true"] {
  pointer-events: auto;
  cursor: pointer;
  border-color: var(--st-warning);
  color: var(--st-text);
}
.concept-std .st-cta-caption {
  margin: 4px 0 0; font-size: 13px; line-height: 1.35; color: var(--st-muted); text-align: center;
}
.concept-std .st-cta-caption--warn { color: var(--st-warning); }

/* ---------- 17b. Fields and inputs -----------------------------------------
   The two shapes the kit needed the day a value had to be TYPED on a screen
   rather than in an order modal: renaming a colony, setting a population cap,
   moving a supply line. Everything expands in place on this skin, so there is
   no dialog to borrow the classic form controls from — and a bare <input>
   inside the frame inherits the browser's own white box.

   The box is a tap target like every other control here: --st-tap, the same
   floor a row and a call-to-action sit on. */

.concept-std .st-field { display: grid; gap: 4px; }
.concept-std .st-field__label {
  font-size: 13px; font-weight: 650; color: var(--st-muted);
}
.concept-std .st-field__hint {
  margin: 0; font-size: 12px; line-height: 1.35; color: var(--st-muted); overflow-wrap: anywhere;
}
/* The error REPLACES the hint rather than stacking under it. */
.concept-std .st-field__error {
  margin: 0; font-size: 12px; line-height: 1.35; color: var(--st-danger); overflow-wrap: anywhere;
}
.concept-std .st-input {
  width: 100%; min-height: var(--st-tap); padding: 8px 10px;
  border: 1px solid var(--st-edge-ui); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised);
  color: var(--st-text);
  font-family: inherit; font-size: 15px; line-height: 1.3;
  font-variant-numeric: tabular-nums;
}
.concept-std .st-input::placeholder { color: var(--st-muted); opacity: 1; }
.concept-std .st-input:disabled { color: var(--st-muted); background: var(--st-panel); }
.concept-std .st-input:focus-visible { border-color: var(--st-accent); outline: none; }
.concept-std .st-input[aria-invalid="true"] { border-color: var(--st-danger); }
/* A slider is one property away from being themed: accent-color paints the
   track and the thumb from the palette, so the Astral theme gets an orange one
   without a rule of its own. The box keeps the tap floor and loses the border,
   because a bordered box round a slider reads as a text field. */
.concept-std .st-input--range {
  padding: 0; border: 0; background: none;
  accent-color: var(--st-accent);
}

/* ---------- 18. Pills ------------------------------------------------------ */

.concept-std .st-pill {
  display: inline-flex; align-items: center; gap: 4px;
  max-width: 100%; padding: 2px 8px;
  border: 1px solid currentColor; border-radius: 999px;
  font-size: 11px; line-height: 1.35; font-weight: 600; color: var(--st-muted);
  font-variant-numeric: tabular-nums;
  background: var(--st-glass-soft);
}
.concept-std .st-pill--accent  { color: var(--st-accent);  background: var(--st-accent-bg); }
.concept-std .st-pill--good    { color: var(--st-success); background: var(--st-success-bg); }
.concept-std .st-pill--warn    { color: var(--st-warning); background: var(--st-warning-bg); }
.concept-std .st-pill--danger  { color: var(--st-danger);  background: var(--st-danger-bg); }

/* A row of pills OUTSIDE a hero. stHero has its own; everywhere else a screen
   was building a bare div and hoping it wrapped, which it does not — a run of
   inline-flex pills in a block box runs off the side of the card instead. */
.concept-std .st-pills { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---------- 18b. Back link -------------------------------------------------
   "< Colonies", at the top of a detail screen. A primitive rather than five
   hand-composed copies, because every copy has to get the same three things
   right: a 48px tap box, a glyph that is decoration beside the words rather
   than the label itself, and a hit area that reaches the card's left edge
   instead of starting 12px inside it. */
.concept-std .st-back {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--st-tap); min-width: var(--st-tap);
  margin: 0 0 6px -8px; padding: 0 10px 0 8px;
  border: 0; border-radius: var(--st-radius-sm);
  background: none;
  color: var(--st-muted);
  font-family: inherit; font-size: 14px; font-weight: 650;
  text-decoration: none; cursor: pointer;
}
.concept-std .st-back:hover { color: var(--st-text); text-decoration: none; }
.concept-std .st-back__label { min-width: 0; overflow-wrap: anywhere; }

/* ---------- 19. Timeline ---------------------------------------------------
   The vertical stepper the research mock uses: a rail, a node per step, and
   the step's own card beside it. */

.concept-std .st-timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.concept-std .st-timeline__step {
  position: relative;
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px;
  padding: 0 0 10px;
}
.concept-std .st-timeline__rail {
  position: relative;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 4px;
}
/* The line between one node and the next. Drawn on the step, not between
   steps, so the last one simply does not draw it. */
.concept-std .st-timeline__step:not(:last-child) .st-timeline__rail::after {
  content: ""; position: absolute; top: 18px; bottom: -10px; width: 2px;
  background: var(--st-line);
}
.concept-std .st-timeline__node {
  position: relative; z-index: 1;
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--st-line); background: var(--st-bg);
}
.concept-std .st-timeline__step--done .st-timeline__node    { border-color: var(--st-success); background: var(--st-success); }
.concept-std .st-timeline__step--active .st-timeline__node  { border-color: var(--st-accent);  background: var(--st-accent); }
.concept-std .st-timeline__body { min-width: 0; }
/* Both lines are <span>s — a step may be a link, and a <div> inside an <a> is
   invalid — so they are made blocks here rather than run together. Without this
   a step read "Fusion PlantsComplete" on one line, which is section 15's rule
   for st-row and was simply missing from this one. */
.concept-std .st-timeline__title {
  display: block;
  font-size: 15px; font-weight: 650; line-height: 1.3; overflow-wrap: anywhere;
}
.concept-std .st-timeline__sub {
  display: block;
  font-size: 13px; line-height: 1.3; color: var(--st-muted); overflow-wrap: anywhere;
}
/* A step's own glyph. Inline rather than a flex child, so a step WITHOUT one
   lays out exactly as it always has. */
.concept-std .st-timeline__glyph { margin-right: 6px; color: var(--st-link); }
/* A step that goes somewhere. The body becomes the link, so the whole line is
   the tap target rather than the four words in the middle of it. */
.concept-std .st-timeline__body--link {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px;
  color: var(--st-text); text-decoration: none;
}
.concept-std .st-timeline__body--link:hover { color: var(--st-accent); text-decoration: none; }
.concept-std .st-timeline__text { flex: 1 1 auto; min-width: 0; }
.concept-std .st-timeline__chevron { flex: none; color: var(--st-muted); }

/* ---------- 20. Icons ------------------------------------------------------
   Sprite symbols, coloured by `currentColor` — which is the whole reason they
   are a sprite and not 75 <img> files. */

.concept-std .st-icon {
  width: 24px; height: 24px; flex: none;
  display: inline-block; vertical-align: middle;
  color: inherit;
}
.concept-std .st-icon--lg { width: 28px; height: 28px; }
.concept-std .st-icon--sm { width: 16px; height: 16px; }

/* Framed artwork. `cover` on a banner, `contain` on an object — the pack's
   objects are centred on their own navy field and cropping one cuts the thing
   the tile is about. */
.concept-std .st-art {
  display: block; width: 100%; border-radius: var(--st-radius-sm);
  background: var(--st-panel);
}
.concept-std .st-art--banner { height: clamp(92px, 13vh, 128px); object-fit: cover; }
/* Inside a hero the hero's own height rule is the one that counts; this rule sits later in the
   file at equal specificity and was quietly winning (every banner drew 150px, not 144). */
.concept-std .st-hero__img.st-art--banner { height: clamp(92px, 13vh, 128px); }
.concept-std .st-art--object { aspect-ratio: 1; object-fit: contain; }

/* ---------- 20b. Form controls ---------------------------------------------
   The kit had no way to draw a control, so every screen that needed one drew it
   by hand and each one landed at a different height. One 48px floor, one
   border, one focus ring — and the elements underneath are the platform's own
   select, input and textarea, which already own the keyboard, the picker and
   the accessibility a re-implementation would have to earn back. */

/* The native arrow is drawn in the UA's own colour, which on a dark panel is a
   black wedge on navy. `color-scheme` is the one declaration that tells the
   platform this control lives on a dark surface, and it fixes the arrow, the
   colour picker's chrome and the number spinner in one line. */
.concept-std .st-select,
.concept-std .st-colour,
.concept-std .st-input { color-scheme: dark; }
.concept-std .st-select { cursor: pointer; }
.concept-std .st-textarea { min-height: 88px; resize: vertical; line-height: 1.4; }

.concept-std .st-colour {
  flex: none; width: var(--st-tap); height: var(--st-tap); padding: 3px;
  border: 1px solid var(--st-edge-ui); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised); cursor: pointer;
}

/* NOT the call to action: this is the Save beside a field and one of a row of
   three, so it hugs its own label instead of filling the card. */
.concept-std .st-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: var(--st-tap); padding: 6px 12px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised); color: var(--st-text);
  font-family: inherit; font-size: 14px; font-weight: 650; line-height: 1.2;
  text-decoration: none; cursor: pointer; touch-action: manipulation;
}
.concept-std .st-btn:hover { border-color: var(--st-accent); text-decoration: none; color: var(--st-text); }
.concept-std .st-btn--primary {
  background: var(--st-accent); border-color: var(--st-accent); color: var(--st-accent-ink);
}
.concept-std .st-btn--danger { color: var(--st-danger); border-color: var(--st-danger); }
/* Same rule as the disabled CTA, same reason: the quiet shape at full opacity,
   never the accent one faded under the contrast floor. */
.concept-std .st-btn[aria-disabled="true"],
.concept-std .st-btn:disabled {
  opacity: 1; background: var(--st-panel); border-color: var(--st-line);
  color: var(--st-muted); pointer-events: none; cursor: default;
}
.concept-std .st-actions {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; margin-top: 8px; min-width: 0;
}

/* The eight colour codes a player marks systems with (core/mapMarks.js).

   FOUR ACROSS, and the grid says so rather than letting flex-wrap decide: eight
   buttons on a 360px phone is 45px each before any gap, and each one carries the
   code's word under its swatch. Two rows of four gives every button the tap
   floor and its label room to be read.

   The swatch is a RING, not a filled dot, because a ring is what the chart draws
   around a marked system — the control looks like the mark it makes. Its colour
   is set inline from the palette in force, so a colour-vision mode changes both
   the ring and this swatch through one door. */
.concept-std .st-marks {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin-top: 6px;
}
.concept-std .st-mark {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--st-tap); min-width: 0; padding: 4px 2px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised); color: var(--st-text);
  font-family: inherit; font-size: 11px; font-weight: 650; line-height: 1.1;
  cursor: pointer; touch-action: manipulation;
}
.concept-std .st-mark:hover { border-color: var(--st-accent); }
/* The pressed state is the code's own colour on the border (set inline) plus a
   lit surface, so "this system is marked" is legible without relying on the
   2px border alone — which is the one cue a monochrome player would lose. */
.concept-std .st-mark[aria-pressed="true"] { background: var(--st-panel-3); }
.concept-std .st-mark__dot {
  display: block; width: 16px; height: 16px; flex: none;
  border: 2.5px solid var(--st-line); border-radius: 50%;
}
.concept-std .st-mark__label {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* One row of the rename dialog: the code's ring, then the field it names. */
.concept-std .st-mark-row {
  display: flex; align-items: center; gap: 8px; margin-top: 6px; min-width: 0;
}
.concept-std .st-mark-row .st-input { flex: 1; min-width: 0; }

/* ---------- 20c. In-place disclosure ---------------------------------------
   A ROW that opens where it stands — the shot list's working, the fleet-by-fleet
   line's numbers. Same <details> machinery as the fold, row geometry instead of
   card geometry, and deliberately no sheet: the answer appears under the line
   that raised the question. */

.concept-std .st-disclosure {
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel); overflow: hidden;
}
.concept-std .st-disclosure__summary {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--st-tap); padding: 4px 10px;
  list-style: none; cursor: pointer; color: var(--st-text);
}
.concept-std .st-disclosure__summary::-webkit-details-marker { display: none; }
.concept-std .st-disclosure__summary::marker { content: ""; }
.concept-std .st-disclosure__lead {
  flex: none; width: 24px; height: 24px; display: grid; place-items: center;
  border-radius: 6px; background: var(--st-panel-raised); color: var(--st-link);
}
.concept-std .st-disclosure__text { flex: 1 1 auto; min-width: 0; display: block; }
.concept-std .st-disclosure__title {
  display: block; font-size: 13px; line-height: 1.3; overflow-wrap: anywhere;
}
.concept-std .st-disclosure__sub {
  display: block; font-size: 12px; line-height: 1.3; color: var(--st-muted); overflow-wrap: anywhere;
}
.concept-std .st-disclosure__chevron {
  flex: none; margin-left: auto; color: var(--st-muted); transition: transform .15s ease;
}
.concept-std .st-disclosure[open] .st-disclosure__chevron { transform: rotate(180deg); }
.concept-std .st-disclosure__body { padding: 0 10px 8px 42px; }
.concept-std .st-disclosure__body p { margin: 0 0 4px; font-size: 12px; line-height: 1.4; color: var(--st-muted); }
.concept-std .st-disclosure--warn { border-color: var(--st-warning); }
.concept-std .st-disclosure--danger { border-color: var(--st-danger); }
.concept-std .st-disclosure--danger .st-disclosure__lead { color: var(--st-danger); background: var(--st-danger-dim); }

/* ---------- 20d. Codes, and the sideways box -------------------------------- */

/* A code a player reads out or types in. The whole point of it is being copied
   without error, so it is tabular and letter-spaced and it may be selected. */
.concept-std .st-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px; letter-spacing: .08em; color: var(--st-text);
  user-select: all; overflow-wrap: anywhere;
}

/* A diagram wider than a phone. <main> stays the only VERTICAL scroller in this
   frame; this is the other axis, which that rule does not cover. */
.concept-std .st-scroller {
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

/* ---------- 21. Focus, links, empty states --------------------------------- */

.concept-std :focus-visible { outline: 3px solid var(--st-accent); outline-offset: 3px; }
.concept-std a { color: var(--st-link); text-underline-offset: 3px; }
.concept-std .st-empty {
  padding: 12px 12px; text-align: center;
  border: 1px dashed var(--st-line); border-radius: var(--st-radius-sm);
  color: var(--st-muted); font-size: 13px; line-height: 1.4;
}

/* ---------- 21b. Raw text: a payload, an id, a JSON sketch ------------------
   The one place this skin shows a player something the GAME wrote rather than
   something it says: an order's raw parameters, its order id, and the payload
   sketch a draft plan's item carries. Monospace on purpose — a uuid read in a
   proportional face is a uuid a player cannot check against another one — and
   wrapping rather than scrolling sideways, because a second scroller inside
   <main> is the one thing the frame does not allow.

   The editable form is the same box: a queue payload is stored as-is and never
   validated by the server, so what a player edits IS the raw text, and making
   the editor look like the reader is the honest shape. */
.concept-std .st-code {
  display: block; width: 100%; box-sizing: border-box;
  margin: 8px 0 0; padding: 8px 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 12px; line-height: 1.5;
  color: var(--st-text);
  background: var(--st-bg-1);
  border: 1px solid var(--st-line-mid);
  border-radius: var(--st-radius-sm);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.concept-std textarea.st-code {
  min-height: 132px; resize: vertical;
  /* The tap floor belongs to controls a thumb aims at, and a 48px text area is
     not one — this is deliberately taller than the token, never shorter. */
}

/* Four figures remain a compact strip, with lining tabular numerals. */
.concept-std .st-tiles--4 .st-tile { min-height: 0; padding: 5px 8px; border-radius: 6px; }
.concept-std .st-tiles--4 .st-tile__value { font-size: 15px; font-variant-numeric: tabular-nums lining-nums; }
@media (min-width: 1024px) {
  .concept-std .st-card { border-radius: 6px; }
  .concept-std .st-tiles--4 .st-tile__value { font-size: 16px; }
}

/* ---------- 22. Classic screens inside this frame --------------------------
   Every tab without a mint screen renders its CLASSIC screen here — that is
   the concept mechanism's default and it is what stops the skin ever hiding a
   feature. Section 1's token retune already paints those screens; these are the
   two GEOMETRY facts they need, and nothing else is touched. */

/* The map stage sizes itself off `100dvh - header - tabbar` in game.css, which
   is arithmetic about a page that scrolls. Here <main> is the scroller and its
   height is already correct, so the stage simply fills it. */
.concept-std > main.game-main.wide { display: flex; flex-direction: column; padding: 0; }
.concept-std .map-shell { flex: 1 1 auto; height: auto; min-height: 0; }

/* THE IMMERSIVE VIEW in this layout (core/immersive.js; game.css lifts the
   stage). In Panel the Mint frame is the chart's chrome and the engine's own
   HUD and key are hidden inline by ui/concept/standard/map.js. In Immersive the
   frame steps aside (ui/concept/standard/map/frame.js) and the engine's HUD is the
   chrome — Find a system, Home, Layers, the view chip and zoom, the same three
   corners on every layout — so it, and the key at the top of its Layers sheet,
   come back over that inline hide. The system sheet stays the Mint sheet: it
   sits above the lifted stage (60 against 50) and is how a selected system
   reads here either way.

   The bottom bar is the one piece of chrome stacked ABOVE the lifted stage
   (70), so it is hidden, not covered; visibility rather than display, so the
   page behind keeps its layout and nothing jumps on the way out. With no bar
   under it, the sheet gives back the bar's height it reserves at its foot. */
.concept-std .map-shell--immersive > .map-hud { display: block !important; }
.concept-std .map-shell--immersive .map-key { display: block !important; }
:root.asov-map-immersive .concept-std > .st-nav { visibility: hidden; }
:root.asov-map-immersive .concept-std .st-sheet {
  padding-bottom: calc(16px + var(--st-safe-bottom));
}
/* The engine's view chip in this layout's clothes, so it reads as one family
   with the Home and Layers beside it (which this file already re-shapes as
   .btn) and with the frame's own chip on the title row in Panel: the small
   radius, the word in sentence case, and the accent wash on the view in force. */
.concept-std .map-view {
  border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised); border-color: var(--st-line);
}
.concept-std .map-view__opt {
  border-radius: var(--st-radius-sm);
  font-size: 13px; font-weight: 650; letter-spacing: normal; text-transform: none;
  color: var(--st-muted);
}
.concept-std .map-view__opt[aria-pressed="true"] { background: var(--st-accent-bg); color: var(--st-accent); }
/* The turn pill beside it (⟳ Landscape / ⟳ Portrait), in the same clothes. */
.concept-std .map-turn {
  border-radius: var(--st-radius-sm);
  background: var(--st-panel-raised); border-color: var(--st-line);
  font-size: 13px; font-weight: 650; letter-spacing: normal; text-transform: none;
  color: var(--st-text);
}
/* game.css steps the right-hand corners in beside the classic drawer while a
   system is selected. This layout never shows that drawer — the Mint sheet is
   the card — so the corners stay on the edge. */
.concept-std .map-shell--immersive.map-shell--side .map-hud__menu,
.concept-std .map-shell--immersive.map-shell--side .map-hud__view,
.concept-std .map-shell--immersive.map-shell--side .map-hud__zoom { right: 0; }
.concept-std .map-shell--immersive.map-shell--side .map-hud__find { max-width: calc(100% - 12rem); }

/* The Scanned bodies screen is a fixed-height column so its header row can stay
   pinned to the top of what the reader can see (game.css .map-list-screen--
   bodies), and the classic arithmetic for that is "the viewport, less the
   sticky chrome above it". Here the chrome is not above the screen, it is
   outside the SCROLLER: <main> is the scrolling box and the two bands are its
   siblings, so the whole viewport would make the column taller than <main> and
   let its header scroll out of the frame with it.

   The bands, named: --chrome-measured is app.js's live reading of the header
   (game.css resolves it on <html>, above this scope's own --chrome-h: 0),
   --subtab-measured is its reading of the Map group's section strip — a sibling
   of <main> in this frame exactly as the header is, and a band this screen only
   grew when the Map panes became sections like every other tab's — and
   --st-nav-h is the bottom bar. The 58px is the padding INSIDE <main> that
   the column sits in and therefore has to leave room for: <main>'s own 10px and
   12px (section 6), and the 12px and 24px listRoute() puts round the card
   (ui/concept/standard/map.js). Measured with them left out, <main> could scroll
   13px — enough to slide the header row up out of the frame. */
.concept-std .map-list-screen--bodies {
  height: calc(100dvh - var(--chrome-measured) - var(--subtab-measured, 0px) - var(--st-nav-h) - 58px);
}

/* THE COMMAND PRESET'S GRADIENT, on the classic screens this frame hosts.
   Section 3 already flattens the ONE .btn on the top line, and the argument is
   written out there: the Command preset paints every .btn with a gradient, and a
   gradient is a background no contrast check can resolve from styles. Inside a
   screen it is the same button and the same problem — the map's own
   Map / Systems / Bodies strip was the last "contrast unknown" the harness had
   on this layout, and that strip is chrome now, which is a second reason it can
   no longer be one. Flat, from the mint tokens, like everything else in here.
   Scoped to <main> so it cannot reach the header rule above it. */
.concept-std main.game-main .btn {
  background-image: none;
  background-color: var(--st-panel-raised);
  border-color: var(--st-line);
  color: var(--st-text);
}
.concept-std main.game-main .btn:hover {
  background-image: none;
  background-color: var(--st-panel-3);
  border-color: var(--st-edge-ui);
}
.concept-std main.game-main .btn--primary {
  background-image: none;
  background-color: var(--st-accent);
  border-color: var(--st-accent);
  color: var(--st-accent-ink);
  box-shadow: none;
}
.concept-std main.game-main .btn--ghost,
.concept-std main.game-main .btn--danger {
  background-image: none;
  background-color: transparent;
}

/* Anything a screen sticks to the top of the page belongs at the top of the
   SCROLLER here. --chrome-h is already 0 in this scope, so this is only the
   designer's own vitals bar, which pins with a literal fallback. */
.concept-std .design-vitals { top: 0; }

/* CLASSIC DENSITY. A colony page in this frame ends in five folded classic
   cards, and at game.css's own .95rem padding and 1rem margin they were 501px
   of shut summaries — a quarter of the screen for five one-line headings. The
   padding and the heading size come down to this skin's, and the fold summary's
   NEGATIVE MARGINS come down with them: they exist to pull the summary out over
   the card's padding so the whole row is tappable, so the two numbers have to
   stay equal or the header sits off-centre in its own card. The coarse-pointer
   tap floor game.css puts on that summary is untouched. */
.concept-std .card { padding: .7rem; margin-bottom: .7rem; }
.concept-std details.card--fold > summary { padding: .7rem; margin: -.7rem; }
.concept-std details.card--fold[open] > summary { margin: -.7rem -.7rem .45rem; }
.concept-std .card > h2,
.concept-std details.card--fold > summary h2 { font-size: 15px; line-height: 1.3; }
.concept-std .card > h3 { font-size: 14px; line-height: 1.3; }

/* Classic cards, buttons and pills, given the mint's radius and tap floor.
   Paint comes from the token retune; these three are the shapes that would
   otherwise read as a different design language inside the same frame. */
/* The Command preset paints a handful of surfaces with LITERAL colours rather
   than through game.css's tokens — a blue-black card gradient, a blue primary
   button, a blue-edged modal — so the token retune in section 1 cannot reach
   them, and a classic screen in this frame showed mint panels around a navy
   card with a bright blue button in it. These are those surfaces, and only
   those: same selectors, same weight, later file. */
.concept-std .card {
  border-radius: var(--st-radius);
  background: var(--st-panel);
  border-color: var(--st-line);
  border-left-color: var(--st-line);
}
.concept-std .card--sub { background: var(--st-panel-raised); }
.concept-std .btn--primary {
  background: var(--st-accent);
  border-color: var(--st-accent);
  /* The ink too, not just the fill. Without this line the button kept
     game.css's own --on-accent, which is the ink for THAT look's accent — white
     on a mint-cyan CTA measures 1.9:1. The modal rule 20 lines down had always
     said it; the in-page one had not. */
  color: var(--st-accent-ink);
  box-shadow: none;
}
.concept-std .btn--primary:hover {
  background: var(--st-accent);
  border-color: var(--st-accent);
  filter: brightness(1.06);
}
.concept-std ~ dialog.modal {
  background: var(--st-panel);
  border-color: var(--st-line);
  border-radius: var(--st-radius);
  box-shadow: none;
}
.concept-std ~ dialog.modal .modal-head { background: none; border-bottom-color: var(--st-line); }
/* Modals are appended to <body>, a SIBLING of #app, so nothing written as a
   descendant of .concept-std reaches an order form. The token blocks above
   are scoped to the sibling too; these are the literal Command surfaces. */
.concept-std ~ dialog.modal .btn--primary {
  background: var(--st-accent);
  border-color: var(--st-accent);
  color: var(--st-accent-ink);
  box-shadow: none;
}
.concept-std ~ dialog.modal .btn { border-radius: var(--st-radius-sm); min-height: var(--st-tap); }
.concept-std ~ dialog.modal .card { border-radius: var(--st-radius); background: var(--st-panel); border-color: var(--st-line); }
.concept-std .banner { background: var(--st-panel); border-radius: var(--st-radius-sm); }
.concept-std ~ #toasts .toast {
  background: var(--st-panel-raised);
  border-radius: var(--st-radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .6);
}
/* Radius only. A min-height here would be a SIZE, and game.css sets several of
   those on .btn through more specific selectors of the same weight
   (.map-hud .btn, .chip-scroll .btn, .shell-header--game .btn) — a blanket
   rule in this file loads later and silently wins them all, which is how the
   map HUD and the Orders filter chips lost 4px of tap height in the first pass
   of this skin. The classic geometry is correct; only the shapes change. */
.concept-std .btn { border-radius: var(--st-radius-sm); }
.concept-std .btn--primary { color: var(--st-accent-ink); }
.concept-std .pill { border-radius: 999px; }
/* The classic cards embedded in a mint screen (shipyard queue, structures, the
   colony's "more" cards) keep their small buttons; on a phone those are the
   only targets under the tap floor, so the floor is applied to them here. */
.concept-std .btn--sm { min-height: var(--st-tap); min-width: var(--st-tap); }
/* A disabled classic button is dimmed by opacity in the preset, which drops its
   label below 3:1 on these panels; keep the glyph legible and say disabled by
   colour instead. */
.concept-std .btn[disabled], .concept-std .btn:disabled {
  opacity: 1; color: var(--text-3); background: var(--panel-3); border-color: var(--line);
}
/* The PRIMARY one too. `main.game-main .btn--primary` above outranks the rule just written, so
   a disabled primary button (Settings → Ask VEGA with nothing typed, or while VEGA is resting)
   still painted as a live CTA. Same disabled colours, at the weight that wins. */
.concept-std main.game-main .btn--primary[disabled],
.concept-std main.game-main .btn--primary:disabled {
  opacity: 1; color: var(--text-3); background: var(--panel-3); border-color: var(--line);
}
.concept-std select,
.concept-std input:not([type="checkbox"]):not([type="radio"]):not([type="range"]) { min-height: var(--st-tap); }

/* Toasts clear the bottom bar — #toasts is a SIBLING of #app and inherits
   nothing from it, so the height is repeated rather than referenced. */
.concept-std ~ #toasts { bottom: calc(var(--st-nav-h) + 12px + env(safe-area-inset-bottom, 0px)); }

/* ---------- 24. Gauges -----------------------------------------------------
   A budget in the smallest honest box: a label and a figure on one line, a bar
   under them, and the fix in words under that. The designer's editor has four
   of these to show at once — power, crew, heat, mass — and four st-tiles is a
   whole screen at 360px, which is why this is not a tile. */

.concept-std .st-gauges {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
}
.concept-std .st-gauges--1 { grid-template-columns: minmax(0, 1fr); }
.concept-std .st-gauges--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.concept-std .st-gauge {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel);
}
/* Label left, figure right, on one line — and the figure never wraps, because a
   two-part number broken across lines reads as two numbers. */
.concept-std .st-gauge__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  min-width: 0;
}
.concept-std .st-gauge__label {
  flex: 0 1 auto; min-width: 0;
  font-size: 12px; line-height: 1.3; color: var(--st-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* WRAPS RATHER THAN SPILLING. `flex: none` kept a two-part figure on one line,
   which is right for "47 / 60" and wrong for a build cost — the cost ran three
   resources long and simply painted out of the card and across the next column.
   The harness does not see that: the box is not clipped and nothing crosses the
   viewport edge. Shrinking is what keeps the figure inside its own card. */
.concept-std .st-gauge__value {
  flex: 0 1 auto; min-width: 0;
  text-align: right; overflow-wrap: anywhere;
  font-size: 14px; font-weight: 700; line-height: 1.3;
  color: var(--st-text); font-variant-numeric: tabular-nums;
}
/* The fix, in words. Wraps freely: it is a sentence, and a clipped instruction
   is worse than a taller box. */
.concept-std .st-gauge__note {
  font-size: 12px; line-height: 1.35; color: var(--st-muted); overflow-wrap: anywhere;
}

/* ---------- 25. Form controls ----------------------------------------------
   The kit's first typing surfaces. The first six mint screens read and
   navigated; the designer's editor asks for a name, a search term, a switch and
   a pair of steppers, and every one of those would otherwise have been
   hand-composed out of game.css classes inside a mint card. */


/* A switch that IS the row. A native checkbox is a 13px hit box beside a label
   and the render harness measures the input, not the label, so the one shape
   that is both accessible and above the floor is this one. */
.concept-std .st-toggle {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: var(--st-tap); padding: 6px 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel); color: var(--st-text);
  font: inherit; text-align: left; cursor: pointer;
}
.concept-std .st-toggle__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.concept-std .st-toggle__label { font-size: 15px; font-weight: 650; line-height: 1.3; }
.concept-std .st-toggle__hint { font-size: 13px; line-height: 1.3; color: var(--st-muted); overflow-wrap: anywhere; }
.concept-std .st-toggle__track {
  flex: none; position: relative;
  width: 42px; height: 24px; border-radius: 999px;
  background: var(--st-track); border: 1px solid var(--st-line);
}
.concept-std .st-toggle__knob {
  position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 999px;
  background: var(--st-grabber);
  transition: left .12s ease, background .12s ease;
}
.concept-std .st-toggle--on .st-toggle__track { background: var(--st-accent-bg); border-color: var(--st-accent); }
.concept-std .st-toggle--on .st-toggle__knob { left: 20px; background: var(--st-accent); }
.concept-std .st-toggle[aria-disabled="true"] { color: var(--st-text-4); cursor: default; }

/* Minus, a count, plus. Both buttons are full tap targets; the count between
   them is a span, so the pair keeps its size whatever the number says. */
.concept-std .st-stepper { flex: none; display: inline-flex; align-items: center; gap: 2px; }
.concept-std .st-stepper__btn {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--st-tap); height: var(--st-tap);
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel); color: var(--st-text);
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.concept-std .st-stepper__btn--add { border-color: var(--st-edge-ui); color: var(--st-accent); }
.concept-std .st-stepper__btn[disabled] {
  color: var(--st-text-4); background: var(--st-panel-3); border-color: var(--st-line-mid); cursor: default;
}
.concept-std .st-stepper__count {
  flex: none; min-width: 22px; text-align: center;
  font-size: 13px; font-weight: 700; color: var(--st-muted); font-variant-numeric: tabular-nums;
}
.concept-std .st-stepper__count--on { color: var(--st-accent); }

/* ---------- 26. Climate axes, and the comfort bar --------------------------
   The colony page's environment list. The owner met it as six rows of words —
   "Temperature · Warm · Continuous — Comfortable" — on a screen whose whole
   subject is how far outside a comfortable range this planet sits, and asked
   for "actual bars and environment ratings and such" (2026-09-10).

   ONE AXIS IS A SMALL CARD, not a row: it carries a head line, a bar under it
   and — where the axis is hostile — a gauge and two sentences about who is
   covered. That is three blocks, and a row is one line with a value on the
   right. The row inside it is a plain one, so the box is drawn once.

   THE BAR IS THE CLASSIC BODY PAGE'S BAR, in the skin's palette. Its geometry
   comes from ui/bodyDetail.js axisBarModel(), the same model the survey screen
   draws, and the zones mean exactly what they mean there: the shaded span is
   the outer limit of tolerance, most of which is livable only under protective
   structures, and the solid green core is where nobody needs protecting at
   all. The 2px tick is the ideal and the 8px marker is this world. */

.concept-std .st-axis {
  display: grid; gap: 4px;
  padding: 6px 10px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-panel);
}
/* The verdict column: the chip, and the severity number under it rather than
   instead of it — "Comfortable" and "severity 12" are both true of an axis
   below the harm threshold, and one row could only ever say one of them. */
.concept-std .st-axis__status {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
}
.concept-std .st-axis__severity {
  font-size: 11px; font-weight: 600; line-height: 1.2;
  color: var(--st-muted); font-variant-numeric: tabular-nums;
}
/* How much of a hostile axis is actually covered, and what to build. */
.concept-std .st-axis__cover { display: grid; gap: 3px; }
.concept-std .st-axis__cover .st-card__note { margin: 0; }

/* THE FULL WIDTH OF THE CARD. It is a 0-100 scale, and inside the row's body it
   only ever got what was left beside the status chip. 2px of side margin keeps
   the marker's ring off the card's own border at either end. */
.concept-std .st-comfort {
  display: block; position: relative; height: 10px; margin: 1px 2px 2px;
}
.concept-std .st-comfort__track {
  position: absolute; inset: 0;
  border-radius: 999px; overflow: hidden;
  background: var(--st-track);
}
.concept-std .st-comfort__band,
.concept-std .st-comfort__zone { position: absolute; top: 0; bottom: 0; }
/* Tolerated, but only under a roof: recessive amber, because it is a caution
   and not a verdict. */
.concept-std .st-comfort__band { background: var(--st-warning); opacity: .34; }
/* No protection needed at all. The ring is the track colour, so the green core
   reads as sitting ON the band rather than blending into it. */
.concept-std .st-comfort__zone {
  background: var(--st-success); border-radius: 2px;
  box-shadow: 0 0 0 2px var(--st-track);
}
.concept-std .st-comfort__ideal {
  position: absolute; top: 1px; bottom: 1px; width: 2px; border-radius: 1px;
  transform: translateX(-50%);
  background: var(--st-text); opacity: .7;
}
/* This world. Taller than the track and ringed in the card's own colour, so it
   is legible wherever on the bar it lands. */
.concept-std .st-comfort__marker {
  position: absolute; top: -2px; bottom: -2px; width: 8px;
  border-radius: 4px; transform: translateX(-50%); z-index: 1;
  background: var(--st-muted);
  box-shadow: 0 0 0 2px var(--st-panel);
}
.concept-std .st-comfort__marker--good   { background: var(--st-success); }
.concept-std .st-comfort__marker--warn   { background: var(--st-warning); }
.concept-std .st-comfort__marker--danger { background: var(--st-danger); }

/* ---------- 27. The 3D system view -----------------------------------------
   The orrery on the System page (ui/concept/standard/map/system3d.js; the drawing is
   ui/systemScene3d.js). Two ways of being shown, the owner's "total immersion":

   PANEL. The scene in a box over the page's cards: as tall as a phone needs to
   hold the tilted disc and never the whole screen, because inside the box a
   finger turns the system and outside it the same finger scrolls the page. The
   rim is the kit's hairline, so the box reads as a card in either look.

   IMMERSIVE (27b, the default). The same box, moved to the app root and fixed
   over the whole screen — above the header and the bottom bar (z 80, the bar is
   70) and under the toasts (90). */
/* Map reading pages hand horizontal overflow to the table's own scroll box. */
.concept-std .st-map-page { width: 100%; min-width: 0; max-width: 100%; padding: 12px; box-sizing: border-box; }
.concept-std .st-map-page > section { margin-block: 12px; }

.concept-std .st-system3d {
  position: relative;
  height: clamp(220px, min(62vh, 80vw), 480px);
  border-radius: var(--st-radius, 14px);
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--st-line);
}
/* The page keeps the box's height while the box is away in Immersive, so the
   cards under it do not jump up and back when the player returns. */
.concept-std .st-system3d-home--away {
  height: clamp(220px, min(62vh, 80vw), 480px);
}

/* THE HEADS-UP LAYER. Over the scene, under nothing but the sheets: the
   Immersive / Panel chip top left, the camera chips top right (they wrap under
   it on a narrow phone), the Move banner under them, the in-flight card at the
   foot. The layer itself lets every touch through to the scene; its controls
   take their own. */
.concept-std .st-sv-hud {
  position: absolute; inset: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px;
  pointer-events: none;
}
.concept-std .st-sv-hud__top {
  display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 6px;
}
.concept-std .st-sv-hud__top > *,
.concept-std .st-sv-banner,
.concept-std .st-sv-flightcard { pointer-events: auto; }
/* The page holds the box and, under it in Panel, the in-flight list. */
.concept-std .st-system3d-wrap { display: block; }
/* Immersive / Panel: the kit's compact segment, on glass over the scene. */
.concept-std .st-sv-mode {
  flex: 0 0 auto; background: var(--st-glass); border-color: var(--st-line);
}
.concept-std .st-sv-hud .st-segment__item { background: transparent; color: var(--st-text); }
.concept-std .st-sv-hud .st-segment__item[aria-selected="true"] {
  background: var(--st-accent); color: var(--st-accent-ink);
}
.concept-std .st-sv-glyph { font-size: 15px; line-height: 1; }
/* The system's name: only in Immersive, where the page title is covered. */
.concept-std .st-sv-hud__title { display: none; }

/* Top, Tilt, Low, Frame: set angles, a finger's width each. */
.concept-std .st-sv-cam {
  display: flex; gap: 3px; padding: 3px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-sm);
  background: var(--st-glass);
}
/* ⟳ LANDSCAPE / ⟳ PORTRAIT — the turn pill, Immersive only (system3d.js syncTurn shows it where the
   platform can turn the screen): the galaxy map's own control (game.css .map-turn), in this layout's
   glass. A finger's width and height. */
.concept-std .st-sv-turn {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  min-height: 44px; min-width: 44px; padding: 0 12px; margin: 0;
  border: 0; border-radius: 999px;
  background: var(--st-glass-soft); color: var(--st-text);
  font-family: inherit; font-size: 11px; font-weight: 650; letter-spacing: .12em; text-transform: uppercase;
  white-space: nowrap; cursor: pointer;
}
.concept-std .st-sv-turn[hidden] { display: none; }
.concept-std .st-sv-turn:focus-visible { outline: 2px solid var(--st-accent); outline-offset: -2px; }
.concept-std .st-sv-turn__glyph { font-size: 15px; line-height: 1; letter-spacing: 0; }
.concept-std .st-sv-turn__word { white-space: nowrap; }
/* The chrome round: the pill KEEPS ITS WORD at every width — "Landscape" / "Portrait", never a bare ⟳
   (⟳ is the app's Refresh glyph). On a narrow row the glyph goes instead and the padding tightens;
   the system's name moved off this row to the top edge tab (27c), so it is never cut either. */
@media (max-width: 480px) {
  .concept-std .st-system3d--immersive .st-sv-turn { padding: 0 10px; gap: 0; letter-spacing: .08em; }
  .concept-std .st-system3d--immersive .st-sv-turn__glyph { display: none; }
}
.concept-std .st-sv-cam__btn {
  min-width: 44px; min-height: 44px; padding: 0 8px;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--st-text);
  font-family: inherit; font-size: 12px; font-weight: 650; cursor: pointer;
}
.concept-std .st-sv-cam__btn[aria-pressed="true"] {
  box-shadow: inset 0 -2px 0 var(--st-accent); color: var(--st-accent);
}
/* The one round button the chips fold behind in Immersive (27b); in Panel the
   chips are a row and the button is not drawn. */
.concept-std .st-sv-camwrap { position: relative; flex: 0 0 auto; }
.concept-std .st-sv-camtoggle { display: none; }

/* The one line while a fleet chooses where to move: what to do, or why that tap
   did nothing, and Cancel. */
.concept-std .st-sv-banner {
  display: flex; gap: 8px; align-items: center;
  padding: 6px 6px 6px 12px; border-radius: 12px;
  background: var(--st-panel); box-shadow: 0 0 0 1px var(--st-line);
  color: var(--st-text); font-size: 13px;
}
.concept-std .st-sv-banner[hidden] { display: none; }
.concept-std .st-sv-banner__text { flex: 1 1 auto; min-width: 0; }

/* FLEETS IN FLIGHT. Under the scene in Panel (a section of rows: name, where to,
   the countdown, and a bar for how much of this tick's order window is gone)
   and a compact card over the scene's foot in Immersive. */
.concept-std .st-sv-flights { margin-top: 10px; }
.concept-std .st-sv-flights[hidden],
.concept-std .st-sv-flightcard[hidden] { display: none; }
.concept-std .st-sv-eta {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums;
  font-size: 13px; color: var(--st-text);
}
.concept-std .st-sv-flight--on { box-shadow: inset 3px 0 0 var(--st-accent); }
.concept-std .st-sv-flightcard { display: none; }

/* ---------- 23. Small controls keep a 44px touch box without growing layout.
   The face is the element's own box: its border, its pill radius, its fill. The touch box is a
   transparent ::after hanging off it. It must not be padding under `background-clip: content-box`:
   the visible corner is the radius minus the padding, so every face came out a borderless square. */
.concept-std main.game-main .btn,
.concept-std .st-btn,
.concept-std .st-head .btn {
  box-sizing: border-box; min-height: var(--st-size-button); height: var(--st-size-button);
  padding: 0 9px; border: 1px solid var(--st-line); border-radius: var(--st-radius-control);
}
/* Immersive's Home and Layers: full-size controls beside the 44 px find field and view chip. */
.concept-std main.game-main .map-hud .btn { min-height: var(--st-size-control); height: var(--st-size-control); padding: 0 11px; font-size: 12.5px; }
/* :where, so a control a screen pins in place keeps its own position; the ::after needs one either way. */
:where(.concept-std main.game-main .btn, .concept-std .st-btn, .concept-std .st-head .btn) { position: relative; }
@media (pointer: coarse) {
  .concept-std .shell-header--game .icon-btn,
  .concept-std .st-orders-badge, .concept-std .st-needs {
    padding-block: 9px; margin-block: -9px; background-clip: content-box;
  }
  .concept-std main.game-main .btn::after,
  .concept-std .st-btn::after,
  .concept-std .st-head .btn::after {
    content: ''; position: absolute; inset: calc(50% - var(--st-size-touch) / 2) 0;
  }
  .concept-std .st-strip a { padding-block: 10px; margin-block: -10px; background-clip: content-box; }
}

/* ---------- 27b. The 3D system view, immersive ------------------------------
   The box fixed over the whole screen (ui/concept/standard/map/system3d.js moves it
   to the app root, where nothing transformed contains it), every control kept
   clear of the notch and the gesture bar. The sheets stack above it (85) with
   no scrim: the scene beside a sheet stays live, and a tap on empty space puts
   the sheet away. On a phone the sheet keeps to the lower half so the scene
   still shows above it; on a wide screen it docks down the right-hand side, the
   place this layout's desktop rail puts a detail. Either way the renderer moves
   the camera's centre into what the sheet leaves. */
.concept-std .st-system3d.st-system3d--immersive {
  position: fixed; inset: 0; z-index: 80;
  height: auto; border-radius: 0; box-shadow: none;
}
.concept-std .st-system3d--immersive .st-sv-hud {
  padding:
    calc(8px + var(--st-safe-top))
    calc(8px + env(safe-area-inset-right, 0px))
    calc(8px + var(--st-safe-bottom))
    calc(8px + env(safe-area-inset-left, 0px));
}
/* ALMOST NO CHROME — the reference pass (the owner's Haulspar map: the scene is
   the screen). One row along the top: the Immersive / Panel chip, small and on
   faint glass; the system's name beside it in quiet capitals; the camera folded
   behind one round orbit button at the right that opens its four set angles as
   a short column. The in-flight card is a compact glass list (one line a fleet). */
.concept-std .st-system3d--immersive .st-sv-hud__top,
.concept-std .st-system3d--narrow .st-sv-hud__top {
  flex-wrap: nowrap; align-items: center;
}
/* The narrowest phones: Immersive, Panel, the turn pill, search and the camera toggle are 384 px at the sizes above, and
   the toggle went off the glass. The icon beside Immersive and the air go first; the words stay. */
@media (max-width: 404px) {
  .concept-std .st-system3d--immersive .st-sv-hud__top,
  .concept-std .st-system3d--narrow .st-sv-hud__top { gap: 3px; }
  .concept-std .st-system3d--immersive .st-sv-mode .st-segment__item,
  .concept-std .st-system3d--narrow .st-sv-mode .st-segment__item { gap: 0; padding-inline: 6px; }
  .concept-std .st-system3d--immersive .st-sv-mode .st-segment__item .st-icon,
  .concept-std .st-system3d--narrow .st-sv-mode .st-segment__item .st-icon { display: none; }
  .concept-std .st-system3d--immersive .st-sv-turn,
  .concept-std .st-system3d--narrow .st-sv-turn { padding-inline: 6px; letter-spacing: .02em; }
}
/* Fix round 2: the hit box back to 44 px (round 1 had slimmed it to 40); the chip's own padding goes
   instead, so the pill is no taller on screen than it was. */
.concept-std .st-system3d--immersive .st-sv-mode {
  background: var(--st-glass-soft); border-color: transparent; padding: 0; gap: 2px;
}
.concept-std .st-system3d--immersive .st-sv-mode .st-segment__item {
  min-height: 44px; padding: 0 10px; font-size: 12px; background: transparent;
}
.concept-std .st-system3d--immersive .st-sv-mode .st-segment__item[aria-selected="true"] {
  background: rgba(255, 255, 255, .12); color: var(--st-text);
}
/* The system's name rides on the top edge tab now (27c), not in this row. */
.concept-std .st-sv-hud__spacer { flex: 1 1 auto; min-width: 0; }
/* Fix 1 of the chrome round: a NARROW Panel box (under 560 px, system3d.js layoutInsets) folds them
   the same way — with the magnifier in the row, Top · Tilt · Low · Frame wrapped to a second row inside
   the box and the scene lost 50 px of its height. */
.concept-std .st-system3d--immersive .st-sv-camtoggle,
.concept-std .st-system3d--narrow .st-sv-camtoggle {
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--st-glass-soft); color: var(--st-text); cursor: pointer;
}
.concept-std .st-system3d--immersive .st-sv-camtoggle .st-icon,
.concept-std .st-system3d--narrow .st-sv-camtoggle .st-icon { width: 22px; height: 22px; }
.concept-std .st-system3d--immersive .st-sv-camwrap[data-open="true"] .st-sv-camtoggle,
.concept-std .st-system3d--narrow .st-sv-camwrap[data-open="true"] .st-sv-camtoggle {
  background: var(--st-glass); color: var(--st-accent);
}
/* Opaque enough that no name reads through it (fix round 2): the scheme's own background, so every
   colour scheme reaches it without a token of its own. Fix round 3: 97 % and NO backdrop blur — over
   the live WebGL canvas a phone's WebView re-blurs that patch on every frame of a swivel, for a
   difference nobody can see at this opacity. */
.concept-std .st-system3d--immersive .st-sv-cam,
.concept-std .st-system3d--narrow .st-sv-cam {
  display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 8;
  flex-direction: column; min-width: 92px;
  background: color-mix(in srgb, var(--st-bg) 97%, transparent);
}
.concept-std .st-system3d--immersive .st-sv-camwrap[data-open="true"] .st-sv-cam,
.concept-std .st-system3d--narrow .st-sv-camwrap[data-open="true"] .st-sv-cam { display: flex; }
/* Fix round 2: near-opaque — at 0.72 the routes ran on behind its text and read through it. Fix round
   3: 0.97 and no backdrop blur (the camera column's reason: a blur over the live canvas is paid on
   every frame of a gesture). */
.concept-std .st-system3d--immersive .st-sv-flightcard {
  display: block; margin-top: auto; align-self: stretch;
  max-height: 30vh; overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid rgba(255, 255, 255, .06); border-radius: var(--st-radius-sm);
  background: color-mix(in srgb, var(--st-bg) 97%, transparent);
}
/* One line a fleet: no lead tile, smaller type, a hairline bar — and its chevron
   kept, small and quiet, so a row still reads as something to tap. */
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row {
  min-height: 44px; padding: 4px 8px 4px 12px; gap: 8px; border: 0;
}
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row__lead { display: none; }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row__chevron { opacity: .55; transform: scale(.85); }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row__title { font-size: 13px; }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row__sub { font-size: 11.5px; }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-row__meter { margin-top: 3px; }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-meter__track { height: 3px; }
.concept-std .st-system3d--immersive .st-sv-flightcard .st-sv-eta { font-size: 12px; }
.concept-std .st-system3d--immersive .st-sv-flightcard[hidden] { display: none; }
.concept-std .st-sv-flightcard__head {
  display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 44px; padding: 0 12px;
  border: 0; background: transparent; color: var(--st-muted);
  font-family: inherit; font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  cursor: pointer;
}
.concept-std .st-sv-flightcard__count { color: var(--st-accent); }
.concept-std .st-sv-flightcard[data-folded="true"] .st-sv-flightrows { display: none; }
.concept-std .st-sv-flightcard .st-rows { margin: 0; }
.concept-std .st-sv-flightcard .st-row { background: transparent; border-radius: 0; }
/* While a sheet is open the sheet is the detail: the card steps aside, on a phone (where the
   sheet covers the foot anyway) and on a wide screen (where it would cover the scene that is left
   beside the docked sheet). */
.concept-std .st-system3d--immersive.st-system3d--sheet .st-sv-flightcard { display: none; }

/* THE APP'S TOASTS IN IMMERSIVE (fix round 3). At the foot they landed on the world just acted on —
   "Move Fleet submitted for tick 429." over "Ashvale · Capital" on a landscape phone — and over the
   in-flight row of the fleet just ordered on an upright one. While the 3D view is immersive they sit
   at the top, centred, under the chip row and the Move banner (system3d.js writes the height), and
   the view lays its names out round them while they show (setOverlays). */
:root.asov-sv-immersive .concept-std ~ #toasts {
  top: var(--asov-sv-toast-top, calc(64px + env(safe-area-inset-top, 0px)));
  bottom: auto; right: auto; left: 50%;
  transform: translateX(-50%);
  width: max-content; max-width: min(92vw, 24rem);
  align-items: center;
}

.concept-std .st-sheet.st-sheet--sv-immersive {
  z-index: 85;
  max-height: 56dvh;
  padding-bottom: calc(16px + var(--st-safe-bottom));
}
.concept-std .st-sheet__scrim.st-sheet__scrim--sv-immersive { display: none; }

/* The 3D view's sheet, in both views: the grabber and the close button stay
   put and the CONTENT scrolls, in an inner body. Not the kit's fixed sheet as
   the scroller: a fixed sheet that overflowed and scrolled, laid over the
   WebGL canvas, made Chrome drop the canvas from the frame — the names stayed,
   the system vanished (seen in the render harness, every long card: a world's
   climate rows, a fleet's actions). An inner scroller never does. */
.concept-std .st-sheet.st-sheet--sv {
  display: flex; flex-direction: column; overflow: hidden;
}
.concept-std .st-sheet.st-sheet--sv[hidden] { display: none; }
.concept-std .st-sv-sheetbody {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
}

@media (min-aspect-ratio: 4/3) {
  .concept-std .st-sheet.st-sheet--sv-immersive {
    top: 0; right: 0; bottom: 0; left: auto;
    width: min(360px, 46vw);
    max-height: none;
    padding: calc(12px + var(--st-safe-top)) calc(14px + env(safe-area-inset-right, 0px)) calc(16px + var(--st-safe-bottom)) 14px;
    border: 0; border-left: 1px solid var(--st-line);
    border-radius: 0;
    box-shadow: -18px 0 40px var(--st-scrim);
  }
  .concept-std .st-sheet--sv-immersive .st-sheet__grabber { display: none; }
  /* Wide: the in-flight card is a column on the left, clear of the docked sheet. */
  .concept-std .st-system3d--immersive .st-sv-flightcard {
    align-self: flex-start; width: min(280px, 36vw); max-height: 52vh;
  }
  /* The chips stay clear of the docked sheet too. */
  .concept-std .st-system3d--immersive.st-system3d--sheet .st-sv-hud {
    padding-right: calc(8px + min(360px, 46vw));
  }
}


/* ---------- 27c. The 3D system view's chrome: edge tabs, strip, panel, search -----
   The owner, 2026-10-31: "the little < > menu on the side … one on the bottom as well for the tab menu
   and one on top for the sub tab menu … a search and filter option … a ‹ › bar on the left side for
   quick select". All of it is the kit's tokens on the view's own glass; every target is 44 px. The
   positions hang from the chip row's foot (--st-sv-under-chips, written by system3d.js layoutInsets).

   LEFT  the quick-select strip — a 56 px rail of thumbnails on a phone, named rows from 1024 px (open
         on a box 600 px and wider until the player says otherwise), collapsible to a 44 × 44 tab at
         mid-edge showing › (the strip's own head shows ‹)
   RIGHT the system panel: 72 % of a phone's width from the right (at most 320 px, and never over the
         strip's rows), a 320 px column from 1024 px; collapsible to a ‹ tab at mid-edge
   TOP   (Immersive) the system's name on a tab under the chips (﹀), sliding the Map · Systems ·
         Bodies strip down
   BOTTOM (Immersive) a slim ︿ tab at the foot, sliding the game's five sections up
   SEARCH a magnifier in the chip row opens the Find-a-system field's twin under the chips, the
         filter row behind the layers glyph, and up to eight results */
.concept-std .st-sv-searchbtn {
  position: relative; display: grid; place-items: center; flex: 0 0 auto;
  width: 44px; height: 44px; padding: 0; margin: 0;
  border: 0; border-radius: 50%;
  background: var(--st-glass-soft); color: var(--st-text); cursor: pointer;
}
.concept-std .st-sv-searchbtn .st-icon { width: 20px; height: 20px; }
.concept-std .st-sv-searchbtn[aria-expanded="true"] { background: var(--st-glass); color: var(--st-accent); }
/* Some layer is hidden: an amber dot, the galaxy map's own "some layers are hidden" sign. */
.concept-std .st-sv-searchbtn[data-filtered="true"]::after {
  content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--st-warning); box-shadow: 0 0 0 2px var(--st-bg);
}

.concept-std .st-sv-edgetab {
  position: absolute; z-index: 4; display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 0; margin: 0; border: 1px solid var(--st-line-soft);
  background: color-mix(in srgb, var(--st-bg) 88%, transparent); color: var(--st-text);
  font-family: inherit; cursor: pointer; pointer-events: auto;
}
.concept-std .st-sv-edgetab[hidden] { display: none; }
.concept-std .st-sv-edgetab:focus-visible { outline: 2px solid var(--st-accent); outline-offset: -2px; }
.concept-std .st-sv-edgetab__glyph { font-size: 18px; line-height: 1; color: var(--st-muted); }
.concept-std .st-sv-edgetab[aria-expanded="true"] .st-sv-edgetab__glyph { color: var(--st-accent); }
.concept-std .st-sv-edgetab__glyph .st-icon { width: 20px; height: 20px; vertical-align: middle; }
.concept-std .st-sv-arrow--left .st-icon,
.concept-std .st-sv-arrow--up .st-icon { transform: rotate(180deg); }
.concept-std .st-sv-edgetab--left,
.concept-std .st-sv-edgetab--right {
  /* Fix 1 of the chrome round: a 44 × 44 target (it measured 24 × 44 — the only way to open the strip
     and the panel on a phone), the slim 24 px glass tab drawn inside it at the screen's edge; and at
     mid-edge, where a thumb reaches (Haulspar's ‹ › tab), not in the top corners. */
  top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; border: 0; background: transparent;
}
.concept-std .st-sv-edgetab--left::before,
.concept-std .st-sv-edgetab--right::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 24px; z-index: -1;
  border: 1px solid var(--st-line-soft);
  background: color-mix(in srgb, var(--st-bg) 88%, transparent);
}
.concept-std .st-sv-edgetab--left { left: 0; justify-content: flex-start; }
.concept-std .st-sv-edgetab--right { right: 0; justify-content: flex-end; }
.concept-std .st-sv-edgetab--left::before { left: 0; border-left: 0; border-radius: 0 10px 10px 0; }
.concept-std .st-sv-edgetab--right::before { right: 0; border-right: 0; border-radius: 10px 0 0 10px; }
.concept-std .st-sv-edgetab--left .st-sv-edgetab__glyph,
.concept-std .st-sv-edgetab--right .st-sv-edgetab__glyph { width: 24px; text-align: center; }
/* The top and bottom tabs' chevrons turn over while their bar is out. */
.concept-std .st-sv-edgetab--top .st-sv-edgetab__glyph,
.concept-std .st-sv-edgetab--bottom .st-sv-edgetab__glyph { display: inline-block; transition: transform .15s ease-out; }
.concept-std .st-sv-edgetab--top[aria-expanded="true"] .st-sv-edgetab__glyph,
.concept-std .st-sv-edgetab--bottom[aria-expanded="true"] .st-sv-edgetab__glyph { transform: rotate(180deg); }
.concept-std .st-sv-edgetab--top {
  top: var(--st-sv-under-chips, 60px); left: 50%; transform: translateX(-50%);
  min-height: 44px; min-width: 120px; max-width: min(64%, 360px); padding: 0 14px;
  border-radius: 12px;
}
.concept-std .st-sv-edgetab--top .st-sv-hud__title {
  display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--st-muted);
}
.concept-std .st-sv-edgetab--bottom {
  bottom: var(--st-safe-bottom); left: 50%; transform: translateX(-50%);
  width: 120px; height: 44px; border-bottom: 0; border-radius: 14px 14px 0 0;
}

/* THE LEFT STRIP — Haulspar's RAIL (fix 1 of the chrome round). On a phone, either way up, it is a
   56 px column of thumbnails, one 44 px row a place: the world's own painted surface (or the sprite's
   glyph for the star, a node or a field), a holder bar beside your own, your fleets there as a ×N badge
   on the thumbnail's corner and a foreign force as an amber pip — and only the SELECTED place's name,
   under its thumbnail (every row speaks its whole name). Named rows truncated "First Colony" to "First
   …" and took a third of an upright phone. Moons a step in. From 1024 px the rows carry their names. */
.concept-std .st-sv-strip {
  position: absolute; z-index: 4; left: 0; top: var(--st-sv-under-chips, 56px); bottom: 8px;
  width: 56px; display: flex; flex-direction: column; overflow: hidden; pointer-events: auto;
  border: 1px solid var(--st-line-soft); border-left: 0; border-radius: 0 12px 12px 0;
  background: color-mix(in srgb, var(--st-bg) 94%, transparent);
}
.concept-std .st-sv-strip[hidden] { display: none; }
.concept-std .st-sv-strip__head {
  display: flex; align-items: center; justify-content: center; min-height: 44px; flex: 0 0 auto;
  border-bottom: 1px solid var(--st-line-soft);
}
.concept-std .st-sv-strip__close,
.concept-std .st-sv-panel__close {
  display: grid; place-items: center; flex: 0 0 auto; width: 44px; height: 44px; padding: 0;
  border: 0; background: transparent; color: var(--st-text); cursor: pointer;
}
.concept-std .st-sv-strip__title,
.concept-std .st-sv-panel__title {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--st-muted);
}
.concept-std .st-sv-strip__title { display: none; }
.concept-std .st-sv-strip__list {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none;
}
.concept-std .st-sv-strip__row {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  width: 100%; min-height: 44px; padding: 8px 2px; margin: 0;
  border: 0; background: transparent; color: var(--st-text); text-align: center;
  font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.concept-std .st-sv-strip__row:focus-visible { outline: 2px solid var(--st-accent); outline-offset: -2px; }
.concept-std .st-sv-strip__row--on { background: var(--st-accent-bg); }
.concept-std .st-sv-strip__row--on .st-sv-thumb { box-shadow: 0 0 0 2px var(--st-accent); }
.concept-std .st-sv-strip__row--moon .st-sv-thumb { width: 20px; height: 20px; margin-left: 10px; }
.concept-std .st-sv-strip__bar {
  position: absolute; left: 0; top: 8px; width: 3px; height: 28px; border-radius: 0 2px 2px 0; background: transparent;
}
.concept-std .st-sv-strip__row--own .st-sv-strip__bar { background: var(--st-success); }
.concept-std .st-sv-strip__row--ally .st-sv-strip__bar { background: var(--st-link); }
.concept-std .st-sv-strip__row--foreign .st-sv-strip__bar { background: var(--st-warning); }
/* Only the selected place's name, under its thumbnail, in at most two lines. */
.concept-std .st-sv-strip__name { display: none; }
.concept-std .st-sv-strip__row--on .st-sv-strip__name {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  max-width: 52px; font-size: 10px; font-weight: 700; line-height: 1.15; color: var(--st-accent);
  white-space: normal; overflow-wrap: break-word;
}
.concept-std .st-sv-strip__badge {
  position: absolute; top: 3px; right: 3px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 8px; background: var(--st-accent); color: var(--st-accent-ink);
  font-size: 9.5px; font-weight: 800; line-height: 16px; text-align: center; font-variant-numeric: tabular-nums;
}
/* Fix round 6: the foreign pip carries the SERVED count (the Fleets tab's own — core/presence.js over the
   server's fleet_contacts), the number the scene's amber ×N says beside the same ships. A count of
   contacts, never a strength. */
.concept-std .st-sv-strip__foreign {
  position: absolute; left: 3px; top: 27px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 7px;
  background: var(--st-warning); color: var(--st-warning-ink); box-shadow: 0 0 0 2px var(--st-bg);
  font-size: 9px; font-weight: 800; line-height: 14px; text-align: center; font-variant-numeric: tabular-nums;
}
.concept-std .st-sv-thumb {
  display: grid; place-items: center; flex: 0 0 auto; width: 28px; height: 28px; overflow: hidden;
  border-radius: 50%; background: var(--st-panel-raised); color: var(--st-accent);
}
.concept-std .st-sv-thumb canvas { display: block; width: 100%; height: 100%; }
/* Fix round 6: a field's card (the System page's body card) wears the glyph its rail row and its marker
   draw, in the portrait circle the art pack has no picture for. */
.concept-std .st-sv-cardglyph { display: grid; place-items: center; width: 100%; height: 100%; color: var(--st-accent); }
.concept-std .st-sv-cardglyph .st-icon { width: 34px; height: 34px; }
.concept-std .st-sv-thumb .st-icon { width: 18px; height: 18px; }
@media (min-width: 1024px) {
  .concept-std .st-sv-strip { width: 200px; }
  .concept-std .st-sv-strip__head { justify-content: flex-start; }
  .concept-std .st-sv-strip__title { display: block; }
  .concept-std .st-sv-strip__row {
    display: grid; grid-template-columns: 3px 28px minmax(0, 1fr) auto auto; align-items: center; gap: 8px;
    padding: 0 8px 0 0; text-align: left;
  }
  .concept-std .st-sv-strip__bar { position: static; }
  .concept-std .st-sv-strip__row--moon .st-sv-thumb { width: 22px; height: 22px; margin-left: 3px; }
  .concept-std .st-sv-strip__name,
  .concept-std .st-sv-strip__row--on .st-sv-strip__name {
    display: block; max-width: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 13px; line-height: 1.3;
  }
  .concept-std .st-sv-strip__row--moon .st-sv-strip__name { padding-left: 8px; font-weight: 500; }
  .concept-std .st-sv-strip__badge { position: static; background: transparent; color: var(--st-accent); font-size: 11px; }
  .concept-std .st-sv-strip__foreign { position: static; box-shadow: none; justify-self: end; }
}

/* THE RIGHT PANEL. One row size, no nested boxes: the place's name, its pills and facts, Move here, its
   links; FLEETS HERE with each fleet's orders row; FLEETS IN FLIGHT. */
.concept-std .st-sv-panel {
  position: absolute; z-index: 5; right: 0; top: var(--st-sv-under-chips, 56px); bottom: 0;
  width: min(72%, 320px); display: flex; flex-direction: column; overflow: hidden; pointer-events: auto;
  border: 1px solid var(--st-line-soft); border-right: 0; border-radius: 12px 0 0 12px;
  background: color-mix(in srgb, var(--st-bg) 97%, transparent);
}
.concept-std .st-system3d--strip .st-sv-panel {
  width: min(72%, 320px, calc(100% - var(--st-sv-strip-w, 56px) - 8px));
}
.concept-std .st-sv-panel[hidden] { display: none; }
.concept-std .st-sv-panel__head {
  display: flex; align-items: center; min-height: 44px; flex: 0 0 auto; border-bottom: 1px solid var(--st-line-soft);
}
.concept-std .st-sv-panel__body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 10px 12px 14px;
}
.concept-std .st-sv-panel__name { margin: 0 0 6px; font-size: 17px; font-weight: 700; line-height: 1.25; }
.concept-std .st-sv-panel__pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 6px; }
.concept-std .st-sv-panel__facts,
.concept-std .st-sv-panel__note,
.concept-std .st-sv-panel__hint { margin: 0 0 8px; }
/* The orders row: five stacked tiles (glyph over word), one row at any panel width. Greyed where the
   order cannot fire (a tap says why under the row), dimmed where the server is expected to refuse it
   (a tap still opens the form). */
.concept-std .st-sv-panel__orders {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; margin: 4px 0 6px;
}
.concept-std .st-sv-panel__orders .st-btn {
  flex-direction: column; gap: 2px; min-width: 0; min-height: 48px; padding: 4px 2px;
  font-size: 11px; white-space: nowrap; overflow: hidden;
}
.concept-std .st-sv-panel__orders .st-btn .st-icon { width: 18px; height: 18px; }
/* Fix round 6: the Fleets tab's own two looks (a live stTile, a locked one). LIVE: raised, the glyph lit.
   CANNOT FIRE HERE (data-reason): flat, dashed, muted, the kit's lock glyph in its corner — still a
   button, whose tap says why under the row. EXPECTED TO BE REFUSED (data-advised): live, with an amber
   edge and glyph; it still opens the form. (Round 5 dimmed the advised tile under the dead ones, and
   the row read backwards.) */
.concept-std .st-sv-panel__orders .st-btn { position: relative; border-radius: var(--st-radius-sm); }
.concept-std .st-sv-panel__orders .st-btn:not(.st-btn--primary) { background: var(--st-panel-3); border-color: var(--st-line); color: var(--st-text); }
.concept-std .st-sv-panel__orders .st-btn:not(.st-btn--primary) .st-icon { color: var(--st-link); }
.concept-std .st-sv-panel__orders .st-btn[data-reason] {
  background: transparent; border-style: dashed; border-color: var(--st-line); color: var(--st-muted); font-weight: 550;
}
.concept-std .st-sv-panel__orders .st-btn[data-reason] .st-icon { color: var(--st-muted); }
.concept-std .st-sv-panel__orders .st-btn[data-reason]:hover { border-color: var(--st-line); }
.concept-std .st-sv-panel__orders .st-btn[data-advised] { border-color: var(--st-warning); }
.concept-std .st-sv-panel__orders .st-btn[data-advised] .st-icon { color: var(--st-warning); }
.concept-std .st-sv-panel__lock { position: absolute; top: 3px; right: 3px; display: inline-flex; color: var(--st-muted); }
.concept-std .st-sv-panel__orders .st-btn .st-sv-panel__lock .st-icon { width: 11px; height: 11px; color: var(--st-muted); }
/* Fix 1 of the chrome round: a narrow panel (a 412 px phone's 296 px) wraps the five tiles three and two
   — the Fleets tab's own measured count (fleets/model.js actionGridColumns) — where five across left
   "Colonize" running past both edges of a 50 px tile. system3d.js sets the class from the panel's width. */
.concept-std .st-sv-panel--narrow .st-sv-panel__orders { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.concept-std .st-sv-panel__move { display: flex; margin: 4px 0 8px; }
.concept-std .st-sv-panel__move .st-btn { min-height: 44px; }
.concept-std .st-sv-panel__section { margin-top: 12px; }
.concept-std .st-sv-panel__card { display: block; }
.concept-std .st-sv-panel__fleet { display: block; padding: 2px 0 6px; border-bottom: 1px solid var(--st-line-soft); }
/* Fix round 6: the fleet whose ships were tapped — its block lit, the panel scrolled to it. */
.concept-std .st-sv-panel__fleet--on { background: var(--st-panel-raised); box-shadow: inset 3px 0 0 var(--st-accent); padding-left: 6px; border-radius: 4px; }
.concept-std .st-sv-panel__placerows { margin-bottom: 4px; }
.concept-std .st-sv-panel .st-sv-panel__placeline--own .st-row__title { color: var(--st-success); }
.concept-std .st-sv-panel__links { margin-top: 2px; }
.concept-std .st-sv-results__rows { display: block; }
.concept-std .st-sv-panel .st-rows { margin: 0; gap: 0; border: 0; background: transparent; box-shadow: none; }
.concept-std .st-sv-panel .st-row {
  min-height: 44px; background: transparent; border: 0; border-bottom: 1px solid var(--st-line-soft);
  border-radius: 0; padding-left: 0; padding-right: 0;
}
.concept-std .st-sv-panel .st-row__lead { background: transparent; }
.concept-std .st-sv-panel .st-sv-panel__fleet .st-row { border-bottom: 0; }
.concept-std .st-sv-panel .st-sv-flight--on { box-shadow: inset 3px 0 0 var(--st-accent); padding-left: 8px; }
/* One row layout in the panel (fix 1): the status always UNDER the name ("Ore Run Alpha" with "Standing
   by" beside it, "Longreach Survey" over its status), one size for every row's name and one for its
   line, so "Longreach Survey" no longer wraps to three lines beside its countdown. */
.concept-std .st-sv-panel .st-row__body { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 1px; }
.concept-std .st-sv-panel .st-row__title { font-size: 14px; line-height: 1.25; overflow-wrap: normal; }
.concept-std .st-sv-panel .st-row__sub { font-size: 12px; line-height: 1.3; overflow-wrap: normal; }
.concept-std .st-sv-panel .st-sv-flight .st-row__lead { display: none; }
.concept-std .st-sv-panel .st-sv-eta { font-size: 12px; }
/* A system's handle never breaks at its hyphen ("AC-" / "2044"). */
.concept-std .st-sv-nowrap { white-space: nowrap; }
/* The in-flight list moves into the panel while it is open. */
.concept-std .st-system3d--panel .st-sv-flightcard { display: none; }

/* THE SLID-UP BAR (Immersive): the Mint bar's own five places, over the scene's foot. */
.concept-std .st-sv-navbar {
  position: absolute; z-index: 6; left: 0; right: 0; bottom: 0; pointer-events: auto;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0;
  padding: 4px 4px calc(6px + var(--st-safe-bottom));
  background: var(--st-bg); border-top: 1px solid var(--st-line);
  animation: st-sv-up .18s ease-out;
}
.concept-std .st-sv-navbar[hidden] { display: none; }
/* THE SLID-DOWN STRIP (Immersive): Map · Systems · Bodies, under the name's tab. */
.concept-std .st-sv-subnav {
  position: absolute; z-index: 6; top: calc(var(--st-sv-under-chips, 60px) + 50px); left: 50%;
  transform: translateX(-50%); pointer-events: auto;
  display: flex; gap: 2px; padding: 4px; max-width: calc(100% - 16px); overflow-x: auto;
  border: 1px solid var(--st-line); border-radius: 14px;
  background: color-mix(in srgb, var(--st-bg) 96%, transparent);
  animation: st-sv-down .18s ease-out;
}
.concept-std .st-sv-subnav[hidden] { display: none; }
.concept-std .st-sv-subnav__item {
  display: grid; place-items: center; min-height: 44px; padding: 0 16px; border-radius: 10px;
  color: var(--st-muted); font-size: 13px; font-weight: 650; text-decoration: none; white-space: nowrap;
}
.concept-std .st-sv-subnav__item[aria-current="page"] { color: var(--st-accent); background: var(--st-accent-bg); }
@keyframes st-sv-up { from { transform: translateY(100%); } to { transform: none; } }
@keyframes st-sv-down { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .concept-std .st-sv-navbar,
  .concept-std .st-sv-subnav { animation: none; }
}

/* SEARCH AND FILTER: the 2D map's Find-a-system field (ui/concept/standard/map/frame.js) in its own tokens,
   a filter glyph and Close beside it; the filter row's six 44 px chips; up to eight results. */
.concept-std .st-sv-search {
  position: absolute; z-index: 7; top: var(--st-sv-under-chips, 56px); left: 8px; right: auto;
  width: min(560px, calc(100% - 16px));
  display: flex; flex-direction: column; gap: 6px; pointer-events: auto;
}
.concept-std .st-sv-search[hidden] { display: none; }
.concept-std .st-sv-search__row { display: flex; align-items: center; gap: 6px; }
.concept-std .st-sv-find {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 8px;
  min-height: var(--st-tap); padding: 0 14px;
  border: 1px solid var(--st-line); border-radius: 999px;
  background: var(--st-panel); color: var(--st-muted);
}
.concept-std .st-sv-find .st-sv-find__input {
  flex: 1 1 auto; min-width: 0; min-height: var(--st-tap); padding: 0; margin: 0;
  border: 0; border-radius: 0; background: transparent; box-shadow: none; -webkit-appearance: none; appearance: none;
  color: var(--st-text); font: inherit; font-size: 15px; outline: none;
}
/* The field's focus is the pill's (the platform's input ring would draw a box inside the pill). */
.concept-std .st-sv-find .st-sv-find__input:focus,
.concept-std .st-sv-find .st-sv-find__input:focus-visible { border: 0; box-shadow: none; outline: none; }
.concept-std .st-sv-find:focus-within { border-color: var(--st-accent); }
.concept-std .st-sv-filterbtn {
  display: grid; place-items: center; flex: 0 0 auto; width: 44px; height: 44px; padding: 0;
  border: 1px solid var(--st-line); border-radius: 50%; background: var(--st-panel); color: var(--st-text); cursor: pointer;
}
.concept-std .st-sv-filterbtn[aria-expanded="true"] { color: var(--st-accent); border-color: var(--st-accent); }
.concept-std .st-sv-searchclose { flex: 0 0 auto; background: var(--st-panel); }
.concept-std .st-sv-filters {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 6px;
  border: 1px solid var(--st-line); border-radius: 14px; background: var(--st-panel);
}
.concept-std .st-sv-filters[hidden] { display: none; }
.concept-std .st-sv-chip {
  min-height: 44px; padding: 0 14px; margin: 0;
  border: 1px solid var(--st-line); border-radius: 999px; background: transparent;
  color: var(--st-muted); font-family: inherit; font-size: 13px; font-weight: 650; cursor: pointer;
}
.concept-std .st-sv-chip[aria-pressed="true"] { background: var(--st-accent-bg); color: var(--st-accent); border-color: var(--st-accent); }
.concept-std .st-sv-results {
  max-height: min(50vh, 360px); overflow-y: auto; overscroll-behavior: contain;
  border: 1px solid var(--st-line); border-radius: 14px; background: var(--st-panel); padding: 0 8px;
}
.concept-std .st-sv-results[hidden] { display: none; }
.concept-std .st-sv-results .st-rows { margin: 0; border: 0; background: transparent; box-shadow: none; }
.concept-std .st-sv-results .st-row { min-height: 44px; background: transparent; }
.concept-std .st-sv-results__none { margin: 10px 4px; }

/* IN IMMERSIVE the foot keeps room for the bottom tab: the in-flight card, the strip and the panel stop
   above it; beside the strip the card moves over (a landscape phone's card is a column on the left). */
.concept-std .st-system3d--immersive .st-sv-hud { padding-bottom: calc(8px + 44px + var(--st-safe-bottom)); }
/* …and the strip and the panel start under the top tab's row, so the system's name stays in view
   whichever is open. */
.concept-std .st-system3d--immersive .st-sv-panel {
  top: calc(var(--st-sv-under-chips, 56px) + 52px); bottom: calc(52px + var(--st-safe-bottom));
}
/* The rail is narrow enough to run from the chips' foot beside the centred name tab (fix 1). */
.concept-std .st-system3d--immersive .st-sv-strip {
  top: var(--st-sv-under-chips, 56px); bottom: calc(52px + var(--st-safe-bottom));
}
@media (min-width: 1024px) {
  .concept-std .st-system3d--immersive .st-sv-strip { top: calc(var(--st-sv-under-chips, 56px) + 52px); }
}
/* The slid-up bar and the slid-down strip never lie over the strip's rows or the panel: while one is
   out, the strip and the panel stop short of it. */
.concept-std .st-system3d--immersive.st-system3d--bar .st-sv-strip,
.concept-std .st-system3d--immersive.st-system3d--bar .st-sv-panel {
  bottom: calc(var(--st-nav-h) + 12px + var(--st-safe-bottom));
}
.concept-std .st-system3d--immersive.st-system3d--subnav .st-sv-strip,
.concept-std .st-system3d--immersive.st-system3d--subnav .st-sv-panel {
  top: calc(var(--st-sv-under-chips, 56px) + 108px);
}
.concept-std .st-system3d--immersive.st-system3d--strip .st-sv-flightcard {
  margin-left: calc(var(--st-sv-strip-w, 56px) + 4px);
}
/* FIX 1 OF THE CHROME ROUND. The in-flight card never sits under something slid over it: while the game
   sections are up (the bar cut its last row) and while the search bar is open (its results cut the
   card's titles) it steps out of sight — keeping its place, so the camera does not move for it — and
   the name tab does the same under the search bar (its "IA" peeked between the field and the layers
   button). */
.concept-std .st-system3d--bar .st-sv-flightcard,
.concept-std .st-system3d--search .st-sv-flightcard,
.concept-std .st-system3d--search .st-sv-edgetab--top { visibility: hidden; }
/* On a landscape phone a FOLDED card is a one-line chip in the bottom tab's own row, left of the ︿ tab,
   beside the rail — it never floats over the scene beside an open strip (system3d.js folds it there
   while the strip is open, until the player unfolds it). */
@media (min-aspect-ratio: 4/3) {
  .concept-std .st-system3d--immersive .st-sv-flightcard[data-folded="true"] {
    position: absolute; left: calc(8px + env(safe-area-inset-left, 0px)); bottom: var(--st-safe-bottom);
    width: min(240px, calc(50% - 76px)); margin: 0; max-height: 44px; overflow: hidden;
  }
  .concept-std .st-system3d--immersive.st-system3d--strip .st-sv-flightcard[data-folded="true"] {
    left: calc(var(--st-sv-strip-w, 56px) + 8px); width: min(240px, calc(50% - 76px - var(--st-sv-strip-w, 56px)));
  }
}
/* While a fleet chooses where to move, the panel steps aside on a phone (the places are the point). */
@media (max-width: 1023px) {
  .concept-std .st-system3d--picking .st-sv-panel { display: none; }
}
@media (min-width: 1024px) {
  .concept-std .st-sv-panel,
  .concept-std .st-system3d--strip .st-sv-panel { width: 320px; }
}

/* ---------- 27d. Colony battles and the enemy-fleet display (2026-11-01) ------
   The approved mockups A1–A4 and B1–B4 on the 3D system view. The plates, badges,
   chevrons, ghost tags and eye marks over the scene are drawn by the renderer
   (ui/systemScene3d.js) from the palette the glue hands it, so a scheme repaints
   them as it repaints the rest of the orrery; these rules are the Mint chrome
   round them: the ally pill, the eyes legend chip, the last-battle row and the
   focus rings of the renderer's new targets. Tokens only. */

/* An ALLY wears blue, never green (the owner's rulings: green is yours alone) —
   the foreign force card's standing pill and anything else that names an ally. */
.concept-std .st-pill--ally { color: var(--blue); background: var(--blue-dim); }

/* The renderer's plates and badges are 44 px buttons over the scene. */
.concept-std .sv3d__plate:focus-visible,
.concept-std .sv3d__badge:focus-visible { outline: 2px solid var(--st-accent); outline-offset: 2px; }

/* THE EYES LEGEND CHIP (mockup B3): "You see foreign fleets only where you have
   eyes" — bottom centre over the scene, above the bottom tab in Immersive; a 44 px
   chip on glass with its own 44 px ×. An overlay: the camera never moves for it. */
.concept-std .st-sv-eyeshint {
  position: absolute; left: 60px; right: 60px; margin: 0 auto; width: fit-content;
  bottom: calc(8px + var(--st-safe-bottom));
  display: flex; align-items: center;
  border: 1px solid var(--st-line); border-radius: 999px; background: var(--st-glass);
  pointer-events: auto; z-index: 2;
}
.concept-std .st-sv-eyeshint[hidden] { display: none; }
.concept-std .st-system3d--immersive .st-sv-eyeshint { bottom: calc(56px + var(--st-safe-bottom)); }
@media (max-aspect-ratio: 4/3) {
  /* The full-width flight card needs its own row above the dismissible hint. */
  .concept-std .st-system3d--immersive:has(.st-sv-eyeshint:not([hidden])) .st-sv-hud {
    padding-bottom: calc(104px + var(--st-safe-bottom));
  }
}
.concept-std .st-system3d--sheet .st-sv-eyeshint,
.concept-std .st-system3d--picking .st-sv-eyeshint,
.concept-std .st-system3d--search .st-sv-eyeshint { display: none; }
/* QUIET, as B3 draws it: regular weight, muted ink, one line on a 412 px phone. */
.concept-std .st-sv-eyeshint__text {
  display: flex; align-items: center; gap: 7px; min-height: 44px; min-width: 44px; padding: 0 0 0 12px;
  border: 0; background: transparent; color: var(--st-muted); font-family: inherit; font-size: 12.5px;
  font-weight: 500; text-align: left; cursor: pointer; white-space: nowrap;
}
.concept-std .st-sv-eyeshint__text span { line-height: 1.2; overflow: hidden; text-overflow: ellipsis; }
.concept-std .st-sv-eyeshint__glyph { flex: 0 0 auto; color: var(--st-muted); }
.concept-std .st-sv-eyeshint__close {
  display: grid; place-items: center; width: 44px; height: 44px; flex: 0 0 44px;
  border: 0; border-radius: 999px; background: transparent; color: var(--st-muted); cursor: pointer;
}
.concept-std .st-sv-eyeshint__text:focus-visible,
.concept-std .st-sv-eyeshint__close:focus-visible { outline: 2px solid var(--st-accent); outline-offset: -2px; }
@media (max-width: 480px) {
  .concept-std .st-sv-eyeshint { left: 8px; right: 8px; max-width: calc(100% - 16px); }
  .concept-std .st-sv-eyeshint__text { font-size: 12px; gap: 6px; padding-left: 10px; }
}

/* The body sheet's "Last ground battle · T430" row, at its head (system3d.js bodySheet). */
.concept-std .st-sv-lastbattle { margin: 0 0 10px; }

/* Working-page primitives: painted faces and transparent touch extensions.
   A segment is one pill tray holding its items, the galaxy map's Immersive / Panel chip in small:
   the tray is one --st-size-control tall, and the item in force takes the same accent wash. */
.concept-std .st-segment {
  box-sizing: border-box; display: inline-flex; flex: none; flex-wrap: wrap; width: auto; max-width: 100%;
  min-height: var(--st-size-control); overflow: visible; gap: 8px 2px; padding: 2px;
  border: 1px solid var(--st-line); border-radius: calc(var(--st-size-control) / 2); background: var(--st-panel);
  -webkit-mask-image: none; mask-image: none;
}
.concept-std .st-segment .st-segment__item {
  box-sizing: border-box; position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none;
  min-height: calc(var(--st-size-control) - 6px); height: calc(var(--st-size-control) - 6px); padding: 0 8px;
  border: 0; border-radius: var(--st-radius-control); background: transparent; color: var(--st-muted);
  font-size: 12.5px; font-weight: 650; line-height: 1;
}
.concept-std .st-segment .st-segment__item:hover { color: var(--st-text); background: var(--st-panel-raised); }
.concept-std .st-segment .st-segment__item[aria-pressed="true"],
.concept-std .st-segment .st-segment__item[aria-selected="true"],
.concept-std .st-segment .st-segment__item[aria-current="page"] {
  color: var(--st-accent); background: var(--st-accent-bg); box-shadow: inset 0 0 0 1px var(--st-accent);
}
.concept-std .st-segment .st-segment__item:focus-visible { outline-width: 2px; outline-offset: 1px; }
/* Loose chips and the plain buttons beside them: a tray's own height and the same pill. */
#app.concept-std .st-social-chips .btn,
#app.concept-std .st-reports__controls .btn,
.concept-std .st-reports__controls .st-segment__item {
  box-sizing: border-box; position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none; width: auto;
  min-height: var(--st-size-control); height: var(--st-size-control); padding: 0 11px;
  border: 1px solid var(--st-line); border-radius: var(--st-radius-control); background: var(--st-panel); color: var(--st-text);
  font-size: 12.5px; font-weight: 650; line-height: 1;
}
#app.concept-std .st-social-chips .btn[aria-pressed="true"],
.concept-std .st-reports__controls .st-segment__item[aria-pressed="true"] {
  color: var(--st-accent); background: var(--st-accent-bg); border-color: var(--st-accent);
}
/* The 3D view's HUD keeps its own glass chip: square-shouldered and a full 44 tall over the scene.
   :where, so the immersive rules in section 27b still outrank these. */
.concept-std :where(.st-sv-hud) .st-segment { min-height: 0; gap: 4px; padding: 0; border: 0; border-radius: var(--st-radius-sm); background: none; }
.concept-std :where(.st-sv-hud) .st-segment .st-segment__item {
  box-sizing: content-box; min-height: 24px; height: 24px; padding: 0 8px; border-radius: 8px; font-size: 11.5px;
  background: transparent; color: var(--st-text); box-shadow: none;
}
.concept-std .st-sv-hud .st-segment .st-segment__item[aria-selected="true"] { background: var(--st-accent); color: var(--st-accent-ink); box-shadow: none; }
.concept-std .st-system3d--immersive .st-sv-mode .st-segment__item[aria-selected="true"] { background: rgba(255, 255, 255, .12); color: var(--st-text); }
.concept-std .st-figure-strip { gap: 0; }
.concept-std .st-figure-strip__tile { min-width: 0; padding: 3px 8px; border-inline-start: 1px solid var(--st-line-soft); }
.concept-std .st-figure-strip__tile:first-child { border-inline-start: 0; }
.concept-std .st-figure-strip__label,
.concept-std .st-figure-strip__value,
.concept-std .st-figure-strip__sub { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.concept-std .st-figure-strip__label { font-size: 11.5px; line-height: 14px; color: var(--st-muted); }
.concept-std .st-figure-strip__value { font-size: 15px; font-weight: 700; line-height: 18px; }
.concept-std .st-figure-strip__sub { font-size: 12px; color: var(--st-muted); line-height: 14px; }
.concept-std .st-head__title { font-size: 17px; }
.concept-std .st-head__context { flex: 1; margin: 0; }
.concept-std .st-head__print { display: inline-flex; align-items: center; gap: 4px; }
.concept-std .st-head__print-label { display: none; }
.concept-std .st-head__detail { display: inline-flex; align-items: center; gap: 4px; }
.concept-std .st-head--detail .st-head__context { order: 5; }
@media (min-width: 1024px) {
  .concept-std .st-figure-strip { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .concept-std .st-head__print-label { display: inline; }
}
@media (pointer: coarse) {
  .concept-std .st-segment .st-segment__item::after,
  .concept-std .st-reports__controls .st-segment__item::after {
    content: ''; position: absolute; inset: calc(50% - var(--st-size-touch) / 2) 0;
  }
  .concept-std :where(.st-sv-hud) .st-segment .st-segment__item::after { content: none; }
  .concept-std :where(.st-sv-hud) .st-segment .st-segment__item { padding-block: 10px; margin-block: -10px; }
}

.concept-std .st-figure-strip__tile[data-tone="warning"] .st-figure-strip__value { color: var(--st-warning); }
.concept-std .st-figure-strip__tile[data-tone="danger"] .st-figure-strip__value { color: var(--st-danger); }
.concept-std .st-figure-strip__tile[data-tone="success"] .st-figure-strip__value { color: var(--st-success); }

.concept-std .st-figure-strip__tile:nth-child(n+5) { display: none; }
@media (min-width: 1024px) { .concept-std .st-figure-strip__tile:nth-child(n+5) { display: block; } }

.concept-std .st-figure-strip__sub { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; max-height: 28px; }
.concept-std .st-head__detail { flex: none; white-space: nowrap; gap: 2px; }
.concept-std .st-head__switcher { display: inline-flex; align-items: center; gap: 2px; }
.concept-std .st-head__switcher .st-icon { width: 14px; height: 14px; }
@media (max-width: 1023px) {
  .concept-std .st-head { flex-wrap: wrap; }
  .concept-std .st-head__context { order: 5; flex-basis: 100%; white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; max-height: 36px; }

  .concept-std .st-head--detail .st-head__title { font-size: 16px; }
  .concept-std .st-head .st-head__switcher { font-size: 11px; padding-inline: 3px; }
  .concept-std .st-head__actions { gap: 2px; }
  .concept-std .st-head__detail .btn { width: 26px; padding-inline: 0; }
}

.concept-std .st-grid__table .st-row { display: flex; align-items: center; min-height: 26px; height: 26px; padding: 0; gap: 4px; border: 0; }
.concept-std .st-grid__table .st-row__lead { width: 22px; height: 22px; min-width: 22px; padding: 0; }
.concept-std .st-grid__table .st-row__lead .st-icon { width: 22px; height: 22px; }
.concept-std .st-grid__table .st-row__body { display: inline-flex; flex-direction: row; flex-wrap: nowrap; align-items: center; gap: 6px; min-width: 0; }
.concept-std .st-grid__table .st-row__title,
.concept-std .st-grid__table .st-row__sub { flex: 0 1 auto; width: auto; overflow: hidden; text-overflow: ellipsis; font-size: 12px; line-height: 18px; white-space: nowrap; }

#app.concept-std main.game-main .st-head .btn { min-width: 0; min-height: 26px; height: 26px; padding: 0 7px; display: inline-flex; align-items: center; justify-content: center; }
#app.concept-std main.game-main .st-head .st-head__back,
#app.concept-std main.game-main .st-head__detail .btn { width: 26px; padding-inline: 0; }
/* The way back out of a page, in words: the head's one full-size control. */
#app.concept-std main.game-main .st-head .st-head__backlink { min-height: var(--st-size-control); height: var(--st-size-control); padding: 0 12px; background: var(--st-panel); font-size: 12.5px; font-weight: 650; white-space: nowrap; }
.concept-std .st-head__back { flex: none; }
.concept-std .st-head--colony .st-head__actions { flex: none; }
@media (pointer: coarse) {
  #app.concept-std main.game-main .st-head .st-head__back::after,
  #app.concept-std main.game-main .st-head__detail .btn::after { inset-inline: -9px; }
}

/* ---------- Tap floor on phones: rows stay compact, what is inside them does not get smaller to tap ------ */
@media (pointer: coarse) {
  /* A cell's link takes the height of its 32 px row; the padding is given back, so nothing moves. */
  .concept-std .st-grid__table tbody a:not(.btn) { padding-block: 9px; margin-block: -9px; }
  /* A link around a clamped block is no tap area at all while it stays inline: the padding goes to its empty lines. */
  .concept-std .st-grid__table tbody a:has(> [style*="-webkit-box"]) { display: block; }
  .concept-std a.st-figure-strip__value { padding-block: 7px; margin-block: -7px; }
  #app.concept-std .st-grid__table button.st-row { min-height: 32px; }
  /* !important because the research card sets its Pause button's height inline, for a mouse. */
  #app.concept-std .st-cta--quiet { min-height: 32px !important; }
  /* The header's buttons carry a 9 px tap margin, so the badge's corner offset put it half off the screen. */
  .concept-std .shell-header--game .mail-badge { top: 3px; }
}

/* ---------- 40. Colony pop-ups: the info window, the Queue window, the group actions ----------
   One background, the dialog's own. Rules between things rather than boxes round them, one row layout for a
   fact, and the picture given room. The owner's "the info window is rough looking" was a black panel inside
   a navy one (the scope wrapper painting the app's page background), a picture against the header rule, and a
   Cost row that wrapped differently from the rows around it. */
.concept-std .st-info { display: flex; flex-direction: column; gap: 12px; min-width: 0; font-size: 13px; line-height: 1.4; }
.concept-std .st-info p, .concept-std .st-info dl, .concept-std .st-info dd, .concept-std .st-info ul { margin: 0; padding: 0; }
.concept-std .st-info__stock, .concept-std .st-info__tiers { list-style: none; }
.concept-std .st-info__facts { display: block; }
.concept-std .st-info__hero { display: flex; align-items: flex-start; gap: 12px; }
.concept-std .st-info__art { flex: 0 0 76px; width: 76px; }
.concept-std .st-info__art .st-art { background: var(--st-panel-raised); }
.concept-std .st-info__about { flex: 1 1 0; min-width: 0; color: var(--st-text); overflow-wrap: break-word; }
.concept-std .st-info__fact { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 6px 0; border-top: 1px solid var(--st-line-soft); }
.concept-std .st-info__fact:first-child { border-top: 0; padding-top: 0; }
.concept-std .st-info__fact:last-child { padding-bottom: 0; }
.concept-std .st-info__fact dt { flex: 0 1 auto; min-width: 0; color: var(--st-muted); font-weight: 400; }
.concept-std .st-info__fact dd { display: flex; flex: 1 1 auto; flex-direction: column; align-items: flex-end; min-width: 0; color: var(--st-text); font-weight: 650; text-align: right; overflow-wrap: break-word; }
.concept-std .st-info__fact--long { display: block; }
.concept-std .st-info__fact--long dd { align-items: flex-start; margin-top: 2px; font-weight: 400; text-align: left; }
.concept-std .st-info__fact-value--warning { color: var(--st-warning); }
.concept-std .st-info__fact-value--danger { color: var(--st-danger); }
.concept-std .st-info__heading { margin: 0 0 -6px; color: var(--st-muted); font-size: 12px; font-weight: 650; line-height: 1.3; }
.concept-std .st-info__res, .concept-std .st-info__tier { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-top: 1px solid var(--st-line-soft); }
.concept-std .st-info__res:first-child, .concept-std .st-info__tier:first-child { border-top: 0; }
.concept-std .st-info__res-icon { flex: none; width: 22px; height: 22px; object-fit: contain; }
.concept-std .st-info__res-text, .concept-std .st-info__tier-text { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; }
.concept-std .st-info__res-name { font-weight: 650; overflow-wrap: break-word; }
.concept-std .st-info__res-need { color: var(--st-muted); font-size: 11.5px; overflow-wrap: break-word; }
.concept-std .st-info__res-verdict { flex: none; display: inline-flex; align-items: center; color: var(--st-success); font-weight: 650; text-align: right; }
.concept-std .st-info__res--short .st-info__res-verdict { flex-shrink: 1; max-width: 45%; color: var(--st-warning); font-size: 12px; }
.concept-std .st-info__tier > .st-icon { flex: none; color: var(--st-muted); }
.concept-std .st-info__note { color: var(--st-muted); font-size: 12px; overflow-wrap: break-word; }
.concept-std .st-info__note:empty { display: none; }
.concept-std .st-info__warn { color: var(--st-warning); font-size: 12px; overflow-wrap: break-word; }
.concept-std .st-info p.st-info__lock { padding: 6px 8px; border-left: 3px solid var(--st-warning); background: var(--st-warning-dim); color: var(--st-text); font-size: 12px; }
.concept-std .st-info p.st-info__refusal { padding: 6px 8px; border-left: 3px solid var(--st-danger); background: var(--st-danger-dim); color: var(--st-text); font-size: 12px; overflow-wrap: break-word; }
.concept-std .st-info__lock[hidden], .concept-std .st-info__refusal[hidden], .concept-std .st-info__qty[hidden], .concept-std .st-info__warn[hidden] { display: none; }
.concept-std .st-info__qty { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-block: 1px solid var(--st-line-soft); }
.concept-std .st-info__qty-label { color: var(--st-text); font-weight: 650; }
.concept-std .st-info__actions { justify-content: flex-end; flex-wrap: wrap; width: 100%; gap: 8px; }
.concept-std .st-qty { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.concept-std ~ dialog.modal .st-qty .st-qty__btn { display: inline-grid; place-items: center; width: 40px; min-width: 40px; height: 40px; min-height: 40px; padding: 0; font-size: 18px; }
.concept-std .st-qty__input { box-sizing: border-box; width: 64px; height: 40px; padding: 0 4px; border: 1px solid var(--st-line); border-radius: var(--st-radius-sm); background: var(--st-panel-raised); color: var(--st-text); color-scheme: dark; font: inherit; font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: center; }
.concept-std .st-qty__input:focus-visible { border-color: var(--st-accent); outline: none; }
/* The head and the button stay on the screen on the smallest phone, and only the body between them scrolls. */
.concept-std ~ dialog.modal:has(.st-info)[open] { display: flex; flex-direction: column; overflow: hidden; }
.concept-std ~ dialog.modal:has(.st-info) .modal-head, .concept-std ~ dialog.modal:has(.st-info) .modal-foot { flex: none; }
.concept-std ~ dialog.modal:has(.st-info) .modal-body { flex: 1 1 auto; min-height: 0; max-height: none; overscroll-behavior: contain; }
/* Two lines in one table cell: the thing, and what is true of it. */
.concept-std .st-grid-stacked { display: flex; flex-direction: column; gap: 1px; min-width: 0; padding-block: 2px; }
.concept-std .st-grid-stacked__title { font-weight: 650; line-height: 1.25; }
.concept-std .st-grid-stacked__sub { color: var(--st-muted); font-size: 11.5px; font-weight: 400; line-height: 1.3; }
.concept-std .st-pane-status { display: block; min-width: 12rem; }
/* The heading over what stands at this colony, with its total. */
.concept-std .st-pane-heading { margin: 10px 0 0; font-size: var(--st-font-section); font-weight: 650; }
.concept-std .st-pane-heading__count { color: var(--st-muted); font-weight: 400; }
.concept-std .st-pane-note { margin: 0; color: var(--st-muted); font-size: 12px; }
.concept-std .st-pane-upgrade { display: grid; gap: 6px; padding: 8px 0; border-top: 1px solid var(--st-line-soft); }
.concept-std .st-pane-upgrade__words { margin: 0; color: var(--st-text); font-size: 12.5px; line-height: 1.4; overflow-wrap: break-word; }
.concept-std .st-pane-upgrade__go { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
#app.concept-std main.game-main .st-pane-upgrade__go .btn { flex: 1 1 12rem; width: auto; min-height: var(--st-size-control); height: auto; padding: 5px 12px; white-space: normal; overflow-wrap: break-word; font-size: 12.5px; line-height: 1.25; }
.concept-std .st-pane-upgrade__go .st-qty__input { height: var(--st-size-control); }
