/* ==========================================================================
   Astral Sovereignty — "Mint" concept skin (foundation pass)

   A second look for the game, built from the owner's concept asset pack: navy
   panels, a mint-cyan accent, big rounded cards, hero artwork with a scrim, and
   five destinations along the bottom where the thumb already is. It reproduces
   the pack's ten reference screens; this file is the kit those screens are
   assembled from, and ui/concept/mint/kit.js is its DOM half.

   SCOPE. Every rule is scoped under `.concept-mint` — a class
   ui/concept/mint/shell.js puts on #app when it assembles and app.js clears at
   the top of every render — so with the class absent this file changes nothing
   at all. tests/concept_mint_shell.test.js pins that scoping the same way
   tests/shell_concept.test.js pins shell-app.css's.

   WHY THIS ONE MAY HAVE COLOURS WHEN shell-app.css MAY NOT. shell-app.css is
   an ARRANGEMENT — pure geometry over the shipped paint, so the Command preset
   still skins it. This is not an arrangement, it is a SECOND SKIN, and the
   owner asked for it as one: the point of the mint concept is to be compared
   against the classic look side by side. So it declares its own palette, and it
   declares it by RETUNING game.css's own tokens inside the scope as well as
   adding its own. That second half is what makes the concept survivable: a tab
   with no mint screen yet renders its CLASSIC screen inside this shell, and
   without the retune that screen would be a slab of the old palette inside a
   mint frame. With it, every screen in the game is at least mint-coloured from
   the first commit, and screens get their mint LAYOUT one at a time.

   Discipline (do not relax these):
   - game.css and preset-command.css ARE NOT TOUCHED. Everything below is an
     override inside the scope, so a classic player is provably unaffected.
   - Loaded AFTER preset-command.css and after shell-app.css, so at equal
     specificity this skin wins inside its own scope.
   - Every tap target is at least --cm-tap. The owner plays on a 360px phone.
   - No braces inside comments: tests parse this file by counting them.
   - Any animation added here ships with its own prefers-reduced-motion guard.
   ========================================================================== */

/* ---------- 1. Tokens ------------------------------------------------------
   Straight from the pack's ui/tokens.json. The names are prefixed --cm- 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 makes section 1c possible. The Astral theme is nothing but a second set
   of values for these same names, so a hex code written anywhere else in this
   file is a colour the theme cannot reach. tests/concept_mint_theme.test.js
   fails on one.

   TWO ACCENT FAMILIES, and they mean different things. --cm-accent is the
   ACTION colour: the CTA, the selected segment, the destination you are on,
   the meter. --cm-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-mint,
.concept-mint ~ dialog.modal,
.concept-mint ~ #toasts {
  --cm-bg:            #080f1b;
  --cm-bg-1:          #0b1524;
  --cm-bg-2:          #0f1c2c;
  --cm-panel:         #142233;
  --cm-panel-raised:  #1a2c40;
  --cm-panel-3:       #21374e;
  --cm-line:          #344a60;
  --cm-line-mid:      #263a4e;
  --cm-line-soft:     #1c2c3d;
  --cm-edge-ui:       #4d6a86;
  --cm-track:         #2b4052;
  --cm-grabber:       #637b90;
  --cm-text:          #edf1f2;
  --cm-muted:         #b5c6d8;
  --cm-text-3:        #adbfd2;
  --cm-text-4:        #a3b5c7;
  --cm-accent:        #69dce5;
  --cm-accent-ink:    #06252b;
  --cm-link:          #69dce5;
  --cm-link-deep:     #10404a;
  --cm-success:       #79dca0;
  --cm-warning:       #ffd074;
  --cm-warning-ink:   #281600;
  --cm-danger:        #ff9290;

  /* Tints for the toned rows. The pack ships flat swatches for these; a tint
     over the panel keeps a row readable at any panel darkness. */
  --cm-warning-bg:    #302819;
  --cm-danger-bg:     #341e28;
  --cm-success-bg:    #142d24;
  --cm-accent-bg:     #12303a;

  /* The translucent halves: a dim wash of a semantic colour, the two scrims
     the frame paints over artwork and behind the More sheet, and the glow and
     the edge a hero with no art draws instead of a photograph. */
  --cm-link-dim:      rgba(105, 220, 229, .13);
  --cm-warning-dim:   rgba(255, 208, 116, .13);
  --cm-success-dim:   rgba(121, 220, 160, .13);
  --cm-danger-dim:    rgba(255, 146, 144, .12);
  --cm-scrim:         rgba(4, 8, 14, .6);
  --cm-glass:         rgba(8, 15, 27, .72);
  --cm-glass-soft:    rgba(8, 15, 27, .45);
  --cm-hero-fade:     rgba(8, 15, 27, .55);
  --cm-hero-glow:     rgba(105, 220, 229, .18);
  --cm-hero-edge:     rgba(105, 220, 229, .45);

  /* Ink ON the artwork. The webp banners are the same pictures in both
     palettes, so these barely move: white and a cool near-white, both over a
     drop shadow the art cannot brighten away. */
  --cm-art-ink:       #ffffff;
  --cm-art-ink-2:     #dbe6f2;

  /* The pack's tokens.json says 18/12/76. Those are the MOCK's numbers at
     2.5x DPR: measured off the reference PNGs (887px wide for a 360px screen)
     the same corners come out at 14 and 10 CSS px and the bar at 64. The
     reference is the thing the owner is comparing against, so the reference
     wins over the token file. --cm-tap is the exception and stays at 48: it is
     a thumb, not a drawing.

     --cm-header-icon is the one place a tap target is smaller than --cm-tap.
     The top line is a 53px band carrying four of them beside a clock that
     never truncates; 44px is WCAG 2.2 AAA and the render harness's own floor,
     and nothing INSIDE the screen uses it. */
  --cm-radius:        14px;
  --cm-radius-sm:     10px;
  --cm-tap:           48px;
  --cm-header-icon:   44px;
  --cm-nav-h:         60px;
  --cm-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. */
  --cm-safe-top:      env(safe-area-inset-top, 0px);
  --cm-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-mint,
.concept-mint ~ dialog.modal,
.concept-mint ~ #toasts {
  --bg-0:      var(--cm-bg);
  --bg-1:      var(--cm-bg-1);
  --bg-2:      var(--cm-bg-2);
  --panel:     var(--cm-panel);
  --panel-2:   var(--cm-panel-raised);
  --panel-3:   var(--cm-panel-3);

  --line:      var(--cm-line-mid);
  --line-soft: var(--cm-line-soft);
  --line-lit:  var(--cm-line);
  --edge-ui:   var(--cm-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(--cm-link);
  --blue-lit:  var(--cm-link);
  --blue-deep: var(--cm-link-deep);
  --blue-dim:  var(--cm-link-dim);

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

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

  --rad:       var(--cm-radius-sm);
  --rad-sm:    8px;
  --tab-current: var(--cm-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 --cm-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(--cm-bg);
  --on-danger: var(--cm-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(--cm-bg);
  color: var(--cm-text);
  font-family: var(--cm-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-mint h1,
.concept-mint h2,
.concept-mint h3,
.concept-mint .card > h2,
.concept-mint details.card--fold > summary h2,
.concept-mint ~ dialog.modal .modal-head h2,
.concept-mint ~ dialog.modal .btn,
.concept-mint .card h3,
.concept-mint .btn,
.concept-mint .pill,
.concept-mint .chip,
.concept-mint .kv dt,
.concept-mint .tbl th,
.concept-mint .tabbar a,
.concept-mint .map-key > summary,
.concept-mint .sub-tabbar a {
  text-transform: none;
  letter-spacing: normal;
}
.concept-mint h1,
.concept-mint 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-mint .card > h2 { background: none; padding-bottom: 0; }

/* ---------- 1c. The ASTRAL theme -------------------------------------------
   The same layout in the game's own colours. The owner's words: "mint is cool
   but it's just not Astral's blue and orange look… I wouldn't mind more orange
   in it with the blue like the website colors."

   So this is a THEME, not a second layout: nothing below is a rule about a
   box, only a second set of values for section 1's tokens. Every measurement,
   every corner, every tap target and every piece of artwork is the mint one.
   ui/concept/mint/shell.js adds `concept-mint--astral` beside `.concept-mint`
   when core/concepts.js's `asov.conceptTheme` says so, and the extra class is
   what wins the specificity contest against the block above — position in the
   file is not doing the work here.

   WHERE THE VALUES COME FROM. Not invented: astralsovereignty.com's own
   stylesheet (the near-black --bg-0, the text-safe blues, the amber it marks
   sovereignty and "live" with) and the client's own Command preset (--blue-lit
   #79b4ff, --cmd-edge-lit #57c8ff). Blue is the SURFACE and the INFORMATION —
   panels, hairlines, links, glyphs. Orange is the ACTION — the CTA, the
   segment you are on, the destination you are on, the meter, the primary
   button. That division is why the two never fight: one is what the screen is
   made of, the other is what you can do to it.

   The three semantic colours keep their meaning, exactly as the mint block
   requires: warning is gold, danger is a warm red, success stays green. Gold
   and orange are close enough to be a real risk here, so the warning gold is
   pushed light (#ffc65a against the accent's #ff8a1f) and every toned row
   still says what it is in words as well as colour.

   CONTRAST. Every text/background pair below measures 4.5:1 or better —
   6.4:1 is the floor (accent on its own tint) and most are past 8:1. The
   render harness is the thing that proves it, at 412x915 with the theme
   seeded; tests/concept_mint_theme.test.js proves the cheaper half, that the
   theme answers for every colour the base decides. */

.concept-mint.concept-mint--astral,
.concept-mint.concept-mint--astral ~ dialog.modal,
.concept-mint.concept-mint--astral ~ #toasts {
  --cm-bg:            #04060e;
  --cm-bg-1:          #070b16;
  --cm-bg-2:          #0a1120;
  --cm-panel:         #0e1729;
  --cm-panel-raised:  #142137;
  --cm-panel-3:       #1b2b45;
  --cm-line:          #2b4a72;
  --cm-line-mid:      #1c2f4a;
  --cm-line-soft:     #14233a;
  --cm-edge-ui:       #4c6b96;
  --cm-track:         #22344f;
  --cm-grabber:       #55708f;
  --cm-text:          #eaf1ff;
  --cm-muted:         #b9c8de;
  --cm-text-3:        #9fb3cd;
  --cm-text-4:        #94a9c5;
  --cm-accent:        #ff8a1f;
  --cm-accent-ink:    #180d00;
  --cm-link:          #8fc0ff;
  --cm-link-deep:     #14345c;
  --cm-success:       #6fd39a;
  --cm-warning:       #ffc65a;
  --cm-warning-ink:   #2a1c00;
  --cm-danger:        #ff8f8c;

  --cm-warning-bg:    #33270e;
  --cm-danger-bg:     #331c22;
  --cm-success-bg:    #0f2a20;
  --cm-accent-bg:     #5a2e06;

  --cm-link-dim:      rgba(143, 192, 255, .13);
  --cm-warning-dim:   rgba(255, 198, 90, .13);
  --cm-success-dim:   rgba(111, 211, 154, .13);
  --cm-danger-dim:    rgba(255, 143, 140, .12);
  --cm-scrim:         rgba(2, 4, 10, .62);
  --cm-glass:         rgba(4, 6, 14, .72);
  --cm-glass-soft:    rgba(4, 6, 14, .45);
  --cm-hero-fade:     rgba(4, 6, 14, .55);
  /* The hero with no artwork: a blue wash lit from the top-left corner, the
     same one the website's panels are lit with, edged in the accent so the
     crest still reads as a mounted pennant. */
  --cm-hero-glow:     rgba(87, 200, 255, .16);
  --cm-hero-edge:     rgba(255, 138, 31, .45);

  --cm-art-ink:       #ffffff;
  --cm-art-ink-2:     #dfe9fb;
}

/* ---------- 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-mint { height: 100dvh; }
/* The same class on the wrapper ui/concept/mint/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-mint.cm-dialog-scope, .modal-foot > .concept-mint.cm-dialog-scope { height: auto; }

/* 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-mint),
body:has(> #app.concept-mint) { 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-mint > .shell-header,
.concept-mint .shard-shutdown-strip,
.concept-mint .combat-strip,
.concept-mint > .sub-tabbar,
.concept-mint > .cm-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-mint > .shell-header,
.concept-mint .shard-shutdown-strip,
.concept-mint .combat-strip { position: static; }

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

/* ---------- 3. The top line ------------------------------------------------
   app.js's own header node, restyled. It is NOT rebuilt: #tick-chip,
   #menu-btn, #empire-id, #mail-btn and the Refresh button all keep working
   because they are the very nodes the rest of the app already patches by id.

   ONE ROW, and it is this pass's single biggest saving. It was two rows and
   measured 113px at 360x780 — a seventh of the phone spent on chrome before
   the game starts. The pack's own references draw ONE row: the mark, the
   clock, the orders badge, nothing else. This one carries six things in 53px:

     menu · brand · Next-tick pill · [space] · orders badge · mail · refresh

   IT IS `order` AND NOT A REBUILD. Every child keeps the id, the handler and
   the aria-label app.js gave it and stays where it was in the DOM, so the tab
   order still follows the source and updateMailBadge(), the tick painter and
   ui/drawer.js all still find their nodes.

   WHAT LEAVES THE ROW, and why that costs nothing. The empire identity block —
   crest, name, rank — is the one thing here that cannot fit, and the one thing
   that is already reachable twice over: the Empire screen's hero prints the
   name at the top of the game's first tab, and the profile sheet this block
   opens is the hamburger's own "Your profile" entry (ui/drawer.js), one tap
   away on this very row. So it is hidden in THIS skin only; the node, its id
   and its click handler are untouched, which is what keeps app.js's
   fillEmpireIdentity() correct for every other layout.

   Measured at 360px, where the content box is 344px: menu 44 + mark 26 +
   clock ~112 + badge 44 + mail 44 + refresh 44 = 314, plus six 4px gaps = 338.
   The wordmark is the only thing on the row that CAN shorten — the clock never
   truncates and everything else is a tap target — so it is the one that does:
   its second word below 480px, exactly as game.css's bare header already does
   at that breakpoint, and its words entirely below 400px. The mark's
   accessible name is on the element itself, so nothing is lost to anyone
   reading the page rather than looking at it. */

.concept-mint > .shell-header--game {
  height: auto;
  min-height: 52px;
  padding: calc(4px + var(--cm-safe-top)) 8px 4px;
  flex-wrap: nowrap;
  align-items: center;
  align-content: center;
  column-gap: 4px;
  row-gap: 0;
  justify-content: flex-start;
  background: var(--cm-bg);
  border-bottom: 1px solid var(--cm-line);
}

/* app.js's row break. One row here, so it is not drawn — but the element stays
   in the DOM, because ui/concept/mint/shell.js finds the orders badge's
   insertion point by it. */
.concept-mint > .shell-header--game .header-break { display: none; }

/* The arrangement, left to right. */
.concept-mint > .shell-header--game .menu-btn { order: 1; }
.concept-mint > .shell-header--game .brand { order: 2; }
.concept-mint > .shell-header--game .tick-chip { order: 3; }
.concept-mint > .shell-header--game .spacer { order: 4; flex: 1 1 auto; min-width: 0; }
.concept-mint > .shell-header--game .cm-orders-badge { order: 5; }
.concept-mint > .shell-header--game .btn { order: 6; }
.concept-mint > .shell-header--game .mail-btn { order: 7; }
.concept-mint > .shell-header--game .icon-btn:not(.menu-btn):not(.mail-btn) { order: 8; }

/* The identity block, and the paragraph above is the whole argument for it.
   Hidden rather than removed: app.js still built it, still fills it and still
   owns its handler. */
.concept-mint > .shell-header--game .empire-id { display: none; }

.concept-mint > .shell-header--game .brand {
  flex: 0 1 auto; min-width: 0; gap: 6px;
  font-size: 14px; letter-spacing: -.01em; color: var(--cm-text);
}
.concept-mint > .shell-header--game .brand b {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.concept-mint > .shell-header--game .brand span { color: var(--cm-text); }
.concept-mint > .shell-header--game .brand img { width: 22px; height: 22px; }

/* ON A PHONE THE MARK IS ITS ICON. Measured at 412x915, the width the owner
   plays at: menu 44 + mark 74 + clock 128 + badge 44 + mail 44 + refresh 44 and
   five 4px gaps is 392 in a 396px box — four pixels of slack, and the word
   "Astral" wanted six more, so it rendered as "Astra…" (clip-x=1 on every
   route). Worse, the slack is content-dependent: an hour-long countdown grows
   the clock by 20px and takes the word out at any width.

   So below 480px the words go and the icon stays. Nothing is lost to anyone
   reading the page rather than looking at it — app.js states the mark's
   accessible name with aria-label on the element itself — and this is the same
   trade game.css already makes on the bare header at the same breakpoint, one
   word further. */
@media (max-width: 479px) {
  .concept-mint > .shell-header--game .brand b { display: none; }
}

/* AND BELOW 400px THE MARK ITSELF GOES, because the row ran out of width for a
   fact the player needs more than it needs a logo.
   MEASURED at 360px, in the demo and signed in alike — the demo spends 44px of
   this row on "Exit demo" and a signed-in player spends the same 44px on the
   mailbox, so the two are equally tight: menu 44 + mark 21.72 + three 44px tap
   targets + six 4px gaps + 16px of padding leaves the pill 122.28px. "Tick 182"
   beside the reserved countdown box needs 138.88px, so the tick number
   ellipsised — and "Tic…" is not a shortened word, it is a number that reads as
   a different number.
   The mark is the one thing on this row that says nothing the rest of the screen
   does not: it is decoration by design (app.js brandMark builds a <span
   role="img">, deliberately not even a link, because at this height it could
   never be a 44px target), and the game's name is on the drawer, the title bar
   and every tab. Its 21.72px and its 4px gap put the pill at 148px, which holds
   a four-digit tick and its countdown with room to spare. The pill's own padding
   comes in 2px on each side at the same breakpoint, which is the last 4px and is
   invisible next to a legible number.
   The limit, stated rather than discovered later: a FIVE-digit tick ("Tick
   17,500", the twelve-month half-hour shard) still wants 153px here and
   ellipsises at 360px. It fits from 390px up. */
@media (max-width: 399px) {
  .concept-mint > .shell-header--game .brand { display: none; }
}

/* The clock, as the pack draws it: an outlined pill with the state in its
   colour. Rigid — it is the most-looked-at element in the game and it never
   gives way; the wordmark beside it is what shortens. */
.concept-mint > .shell-header--game .tick-chip {
  flex: 0 1 auto;
  height: auto;
  min-height: 34px;
  padding: 3px 9px;
  gap: 5px;
  border-radius: 999px;
  border: 1px solid var(--cm-line);
  background: var(--cm-panel);
  color: var(--cm-text);
  font-family: var(--cm-font);
  font-size: 13px;
  font-weight: 600;
  justify-content: center;
  overflow: hidden;
}
/* The countdown rewrites itself every second and CHANGES LENGTH doing it, so
   its box is reserved or the header re-wraps under the player's thumb. It WAS
   13ch, "Next tick 4:58" at this size. The chip now carries the tick's number
   as a segment of its own (core/format.js tickChipView) and the words went with
   it, so this box holds the countdown alone: "1:02:09" is the longest one any
   shard shows, and 7ch covers it: this skin is NOT monospace, so `ch` is the
   width of `0` and five digits plus two colons come in under seven of them —
   measured in headless Chrome at 412px, 1ch is 9.05px here and "1:02:09" is
   55.63px, i.e. 6.15ch. Freeing those six characters is what pays for the
   number: the pill measures 138.86px with "Tick 182" in front of it, against
   176px if the 13ch reserve had been left alone, and 132.66px as it shipped.
   Capped against the viewport because ch grows with system text, and uncapped it
   would push the mailbox off a 360px screen at 200%. */
.concept-mint > .shell-header--game .tick-chip .tick-text {
  min-width: min(7ch, 20vw);
  text-align: center;
}
/* The number in front of it. Quieter than the countdown — a smaller, lighter
   grade of the same colour, so the pill reads as two facts rather than one long
   string, and the countdown stays the thing the eye lands on. Not a dimmer
   colour: the tone colours here are drawn against --cm-panel and dimming them
   is contrast this pill has not got to spare. */
.concept-mint > .shell-header--game .tick-chip .tick-num {
  font-size: 12px;
  font-weight: 500;
}
/* Both segments are numbers that rewrite themselves in place, and this skin's
   font is proportional: without tabular figures a `1` is narrower than a `4`,
   so "Tick 182" -> "Tick 184" and every second of the countdown would nudge the
   pill's contents sideways inside their own boxes. */
.concept-mint > .shell-header--game .tick-chip { font-variant-numeric: tabular-nums; }

/* The narrow-screen half of the trade above (§3, the 400px rule that drops the
   mark): the pill comes in 2px on each side and the number comes down a point.
   Together they are 9px, and they are what puts a FOUR-digit tick — which is
   every shard past its third week — on a 360px screen without an ellipsis.
   Written here rather than up beside the brand rule because these two override
   the chip's own declarations above and would lose the cascade there. */
@media (max-width: 399px) {
  .concept-mint > .shell-header--game .tick-chip { padding: 3px 7px; gap: 4px; }
  .concept-mint > .shell-header--game .tick-chip .tick-num { font-size: 11px; }
  /* WHILE A TICK RESOLVES the rigid segment is a WORD — "Resolving…", 84.45px,
     wider than any countdown — and at 360px that is 2px more than the pill has.
     The number is the segment that gives way, and for this one state it gives
     way entirely instead of ellipsising: "Tick 18…" is not a shortened number,
     it is a different one, and a state that lasts seconds is not worth printing
     a wrong tick for. The pill is exactly what it was before the split while it
     lasts, and the accessible name still leads with the tick number. */
  .concept-mint > .shell-header--game .tick-chip.is-due .tick-num { display: none; }
}
.concept-mint > .shell-header--game .tick-chip--ok    { color: var(--cm-success); border-color: var(--cm-success); }
.concept-mint > .shell-header--game .tick-chip--warn  { color: var(--cm-warning); border-color: var(--cm-warning); }
.concept-mint > .shell-header--game .tick-chip--bad   { color: var(--cm-danger);  border-color: var(--cm-danger); }
.concept-mint > .shell-header--game .tick-chip--info  { color: var(--cm-link);  border-color: var(--cm-link); }

/* The row's tap targets. 44px rather than the screen's own 48px floor: this is
   a 53px band carrying four of them beside a clock that never truncates, and
   44 is WCAG 2.2 AAA and the render harness's own minimum. --cm-tap stays 48
   for everything inside the screen, where there is room for it. */
.concept-mint > .shell-header--game .icon-btn {
  flex: none;
  width: var(--cm-header-icon); height: var(--cm-header-icon);
  min-width: var(--cm-header-icon); min-height: var(--cm-header-icon);
  border-radius: var(--cm-radius-sm);
  color: var(--cm-muted);
}
.concept-mint > .shell-header--game .icon-btn:hover { color: var(--cm-text); }
/* The row's one text button is the demo's "Exit demo" — and on this row it is
   never text: it is its glyph, with the words kept as its accessible name by
   ui/concept/mint/shell.js.

   The FLAT background is not cosmetic. The Command preset paints every .btn
   with a gradient, and a gradient is a background no contrast check can
   resolve from styles — this one button was the single "contrast unknown"
   finding on every mint screen the harness rendered. Flat panel under
   --cm-text is 11.6:1 and provable. */
.concept-mint > .shell-header--game .btn {
  padding: 0 8px; font-size: 13px; border-radius: var(--cm-radius-sm);
  min-height: var(--cm-header-icon);
  background-image: none;
  background-color: var(--cm-panel-raised);
  border-color: var(--cm-line);
  color: var(--cm-text);
}
.concept-mint > .shell-header--game .cm-exit {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: var(--cm-header-icon);
}
.concept-mint > .shell-header--game .cm-exit .cm-icon { width: 20px; height: 20px; }
.concept-mint > .shell-header--game .cm-exit__label { white-space: nowrap; }
@media (max-width: 559px) {
  .concept-mint > .shell-header--game .cm-exit { width: var(--cm-header-icon); padding: 0; }
  .concept-mint > .shell-header--game .cm-exit__label { display: none; }
}

/* The orders badge — the one control this shell adds. The pack's reference
   puts a clipboard with a count in the top-right corner, and it is the shortest
   path in the game from "how many orders are riding into this tick" to the list
   itself. A link, not a button: it goes to a real route. */
.concept-mint .cm-orders-badge {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--cm-header-icon); height: var(--cm-header-icon);
  border-radius: var(--cm-radius-sm);
  border: 1px solid var(--cm-line);
  background: var(--cm-panel);
  color: var(--cm-muted);
  text-decoration: none;
}
.concept-mint .cm-orders-badge:hover { color: var(--cm-text); text-decoration: none; }
.concept-mint .cm-orders-badge .cm-icon { width: 22px; height: 22px; }
.concept-mint .cm-orders-badge__count {
  position: absolute; top: -5px; right: -5px;
  min-width: 19px; height: 19px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: 999px;
  background: var(--cm-warning); color: var(--cm-warning-ink);
  font-size: 11px; font-weight: 750; font-variant-numeric: tabular-nums;
}
.concept-mint .cm-orders-badge__count[hidden] { display: none; }

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

.concept-mint .shard-shutdown-strip,
.concept-mint .combat-strip { border-bottom-color: var(--cm-danger); }

/* ---------- 5. The group's own sections ------------------------------------
   app.js's sub-tab strip, drawn as the pack's segmented control. Still the
   node core/nav.js's grouping produced — this places and paints it.

   ONE JOINED BAR, NOT A ROW OF PILLS. It was fully-round 36px chips spread
   along the whole width with the current one a solid mint blob, and the owner
   read it exactly as it drew: too spaced out and too round for the second
   strip on a page that already has a bottom bar. The pack's references draw
   this control ONE way — a single panel-coloured bar that hugs its own labels,
   the current section a soft-cornered accent tint inside it — and it is the
   same control .cm-segment draws inside a screen, so the group's sections and
   a screen's own tabs now read as one family instead of two.

   COMPACTED RATHER THAN HIDDEN, and the choice was between the two. Hiding the
   strip on detail routes would buy the whole 44px back, and the references do
   draw those pages without it — but it would mean this shell DROPPING a node
   app.js handed it, which tests/concept_mint_shell.test.js pins as the one
   thing this frame may never do (a shell that can silently drop the sub-tabs
   is a shell that can silently drop the combat strip), and it would take the
   only route from a colony page to Designer or Orbitals with it. So the strip
   stays and shrinks again: 61px, then 49px, now 44px — the tap box and nothing
   else, because the band, its padding and its bottom rule are all gone.

   THE TAP BOX IS 44px AND THE PAINTED TAB IS 40px, and one declaration does
   it: a 2px TRANSPARENT BORDER with `background-clip: padding-box`. The <a>
   keeps the 44px floor a thumb lands on and the render harness measures — it
   measures the ELEMENT's box, so the tap area is what has to clear the floor,
   not the paint — while the fill stops 2px inside it. That border does three
   jobs at once: it is the bar's 2px inset, it is half the 4px gap between two
   neighbours, and it is the difference between the 10px 14px the label sits in
   and the 8px 12px of real padding. Move it and all three move together. The
   radii are the same arithmetic — 10 on the bar, 8 on the tab — because a
   padding box inside a 2px border rounds exactly 2px tighter.

   THE BAR HUGS ITS CONTENT. `align-self: flex-start` in the frame's column,
   so a two-section group is a two-tab bar and not two tabs stretched across a
   phone; stretch is the flex default and stretch is what spread the chips out.
   Nine sections (Empire) cannot fit at 360px and scroll instead, and the mask
   is what says so. It is switched on by the COUNT, because CSS cannot ask
   whether a box overflows — the same heuristic ui/concept/mint/kit.js applies
   to .cm-segment from JS, and four labels is where a phone runs out of room.
   A MASK and not a gradient background, for .cm-segment's reason: a background
   image under these labels is a contrast the render harness can no longer
   resolve, and an admitted-unknown is worse than no fade. */

.concept-mint > .sub-tabbar {
  position: static;
  /* Hugs its labels rather than stretching across the width. */
  align-self: flex-start;
  max-width: calc(100% - 20px);
  margin: 0 10px;
  display: flex; gap: 0;
  overflow-x: auto; scrollbar-width: none;
  /* No padding and no bottom rule: the tabs' transparent borders ARE the
     inset, and the top line already draws the edge under the chrome. */
  padding: 0;
  border: 0; border-radius: var(--cm-radius-sm);
  background: var(--cm-panel);
  /* game.css fades both ends of this strip since 2026-09-14, because the
     shipped shell's tier-2 strip scrolls and never said so. This layout already
     has its own answer — the one-sided fade below, applied from the item count
     the way .cm-segment does it — so the shared one is turned off rather than
     drawn under it. */
  -webkit-mask-image: none;
  mask-image: none;
}
.concept-mint > .sub-tabbar::-webkit-scrollbar { display: none; }
.concept-mint > .sub-tabbar:has(> a:nth-child(4)) {
  -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));
}
.concept-mint > .sub-tabbar a {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 8px 12px;
  /* The tab is flat text; the tint is the only mark. The border is transparent
     and structural — see the paragraph above — never a visible outline. */
  border: 2px solid transparent; border-radius: var(--cm-radius-sm);
  /* The panel again rather than `none`, exactly as .cm-segment__item does it:
     an opaque tab makes every label's background answerable from the label's
     own element, and it is the colour the bar under it already is. */
  background: var(--cm-panel); background-clip: padding-box;
  color: var(--cm-muted);
  font-size: 14px; font-weight: 600; white-space: nowrap;
}
.concept-mint > .sub-tabbar a:hover { color: var(--cm-text); text-decoration: none; }
/* background-COLOR and not the shorthand: `background:` resets the clip, and
   the tint would fill the whole tap box again. A tint and accent text, not a
   solid fill — the current section is marked, not shouted.

   AND the bottom border is put back to transparent, which is not belt-and-
   braces: game.css marks the current sub-tab with `border-bottom-color` on a
   selector of its own, and it lands on the 2px border this rule's tab carries
   for spacing — a mint underline sitting under the tint, drawn by a stylesheet
   that has no idea this tab is a segment now. */
.concept-mint > .sub-tabbar a[aria-current="page"] {
  background-color: var(--cm-accent-bg); color: var(--cm-accent);
  border-bottom-color: transparent;
}

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

.concept-mint > main.game-main {
  flex: 1 1 auto;
  min-height: 30vh;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
  width: 100%;
  max-width: none;
  padding: 10px 10px calc(12px + var(--cm-safe-bottom));
  margin: 0;
  background: var(--cm-bg);
  animation: cm-enter .16s ease-out both;
}

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

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

/* ---------- 7. The bottom bar ----------------------------------------------
   Five destinations, built by ui/concept/mint/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-mint > .cm-nav {
  position: relative; z-index: 70;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0;
  padding: 4px 4px calc(6px + var(--cm-safe-bottom));
  background: var(--cm-bg);
  border-top: 1px solid var(--cm-line);
}
.concept-mint .cm-nav__item {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  min-height: calc(var(--cm-nav-h) - 12px);
  padding: 4px 2px;
  border: 0; border-radius: 10px;
  background: none;
  color: var(--cm-muted);
  font-family: inherit; font-size: 12px; line-height: 1.2; font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  position: relative;
}
.concept-mint .cm-nav__item:hover { color: var(--cm-text); text-decoration: none; }
.concept-mint .cm-nav__label {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.concept-mint .cm-nav__item .cm-icon { width: 22px; height: 22px; }
.concept-mint .cm-nav__item[aria-current="page"],
.concept-mint .cm-nav__item[aria-expanded="true"] { color: var(--cm-accent); }
/* The mark under the active destination, exactly as the reference draws it. */
.concept-mint .cm-nav__item[aria-current="page"]::after {
  content: ""; position: absolute; left: 22%; right: 22%; bottom: -3px;
  height: 3px; border-radius: 3px; background: var(--cm-accent);
}

/* ---------- 8. Sheets, and the overflow sheet ------------------------------
   .cm-sheet is the kit's bottom sheet (ui/concept/mint/kit.js cmSheet) 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 `.cm-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-mint .cm-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(--cm-nav-h) + var(--cm-safe-bottom));
  border: 1px solid var(--cm-line); border-bottom: 0;
  border-radius: 24px 24px 0 0;
  background: var(--cm-panel);
  color: var(--cm-text);
  box-shadow: 0 -18px 40px rgba(0, 0, 0, .55);
}
.concept-mint .cm-sheet[hidden] { display: none; }
.concept-mint .cm-sheet__grabber {
  width: 44px; height: 5px; margin: 0 auto 10px;
  border-radius: 999px; background: var(--cm-grabber);
}
.concept-mint .cm-sheet__head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin: 0 0 6px;
}
.concept-mint .cm-sheet__head .cm-sheet__title { margin: 0; }
.concept-mint .cm-sheet__close { flex: none; }
.concept-mint .cm-sheet__title {
  margin: 0 0 8px; font-size: 17px; font-weight: 700; color: var(--cm-text);
}
.concept-mint .cm-sheet__scrim {
  position: fixed; inset: 0; z-index: 55; background: var(--cm-scrim);
  border: 0; padding: 0; cursor: pointer;
}
.concept-mint .cm-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-mint .cm-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-mint .cm-sheet .tabbar a {
  display: flex; align-items: center; gap: 10px;
  min-height: var(--cm-tap); padding: 0 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel-raised);
  color: var(--cm-text); font-size: 13px; font-weight: 600;
}
.concept-mint .cm-sheet .tabbar a[aria-current="page"] {
  border-color: var(--cm-accent); color: var(--cm-accent);
}
.concept-mint .cm-sheet .tabbar a img { width: 20px; height: 20px; }

/* ==========================================================================
   THE KIT — the primitives every mint screen is assembled from.
   Their DOM builders are ui/concept/mint/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-mint .cm-stack { display: grid; gap: 6px; }
.concept-mint .cm-section { display: grid; gap: 6px; margin: 0 0 10px; }
.concept-mint .cm-section__title {
  margin: 0; font-size: 16px; line-height: 1.25; font-weight: 750;
  letter-spacing: -.01em; color: var(--cm-text);
}
.concept-mint .cm-section__sub { margin: 0; font-size: 13px; line-height: 1.35; color: var(--cm-muted); }
.concept-mint .cm-muted { color: var(--cm-muted); }
.concept-mint .cm-num { font-variant-numeric: tabular-nums; }

/* ---------- 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-mint .cm-hero {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: var(--cm-radius);
  background: var(--cm-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-mint .cm-hero__img {
  display: block; width: 100%;
  height: clamp(92px, 13vh, 128px);
  object-fit: cover;
}
.concept-mint .cm-hero::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(0deg, var(--cm-bg) 2%, var(--cm-hero-fade) 42%, transparent 78%);
}
.concept-mint .cm-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-mint .cm-hero__head {
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.concept-mint .cm-hero__head .cm-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-mint .cm-hero__back,
.concept-mint .cm-hero__switch > * {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--cm-tap); height: var(--cm-tap);
  min-width: var(--cm-tap); min-height: var(--cm-tap);
  padding: 0;
  border: 0; border-radius: 999px;
  background: none;
  color: var(--cm-art-ink);
  text-decoration: none; cursor: pointer;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, .7));
}
.concept-mint .cm-hero__back { margin: 0 -4px 0 -10px; }
.concept-mint .cm-hero__switch > * { margin: 0 -10px 0 -4px; }
.concept-mint .cm-hero--plain .cm-hero__back,
.concept-mint .cm-hero--plain .cm-hero__switch > * {
  color: var(--cm-text); filter: none;
}
.concept-mint .cm-hero__back:hover,
.concept-mint .cm-hero__switch > :hover { color: var(--cm-accent); text-decoration: none; }
.concept-mint .cm-hero__back .cm-icon,
.concept-mint .cm-hero__switch .cm-icon { width: 26px; height: 26px; }
.concept-mint .cm-hero__switch { display: inline-flex; flex: none; }
/* 24px at 360px and 28 at 412, against the reference's 23.5. */
.concept-mint .cm-hero__title {
  margin: 0; font-size: clamp(19px, 5.6vw, 24px); line-height: 1.15;
  font-weight: 750; letter-spacing: -.02em; color: var(--cm-art-ink);
  overflow-wrap: anywhere;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .7);
}
.concept-mint .cm-hero__sub {
  margin: 2px 0 0; font-size: 14px; line-height: 1.3; color: var(--cm-art-ink-2);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .7);
}
.concept-mint .cm-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-mint .cm-hero--plain {
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 104px;
  border: 1px solid var(--cm-line);
  background:
    radial-gradient(120% 120% at 10% 0%, var(--cm-hero-glow), transparent 60%),
    linear-gradient(160deg, var(--cm-panel-raised), var(--cm-panel) 62%, var(--cm-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-mint .cm-hero--plain::after { background: none; }
.concept-mint .cm-hero--plain .cm-hero__body {
  position: static; left: auto; right: auto; bottom: auto; padding: 12px;
}
.concept-mint .cm-hero--plain .cm-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-mint .cm-hero:not(.cm-hero--plain) .cm-hero__crest { left: auto; right: 10px; }
.concept-mint .cm-hero:not(.cm-hero--plain) .cm-hero__crest ~ .cm-hero__body > .cm-hero__title,
.concept-mint .cm-hero:not(.cm-hero--plain) .cm-hero__crest ~ .cm-hero__body > .cm-hero__head {
  padding-right: 48px;
}
.concept-mint .cm-hero__crest {
  position: absolute; z-index: 1; top: 10px; left: 10px;
  width: 40px; height: 40px;
  padding: 4px;
  border: 1px solid var(--cm-hero-edge);
  border-radius: 10px;
  background: var(--cm-glass);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}
.concept-mint .cm-hero__crest img { width: 100%; height: 100%; object-fit: contain; }

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

.concept-mint .cm-card {
  padding: 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius);
  background: var(--cm-panel);
  min-width: 0;
}
.concept-mint .cm-card--raised { background: var(--cm-panel-raised); }
.concept-mint .cm-card--flush { padding: 6px 10px; }
.concept-mint .cm-card__title {
  margin: 0 0 6px; font-size: 15px; font-weight: 700; line-height: 1.25;
  color: var(--cm-text);
  display: flex; align-items: center; gap: 6px;
}
.concept-mint .cm-card__title .cm-icon { width: 20px; height: 20px; }
.concept-mint .cm-card__note {
  margin: 6px 0 0; font-size: 13px; line-height: 1.35; color: var(--cm-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 .cm-card at the same weight, so the padding reset below wins. */
.concept-mint .cm-fold { padding: 0; overflow: hidden; }
.concept-mint .cm-fold__summary {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--cm-tap); padding: 4px 12px;
  list-style: none; cursor: pointer;
  color: var(--cm-text); font-size: 15px; font-weight: 700; line-height: 1.25;
}
.concept-mint .cm-fold__summary::-webkit-details-marker { display: none; }
.concept-mint .cm-fold__summary::marker { content: ""; }
.concept-mint .cm-fold__title { min-width: 0; overflow-wrap: anywhere; }
.concept-mint .cm-fold__count {
  flex: none; font-size: 12px; font-weight: 600; color: var(--cm-muted);
  font-variant-numeric: tabular-nums;
}
.concept-mint .cm-fold__chevron {
  flex: none; margin-left: auto; color: var(--cm-muted);
  transition: transform .15s ease;
}
.concept-mint .cm-fold[open] .cm-fold__chevron { transform: rotate(180deg); }
.concept-mint .cm-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-mint .cm-tiles {
  display: grid; gap: 8px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.concept-mint .cm-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-mint .cm-tiles--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }

.concept-mint .cm-tile {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 64px; padding: 8px 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel-raised);
  color: var(--cm-text); text-decoration: none;
  min-width: 0;
}
.concept-mint a.cm-tile:hover { border-color: var(--cm-accent); text-decoration: none; }
/* A PRESSABLE TILE GOT NOTHING BACK. cmTile 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-mint button.cm-tile:hover { border-color: var(--cm-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-mint button.cm-tile:not(.cm-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-mint .cm-tile__more { flex: none; display: inline-flex; color: var(--cm-muted); }
.concept-mint .cm-tile__more .cm-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-mint .cm-tile__head {
  display: flex; align-items: center; gap: 6px;
  width: 100%; min-width: 0;
}
.concept-mint .cm-tile__head .cm-tile__label { flex: 1 1 auto; }
.concept-mint .cm-tile__icon { flex: none; display: inline-flex; color: var(--cm-link); }
.concept-mint .cm-tile__icon .cm-icon { width: 18px; height: 18px; }
.concept-mint .cm-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 .cm-tile and .cm-tile__value on purpose: same specificity, later wins. */
.concept-mint .cm-tile--compact { min-height: 56px; padding: 6px 10px; }
.concept-mint .cm-tile--compact .cm-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-mint .cm-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-mint .cm-tile__label {
  font-size: 13px; line-height: 1.2; color: var(--cm-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-mint .cm-tile__delta {
  font-size: 12px; font-weight: 650; line-height: 1.2; color: var(--cm-muted);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.concept-mint .cm-tile__delta--up   { color: var(--cm-success); }
.concept-mint .cm-tile__delta--down { color: var(--cm-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-mint .cm-tile--locked {
  background: var(--cm-panel);
  border-style: dashed;
  color: var(--cm-muted);
  cursor: default;
}
.concept-mint .cm-tile--locked .cm-tile__icon,
.concept-mint .cm-tile--locked .cm-tile__value { color: var(--cm-muted); }
.concept-mint .cm-tile__lock {
  position: absolute; top: 6px; right: 6px;
  color: var(--cm-muted);
}
.concept-mint .cm-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-mint .cm-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-mint .cm-tile--stacked .cm-tile__icon .cm-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-mint .cm-tile--stacked .cm-tile__label {
  font-size: 11px; line-height: 1.2; letter-spacing: -.01em; color: var(--cm-text);
  white-space: normal; overflow: visible; overflow-wrap: normal; text-align: center;
}
.concept-mint .cm-tile--stacked .cm-tile__value { font-size: 17px; color: var(--cm-muted); font-weight: 650; }

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

.concept-mint .cm-meter { display: flex; align-items: center; gap: 8px; min-width: 0; }
.concept-mint .cm-meter__track {
  flex: 1 1 auto; height: 6px; min-width: 0;
  border-radius: 999px; background: var(--cm-track); overflow: hidden;
}
.concept-mint .cm-meter__fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--cm-accent);
}
.concept-mint .cm-meter--warn .cm-meter__fill   { background: var(--cm-warning); }
.concept-mint .cm-meter--danger .cm-meter__fill { background: var(--cm-danger); }
.concept-mint .cm-meter--good .cm-meter__fill   { background: var(--cm-success); }
.concept-mint .cm-meter__pct {
  flex: none; font-size: 12px; color: var(--cm-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-mint .cm-segment {
  position: relative;
  display: flex; gap: 3px; padding: 3px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel);
  overflow-x: auto; scrollbar-width: none;
}
.concept-mint .cm-segment::-webkit-scrollbar { display: none; }
/* The edge fade, on the strips that have more items than a phone shows at once
   (ui/concept/mint/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-mint .cm-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-mint .cm-segment--wrap {
  flex-wrap: wrap; overflow-x: visible;
  -webkit-mask-image: none; mask-image: none;
}
.concept-mint .cm-segment--wrap .cm-segment__item { flex: 0 0 auto; min-width: 48px; }
.concept-mint .cm-segment__item {
  flex: 1 1 0; min-width: max-content;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; 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(--cm-panel);
  color: var(--cm-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-mint .cm-segment__label {
  display: inline-block; min-width: 20px; text-align: center;
}
/* 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-mint .cm-segment--compact .cm-segment__item {
  padding: 0 6px;
  font-size: 12px;
  letter-spacing: 0;
}
.concept-mint .cm-segment--compact .cm-segment__label { min-width: 0; }

.concept-mint .cm-segment__item:hover { color: var(--cm-text); text-decoration: none; }
.concept-mint .cm-segment__item[aria-selected="true"],
.concept-mint .cm-segment__item[aria-current="page"] {
  background: var(--cm-accent); color: var(--cm-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-mint .cm-rows {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 6px;
}
.concept-mint .cm-row {
  display: flex; align-items: center; gap: 10px;
  min-height: var(--cm-tap); padding: 4px 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel);
  color: var(--cm-text); text-decoration: none;
  min-width: 0;
}
.concept-mint a.cm-row:hover,
.concept-mint button.cm-row:hover { border-color: var(--cm-accent); text-decoration: none; }
.concept-mint button.cm-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. cmRow
   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 --cm-tap floor above. */
.concept-mint div.cm-row { min-height: 40px; }
.concept-mint .cm-row--plain { border: 0; background: none; padding-left: 0; padding-right: 0; }
.concept-mint .cm-row__lead {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 8px; overflow: hidden;
  background: var(--cm-panel-raised);
  color: var(--cm-link);
}
.concept-mint .cm-row__lead img { width: 100%; height: 100%; object-fit: cover; }
/* 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-mint .cm-row__lead .cm-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-mint .cm-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-mint .cm-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-mint .cm-row__sub {
  display: block; flex: 0 1 auto; min-width: 0;
  font-size: 13px; line-height: 1.3; color: var(--cm-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-mint .cm-row__sub .cm-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-mint .cm-row__pills {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px;
  flex: 1 0 100%;
}
.concept-mint .cm-row__meter { display: block; margin-top: 4px; flex: 1 0 100%; }
/* The same, for the two screens that drop a bare cmMeter 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-mint .cm-row__body > .cm-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-mint .cm-row__title:has(.cm-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-mint .cm-row__value {
  flex: none; margin-left: auto; text-align: right;
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.concept-mint .cm-row__chevron { flex: none; color: var(--cm-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-mint .cm-rowset { display: flex; align-items: center; gap: 6px; min-width: 0; }
.concept-mint .cm-rowset > :first-child { flex: 1 1 auto; min-width: 0; }
.concept-mint .cm-icon-btn {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--cm-tap); height: var(--cm-tap);
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel);
  color: var(--cm-muted);
  cursor: pointer;
}
.concept-mint .cm-icon-btn:hover { color: var(--cm-text); }

/* The one very large number on a screen — the reference's "4 orders queued".
   A class rather than an inline style, so the size is decided in the same file
   as every other size. */
.concept-mint .cm-bignum {
  flex: none;
  font-size: 32px; line-height: 1; font-weight: 800;
  color: var(--cm-accent); font-variant-numeric: tabular-nums;
}

/* ---------- 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-mint .cm-alert { border-width: 1px; }
/* A SOLID TINT, not a gradient of one opaque colour laid over the panel twice.
   The two paint identically — --cm-*-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-mint .cm-alert--warn {
  border-color: var(--cm-warning);
  background: var(--cm-warning-bg);
}
.concept-mint .cm-alert--warn .cm-row__lead  { color: var(--cm-warning); background: var(--cm-warning-dim); }
.concept-mint .cm-alert--danger {
  border-color: var(--cm-danger);
  background: var(--cm-danger-bg);
}
.concept-mint .cm-alert--danger .cm-row__lead { color: var(--cm-danger); background: var(--cm-danger-dim); }
.concept-mint .cm-alert--info .cm-row__lead   { color: var(--cm-link); }

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

.concept-mint .cm-cta {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: var(--cm-tap); padding: 8px 14px;
  border: 1px solid var(--cm-accent); border-radius: var(--cm-radius-sm);
  background: var(--cm-accent);
  color: var(--cm-accent-ink);
  font-family: inherit; font-size: 14px; font-weight: 750;
  text-decoration: none; cursor: pointer;
  touch-action: manipulation;
}
.concept-mint .cm-cta:hover { color: var(--cm-accent-ink); text-decoration: none; filter: brightness(1.06); }
.concept-mint .cm-cta--quiet {
  background: var(--cm-panel-raised); color: var(--cm-text); border-color: var(--cm-line);
}
/* A DISABLED CTA IS THE QUIET SHAPE, not the accent one faded out. The old
   rule dimmed --cm-accent-ink on --cm-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-mint .cm-cta[aria-disabled="true"] {
  opacity: 1;
  background: var(--cm-panel-raised);
  border-color: var(--cm-line);
  color: var(--cm-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-mint .cm-cta--advised[aria-disabled="true"] {
  pointer-events: auto;
  cursor: pointer;
  border-color: var(--cm-warning);
  color: var(--cm-text);
}
.concept-mint .cm-cta-caption {
  margin: 4px 0 0; font-size: 13px; line-height: 1.35; color: var(--cm-muted); text-align: center;
}
.concept-mint .cm-cta-caption--warn { color: var(--cm-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: --cm-tap, the same
   floor a row and a call-to-action sit on. */

.concept-mint .cm-field { display: grid; gap: 4px; }
.concept-mint .cm-field__label {
  font-size: 13px; font-weight: 650; color: var(--cm-muted);
}
.concept-mint .cm-field__hint {
  margin: 0; font-size: 12px; line-height: 1.35; color: var(--cm-muted); overflow-wrap: anywhere;
}
/* The error REPLACES the hint rather than stacking under it. */
.concept-mint .cm-field__error {
  margin: 0; font-size: 12px; line-height: 1.35; color: var(--cm-danger); overflow-wrap: anywhere;
}
.concept-mint .cm-input {
  width: 100%; min-height: var(--cm-tap); padding: 8px 10px;
  border: 1px solid var(--cm-edge-ui); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel-raised);
  color: var(--cm-text);
  font-family: inherit; font-size: 15px; line-height: 1.3;
  font-variant-numeric: tabular-nums;
}
.concept-mint .cm-input::placeholder { color: var(--cm-muted); opacity: 1; }
.concept-mint .cm-input:disabled { color: var(--cm-muted); background: var(--cm-panel); }
.concept-mint .cm-input:focus-visible { border-color: var(--cm-accent); outline: none; }
.concept-mint .cm-input[aria-invalid="true"] { border-color: var(--cm-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-mint .cm-input--range {
  padding: 0; border: 0; background: none;
  accent-color: var(--cm-accent);
}

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

.concept-mint .cm-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(--cm-muted);
  font-variant-numeric: tabular-nums;
  background: var(--cm-glass-soft);
}
.concept-mint .cm-pill--accent  { color: var(--cm-accent);  background: var(--cm-accent-bg); }
.concept-mint .cm-pill--good    { color: var(--cm-success); background: var(--cm-success-bg); }
.concept-mint .cm-pill--warn    { color: var(--cm-warning); background: var(--cm-warning-bg); }
.concept-mint .cm-pill--danger  { color: var(--cm-danger);  background: var(--cm-danger-bg); }

/* A row of pills OUTSIDE a hero. cmHero 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-mint .cm-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-mint .cm-back {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--cm-tap); min-width: var(--cm-tap);
  margin: 0 0 6px -8px; padding: 0 10px 0 8px;
  border: 0; border-radius: var(--cm-radius-sm);
  background: none;
  color: var(--cm-muted);
  font-family: inherit; font-size: 14px; font-weight: 650;
  text-decoration: none; cursor: pointer;
}
.concept-mint .cm-back:hover { color: var(--cm-text); text-decoration: none; }
.concept-mint .cm-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-mint .cm-timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.concept-mint .cm-timeline__step {
  position: relative;
  display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px;
  padding: 0 0 10px;
}
.concept-mint .cm-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-mint .cm-timeline__step:not(:last-child) .cm-timeline__rail::after {
  content: ""; position: absolute; top: 18px; bottom: -10px; width: 2px;
  background: var(--cm-line);
}
.concept-mint .cm-timeline__node {
  position: relative; z-index: 1;
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--cm-line); background: var(--cm-bg);
}
.concept-mint .cm-timeline__step--done .cm-timeline__node    { border-color: var(--cm-success); background: var(--cm-success); }
.concept-mint .cm-timeline__step--active .cm-timeline__node  { border-color: var(--cm-accent);  background: var(--cm-accent); }
.concept-mint .cm-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 cm-row and was simply missing from this one. */
.concept-mint .cm-timeline__title {
  display: block;
  font-size: 15px; font-weight: 650; line-height: 1.3; overflow-wrap: anywhere;
}
.concept-mint .cm-timeline__sub {
  display: block;
  font-size: 13px; line-height: 1.3; color: var(--cm-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-mint .cm-timeline__glyph { margin-right: 6px; color: var(--cm-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-mint .cm-timeline__body--link {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px;
  color: var(--cm-text); text-decoration: none;
}
.concept-mint .cm-timeline__body--link:hover { color: var(--cm-accent); text-decoration: none; }
.concept-mint .cm-timeline__text { flex: 1 1 auto; min-width: 0; }
.concept-mint .cm-timeline__chevron { flex: none; color: var(--cm-muted); }

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

.concept-mint .cm-icon {
  width: 24px; height: 24px; flex: none;
  display: inline-block; vertical-align: middle;
  color: inherit;
}
.concept-mint .cm-icon--lg { width: 28px; height: 28px; }
.concept-mint .cm-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-mint .cm-art {
  display: block; width: 100%; border-radius: var(--cm-radius-sm);
  background: var(--cm-panel);
}
.concept-mint .cm-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-mint .cm-hero__img.cm-art--banner { height: clamp(92px, 13vh, 128px); }
.concept-mint .cm-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-mint .cm-select,
.concept-mint .cm-colour,
.concept-mint .cm-input { color-scheme: dark; }
.concept-mint .cm-select { cursor: pointer; }
.concept-mint .cm-textarea { min-height: 88px; resize: vertical; line-height: 1.4; }

.concept-mint .cm-colour {
  flex: none; width: var(--cm-tap); height: var(--cm-tap); padding: 3px;
  border: 1px solid var(--cm-edge-ui); border-radius: var(--cm-radius-sm);
  background: var(--cm-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-mint .cm-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: var(--cm-tap); padding: 6px 12px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel-raised); color: var(--cm-text);
  font-family: inherit; font-size: 14px; font-weight: 650; line-height: 1.2;
  text-decoration: none; cursor: pointer; touch-action: manipulation;
}
.concept-mint .cm-btn:hover { border-color: var(--cm-accent); text-decoration: none; color: var(--cm-text); }
.concept-mint .cm-btn--primary {
  background: var(--cm-accent); border-color: var(--cm-accent); color: var(--cm-accent-ink);
}
.concept-mint .cm-btn--danger { color: var(--cm-danger); border-color: var(--cm-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-mint .cm-btn[aria-disabled="true"],
.concept-mint .cm-btn:disabled {
  opacity: 1; background: var(--cm-panel); border-color: var(--cm-line);
  color: var(--cm-muted); pointer-events: none; cursor: default;
}
.concept-mint .cm-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-mint .cm-marks {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; margin-top: 6px;
}
.concept-mint .cm-mark {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--cm-tap); min-width: 0; padding: 4px 2px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel-raised); color: var(--cm-text);
  font-family: inherit; font-size: 11px; font-weight: 650; line-height: 1.1;
  cursor: pointer; touch-action: manipulation;
}
.concept-mint .cm-mark:hover { border-color: var(--cm-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-mint .cm-mark[aria-pressed="true"] { background: var(--cm-panel-3); }
.concept-mint .cm-mark__dot {
  display: block; width: 16px; height: 16px; flex: none;
  border: 2.5px solid var(--cm-line); border-radius: 50%;
}
.concept-mint .cm-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-mint .cm-mark-row {
  display: flex; align-items: center; gap: 8px; margin-top: 6px; min-width: 0;
}
.concept-mint .cm-mark-row .cm-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-mint .cm-disclosure {
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel); overflow: hidden;
}
.concept-mint .cm-disclosure__summary {
  display: flex; align-items: center; gap: 8px;
  min-height: var(--cm-tap); padding: 4px 10px;
  list-style: none; cursor: pointer; color: var(--cm-text);
}
.concept-mint .cm-disclosure__summary::-webkit-details-marker { display: none; }
.concept-mint .cm-disclosure__summary::marker { content: ""; }
.concept-mint .cm-disclosure__lead {
  flex: none; width: 24px; height: 24px; display: grid; place-items: center;
  border-radius: 6px; background: var(--cm-panel-raised); color: var(--cm-link);
}
.concept-mint .cm-disclosure__text { flex: 1 1 auto; min-width: 0; display: block; }
.concept-mint .cm-disclosure__title {
  display: block; font-size: 13px; line-height: 1.3; overflow-wrap: anywhere;
}
.concept-mint .cm-disclosure__sub {
  display: block; font-size: 12px; line-height: 1.3; color: var(--cm-muted); overflow-wrap: anywhere;
}
.concept-mint .cm-disclosure__chevron {
  flex: none; margin-left: auto; color: var(--cm-muted); transition: transform .15s ease;
}
.concept-mint .cm-disclosure[open] .cm-disclosure__chevron { transform: rotate(180deg); }
.concept-mint .cm-disclosure__body { padding: 0 10px 8px 42px; }
.concept-mint .cm-disclosure__body p { margin: 0 0 4px; font-size: 12px; line-height: 1.4; color: var(--cm-muted); }
.concept-mint .cm-disclosure--warn { border-color: var(--cm-warning); }
.concept-mint .cm-disclosure--danger { border-color: var(--cm-danger); }
.concept-mint .cm-disclosure--danger .cm-disclosure__lead { color: var(--cm-danger); background: var(--cm-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-mint .cm-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px; letter-spacing: .08em; color: var(--cm-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-mint .cm-scroller {
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

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

.concept-mint :focus-visible { outline: 3px solid var(--cm-accent); outline-offset: 3px; }
.concept-mint a { color: var(--cm-link); text-underline-offset: 3px; }
.concept-mint .cm-empty {
  padding: 12px 12px; text-align: center;
  border: 1px dashed var(--cm-line); border-radius: var(--cm-radius-sm);
  color: var(--cm-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-mint .cm-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(--cm-text);
  background: var(--cm-bg-1);
  border: 1px solid var(--cm-line-mid);
  border-radius: var(--cm-radius-sm);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.concept-mint textarea.cm-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. */
}

/* ---------- 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-mint > main.game-main.wide { display: flex; flex-direction: column; padding: 0; }
.concept-mint .map-shell { flex: 1 1 auto; height: auto; min-height: 0; }

/* 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
   --cm-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/mint/map.js). Measured with them left out, <main> could scroll
   13px — enough to slide the header row up out of the frame. */
.concept-mint .map-list-screen--bodies {
  height: calc(100dvh - var(--chrome-measured) - var(--subtab-measured, 0px) - var(--cm-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-mint main.game-main .btn {
  background-image: none;
  background-color: var(--cm-panel-raised);
  border-color: var(--cm-line);
  color: var(--cm-text);
}
.concept-mint main.game-main .btn:hover {
  background-image: none;
  background-color: var(--cm-panel-3);
  border-color: var(--cm-edge-ui);
}
.concept-mint main.game-main .btn--primary {
  background-image: none;
  background-color: var(--cm-accent);
  border-color: var(--cm-accent);
  color: var(--cm-accent-ink);
  box-shadow: none;
}
.concept-mint main.game-main .btn--ghost,
.concept-mint 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-mint .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-mint .card { padding: .7rem; margin-bottom: .7rem; }
.concept-mint details.card--fold > summary { padding: .7rem; margin: -.7rem; }
.concept-mint details.card--fold[open] > summary { margin: -.7rem -.7rem .45rem; }
.concept-mint .card > h2,
.concept-mint details.card--fold > summary h2 { font-size: 15px; line-height: 1.3; }
.concept-mint .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-mint .card {
  border-radius: var(--cm-radius);
  background: var(--cm-panel);
  border-color: var(--cm-line);
  border-left-color: var(--cm-line);
}
.concept-mint .card--sub { background: var(--cm-panel-raised); }
.concept-mint .btn--primary {
  background: var(--cm-accent);
  border-color: var(--cm-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(--cm-accent-ink);
  box-shadow: none;
}
.concept-mint .btn--primary:hover {
  background: var(--cm-accent);
  border-color: var(--cm-accent);
  filter: brightness(1.06);
}
.concept-mint ~ dialog.modal {
  background: var(--cm-panel);
  border-color: var(--cm-line);
  border-radius: var(--cm-radius);
  box-shadow: none;
}
.concept-mint ~ dialog.modal .modal-head { background: none; border-bottom-color: var(--cm-line); }
/* Modals are appended to <body>, a SIBLING of #app, so nothing written as a
   descendant of .concept-mint reaches an order form. The token blocks above
   are scoped to the sibling too; these are the literal Command surfaces. */
.concept-mint ~ dialog.modal .btn--primary {
  background: var(--cm-accent);
  border-color: var(--cm-accent);
  color: var(--cm-accent-ink);
  box-shadow: none;
}
.concept-mint ~ dialog.modal .btn { border-radius: var(--cm-radius-sm); min-height: var(--cm-tap); }
.concept-mint ~ dialog.modal .card { border-radius: var(--cm-radius); background: var(--cm-panel); border-color: var(--cm-line); }
.concept-mint .banner { background: var(--cm-panel); border-radius: var(--cm-radius-sm); }
.concept-mint ~ #toasts .toast {
  background: var(--cm-panel-raised);
  border-radius: var(--cm-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-mint .btn { border-radius: var(--cm-radius-sm); }
.concept-mint .btn--primary { color: var(--cm-accent-ink); }
.concept-mint .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-mint .btn--sm { min-height: var(--cm-tap); min-width: var(--cm-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-mint .btn[disabled], .concept-mint .btn:disabled {
  opacity: 1; color: var(--text-3); background: var(--panel-3); border-color: var(--line);
}
.concept-mint select,
.concept-mint input:not([type="checkbox"]):not([type="radio"]):not([type="range"]) { min-height: var(--cm-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-mint ~ #toasts { bottom: calc(var(--cm-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 cm-tiles is a
   whole screen at 360px, which is why this is not a tile. */

.concept-mint .cm-gauges {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px;
}
.concept-mint .cm-gauges--1 { grid-template-columns: minmax(0, 1fr); }
.concept-mint .cm-gauges--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.concept-mint .cm-gauge {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-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-mint .cm-gauge__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  min-width: 0;
}
.concept-mint .cm-gauge__label {
  flex: 0 1 auto; min-width: 0;
  font-size: 12px; line-height: 1.3; color: var(--cm-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-mint .cm-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(--cm-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-mint .cm-gauge__note {
  font-size: 12px; line-height: 1.35; color: var(--cm-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-mint .cm-toggle {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: var(--cm-tap); padding: 6px 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel); color: var(--cm-text);
  font: inherit; text-align: left; cursor: pointer;
}
.concept-mint .cm-toggle__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.concept-mint .cm-toggle__label { font-size: 15px; font-weight: 650; line-height: 1.3; }
.concept-mint .cm-toggle__hint { font-size: 13px; line-height: 1.3; color: var(--cm-muted); overflow-wrap: anywhere; }
.concept-mint .cm-toggle__track {
  flex: none; position: relative;
  width: 42px; height: 24px; border-radius: 999px;
  background: var(--cm-track); border: 1px solid var(--cm-line);
}
.concept-mint .cm-toggle__knob {
  position: absolute; top: 2px; left: 2px;
  width: 18px; height: 18px; border-radius: 999px;
  background: var(--cm-grabber);
  transition: left .12s ease, background .12s ease;
}
.concept-mint .cm-toggle--on .cm-toggle__track { background: var(--cm-accent-bg); border-color: var(--cm-accent); }
.concept-mint .cm-toggle--on .cm-toggle__knob { left: 20px; background: var(--cm-accent); }
.concept-mint .cm-toggle[aria-disabled="true"] { color: var(--cm-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-mint .cm-stepper { flex: none; display: inline-flex; align-items: center; gap: 2px; }
.concept-mint .cm-stepper__btn {
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--cm-tap); height: var(--cm-tap);
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-panel); color: var(--cm-text);
  font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.concept-mint .cm-stepper__btn--add { border-color: var(--cm-edge-ui); color: var(--cm-accent); }
.concept-mint .cm-stepper__btn[disabled] {
  color: var(--cm-text-4); background: var(--cm-panel-3); border-color: var(--cm-line-mid); cursor: default;
}
.concept-mint .cm-stepper__count {
  flex: none; min-width: 22px; text-align: center;
  font-size: 13px; font-weight: 700; color: var(--cm-muted); font-variant-numeric: tabular-nums;
}
.concept-mint .cm-stepper__count--on { color: var(--cm-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-mint .cm-axis {
  display: grid; gap: 4px;
  padding: 6px 10px;
  border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
  background: var(--cm-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-mint .cm-axis__status {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
}
.concept-mint .cm-axis__severity {
  font-size: 11px; font-weight: 600; line-height: 1.2;
  color: var(--cm-muted); font-variant-numeric: tabular-nums;
}
/* How much of a hostile axis is actually covered, and what to build. */
.concept-mint .cm-axis__cover { display: grid; gap: 3px; }
.concept-mint .cm-axis__cover .cm-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-mint .cm-comfort {
  display: block; position: relative; height: 10px; margin: 1px 2px 2px;
}
.concept-mint .cm-comfort__track {
  position: absolute; inset: 0;
  border-radius: 999px; overflow: hidden;
  background: var(--cm-track);
}
.concept-mint .cm-comfort__band,
.concept-mint .cm-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-mint .cm-comfort__band { background: var(--cm-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-mint .cm-comfort__zone {
  background: var(--cm-success); border-radius: 2px;
  box-shadow: 0 0 0 2px var(--cm-track);
}
.concept-mint .cm-comfort__ideal {
  position: absolute; top: 1px; bottom: 1px; width: 2px; border-radius: 1px;
  transform: translateX(-50%);
  background: var(--cm-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-mint .cm-comfort__marker {
  position: absolute; top: -2px; bottom: -2px; width: 8px;
  border-radius: 4px; transform: translateX(-50%); z-index: 1;
  background: var(--cm-muted);
  box-shadow: 0 0 0 2px var(--cm-panel);
}
.concept-mint .cm-comfort__marker--good   { background: var(--cm-success); }
.concept-mint .cm-comfort__marker--warn   { background: var(--cm-warning); }
.concept-mint .cm-comfort__marker--danger { background: var(--cm-danger); }

/* ---------- 23. Small and large screens ------------------------------------ */

@media (max-width: 339px) {
  .concept-mint .cm-tiles { grid-template-columns: 1fr; }
  .concept-mint .cm-tiles--3,
  .concept-mint .cm-tiles--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .concept-mint .cm-gauges,
  .concept-mint .cm-gauges--3 { grid-template-columns: 1fr; }
}

/* On a computer the frame stays a phone frame — that is what the concept is —
   but the screen itself is centred instead of stretched to 1280px of card. */
@media (min-width: 900px) {
  .concept-mint > main.game-main > * { max-width: 760px; margin-inline: auto; }
  .concept-mint > .cm-nav { padding-inline: 20%; }
}
