/* ==========================================================================
   Astral Sovereignty — the "Mint" layout on a DESKTOP

   The phone frame is a header, a screen and a bottom bar. This file is what
   that same frame does when it is given 1024px or more: a left sidebar, a
   centred content column, and a rail on the right for the row you opened.

   NOTHING NEW IS DRAWN HERE. Every element this file styles is a node app.js
   or ui/concept/mint/shell.js already built for the phone — the same header,
   the same five destinations, the same sub-tab strip, the same <main>.
   The shell moves three of them into a sidebar box and this file lays them out;
   see the diagram at the top of ui/concept/mint/shell.js.

   SCOPE, and it is doubled on purpose. Every rule is scoped under
   `.concept-mint` (the class the mint shell puts on #app) AND lives inside
   `@media (min-width: 1024px)`, and the shell only adds `.concept-mint--desk`
   when that media query actually matches. So this file is inert for a classic
   player, inert for a mint player on a phone, and inert for a mint player on a
   narrow window — three independent reasons, any one of which is enough.
   tests/concept_mint_desktop.test.js pins the scoping and the breakpoint
   against ui/concept/mint/shell.js's own MINT_DESKTOP_AT.

   Discipline, the same four concept-mint.css carries:
   - concept-mint.css is NOT edited. Everything below is an override in a later
     file, inside a scope that file's rules cannot reach.
   - No colour of its own: every value is one of concept-mint.css's --cm-*
     tokens, so both themes paint this arrangement for free.
   - Every tap target is at least --cm-tap.
   - No braces inside comments: the tests parse this file by counting them.
   ========================================================================== */

@media (min-width: 1024px) {

  /* ---------- 1. The three regions ----------------------------------------
     #app is already a flex column one viewport tall. It becomes a flex ROW,
     and the three regions are its three children:

       .cm-side   240px  the sidebar the shell put the header and the bar in
       .cm-desk   1fr    the alert strips, then <main> and the rail beneath
       .cm-rail   360+   the detail of the row you opened, inside .cm-desk

     <main> stays the only thing that scrolls IN THE CONTENT COLUMN, and the
     rail and the sidebar scroll on their own — three independent scrollers,
     which is the whole point of a split view. The page itself still never
     moves, so the strips are still permanently on screen. */

  /* #app is in the selector, and it has to be: game.css declares the column
     direction on `#app` itself, and an id out-ranks any number of classes.
     concept-mint.css needs no such thing because nothing it sets on the frame
     is a property that rule already claims. */
  #app.concept-mint.concept-mint--desk {
    --cm-side-w: 240px;
    --cm-col-w: 880px;
    --cm-rail-w: clamp(360px, 30vw, 460px);
    flex-direction: row;
    align-items: stretch;
  }

  /* ---------- 2. The sidebar ----------------------------------------------
     A four-column grid, and every item in it is placed EXPLICITLY by line
     rather than flowed. That is not fussiness: two of the header's children
     are conditional — "Exit demo" exists only in the demo and the mailbox only
     outside it — and with auto-placement their absence would slide everything
     after them into a different cell. Placed by line, a missing item leaves a
     gap and moves nothing.

       row 1   the wordmark
       row 2   your crest, name and rank
       row 3   the tick and lock pill
       row 4   the destinations, and the current one's sections under it
               (1fr, so it takes the slack and pins the tools to the floor)
       row 5   orders · mailbox · refresh · menu, four across
       row 6   Exit demo, in the demo only

     THE HEADER IS `display: contents`, which is the same move section 3 of
     concept-mint.css makes with `order` and for the same reason: its children
     have to lay out beside the nav, and re-creating them in a box of our own
     would throw away every id, handler and aria-label app.js gave them. */

  .concept-mint--desk .cm-side {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-rows: auto auto auto minmax(0, 1fr) auto;
    gap: 8px 6px;
    flex: 0 0 var(--cm-side-w);
    width: var(--cm-side-w);
    min-height: 0;
    padding: calc(12px + var(--cm-safe-top)) 12px calc(12px + var(--cm-safe-bottom));
    background: var(--cm-bg-1);
    border-right: 1px solid var(--cm-line);
  }

  .concept-mint--desk .cm-side > .shell-header--game { display: contents; }

  .concept-mint--desk .cm-side > .shell-header--game > .brand {
    grid-area: 1 / 1 / 2 / -1;
    display: flex; align-items: center; gap: 8px;
    min-width: 0;
    color: var(--cm-text); font-size: 16px; font-weight: 700;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .brand b {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .brand span { color: var(--cm-text); }
  .concept-mint--desk .cm-side > .shell-header--game > .brand img { width: 24px; height: 24px; }

  /* THE ONE THING THE PHONE FRAME HIDES AND THIS ONE SHOWS. concept-mint.css
     section 3 hides the identity block because a 53px row cannot carry it; a
     240px column can, and who you are playing as belongs at the top of it. The
     node, its id and its click handler are app.js's, untouched — this only
     stops hiding it, because the rule that hid it was scoped to a header that
     is a direct child of #app and this one is not. */
  .concept-mint--desk .cm-side > .shell-header--game > .empire-id {
    grid-area: 2 / 1 / 3 / -1;
    display: flex; align-items: center; gap: 8px;
    width: 100%; min-width: 0; min-height: var(--cm-tap);
    padding: 4px 8px;
    border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
    background: var(--cm-panel);
    color: var(--cm-text); text-align: left;
    cursor: pointer;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .empire-id:hover {
    border-color: var(--cm-edge-ui);
  }

  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip {
    grid-area: 3 / 1 / 4 / -1;
    display: flex; align-items: center; justify-content: center;
    min-height: 34px; padding: 0 10px;
    border: 1px solid var(--cm-line); border-radius: 999px;
    background: var(--cm-panel);
    color: var(--cm-muted); font-size: 13px; font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip .dot { display: none; }
  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip--ok { color: var(--cm-success); border-color: var(--cm-success); }
  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip--warn { color: var(--cm-warning); border-color: var(--cm-warning); }
  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip--bad { color: var(--cm-danger); border-color: var(--cm-danger); }
  .concept-mint--desk .cm-side > .shell-header--game > .tick-chip--info { color: var(--cm-link); border-color: var(--cm-link); }

  /* app.js's row break has no row to break here, and an unplaced grid item
     would be auto-flowed into a cell something else is already in. */
  .concept-mint--desk .cm-side > .shell-header--game > .header-break { display: none; }
  /* The flexible gap that pushes the tools to the bottom of a PHONE header.
     Here the 1fr nav row does that job, and a stray grid item would not. */
  .concept-mint--desk .cm-side > .shell-header--game > .spacer { display: none; }

  /* The tools, four across the floor of the sidebar. */
  .concept-mint--desk .cm-side > .shell-header--game > .cm-orders-badge { grid-area: 5 / 1 / 6 / 2; }
  .concept-mint--desk .cm-side > .shell-header--game > .mail-btn { grid-area: 5 / 2 / 6 / 3; }
  .concept-mint--desk .cm-side > .shell-header--game > .icon-btn:not(.menu-btn):not(.mail-btn) {
    grid-area: 5 / 3 / 6 / 4;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .menu-btn { grid-area: 5 / 4 / 6 / -1; }

  .concept-mint--desk .cm-side > .shell-header--game > .icon-btn,
  .concept-mint--desk .cm-side > .shell-header--game > .cm-orders-badge {
    display: flex; align-items: center; justify-content: center;
    width: auto; min-width: 0;
    height: var(--cm-tap); min-height: var(--cm-tap);
    padding: 0;
    border: 1px solid var(--cm-line); border-radius: var(--cm-radius-sm);
    background: var(--cm-panel);
    color: var(--cm-muted);
    position: relative;
  }
  .concept-mint--desk .cm-side > .shell-header--game > .icon-btn:hover,
  .concept-mint--desk .cm-side > .shell-header--game > .cm-orders-badge:hover {
    color: var(--cm-text); border-color: var(--cm-edge-ui);
  }

  /* Exit demo keeps its words at this width — there is a whole row for them. */
  .concept-mint--desk .cm-side > .shell-header--game > .btn {
    grid-area: 6 / 1 / 7 / -1;
    display: flex; align-items: center; justify-content: center; gap: 6px;
    width: 100%; min-height: var(--cm-tap);
  }
  .concept-mint--desk .cm-side > .shell-header--game > .cm-exit .cm-exit__label { display: inline; }

  /* ---------- 3. The destinations, vertically ------------------------------
     The same nodes the bottom bar is built from — core/nav.js's own labels and
     hrefs — laid out as a list instead of a strip. Every group has an item of
     its own here, because a 240px column has the room a thumb-width bar does
     not, so nothing is folded behind More at this size. */

  .concept-mint--desk .cm-side > .cm-nav.cm-nav--side {
    grid-area: 4 / 1 / 5 / -1;
    display: flex; flex-direction: column; align-items: stretch;
    gap: 2px;
    min-height: 0;
    padding: 0;
    background: none;
    border: 0;
    overflow-y: auto;
    overscroll-behavior-y: contain;
    /* Both scrollers in this column are drawn as one control. On the window
       where they are both scrolling they sit side by side, and the platform
       default beside the nest's 8px bar reads as two unrelated widgets — it is
       also the brightest thing in the sidebar, which a navigation rail's
       scrollbar has no business being. */
    scrollbar-width: thin;
    scrollbar-color: var(--cm-edge-ui) transparent;
  }
  .concept-mint--desk .cm-side > .cm-nav--side::-webkit-scrollbar { width: 8px; }
  .concept-mint--desk .cm-side > .cm-nav--side::-webkit-scrollbar-track { background: transparent; }
  .concept-mint--desk .cm-side > .cm-nav--side::-webkit-scrollbar-thumb {
    background: var(--cm-edge-ui); border-radius: 999px;
  }

  /* WHO ABSORBS A WINDOW TOO SHORT TO HOLD ALL OF THIS, in order. It is a
     cascade of exactly two steps and both of them say so out loud:

       1. THE NEST gives first (section 4). It is the secondary tier, it has a
          floor of three rows, and it scrolls with a fade.
       2. THIS COLUMN gives last, and only once the nest is at its floor and
          there is still not enough room for the destinations beside it. Same
          fade, same measurement. There are five of them since 2026-09-10 — one
          --cm-tap row cheaper than the arithmetic this cascade was measured
          against, so the column gives later than it used to, never sooner.

     THE DESTINATIONS THEMSELVES NEVER GIVE. They are the spine of the
     navigation — a player who has to scroll a sidebar to find Fleets is worse
     off than one who has to scroll to find Contacts — so `.cm-nav__item` below
     carries `flex: none` and cannot be squeezed at any height.

     This is the second correction of the same rule. Until 2026-09-10 the nest
     had no floor at all, and because every destination beside it already
     carried a min-height it was the ONLY child of this column that could
     shrink: the flex algorithm handed it the whole deficit and it collapsed
     silently, to 76px on a 650px window and to nothing at all on a 520px one.
     The first fix stopped it shrinking outright, which moved the damage rather
     than removing it — the nest then pushed the destinations off the bottom.
     A floor is what the rule actually wanted.

     THE FADE IS MEASURED IN JS, and it has to be. CSS cannot ask a box whether
     it overflows; ui/concept/mint/kit.js answers that for .cm-segment with a
     conservative item COUNT, and no count can answer it here — whether either
     of these boxes overflows depends on the WINDOW HEIGHT, which no selector
     can see. So ui/concept/mint/shell.js measures scrollHeight against
     clientHeight on assembly, on scroll and on resize, and writes
     `data-cm-fade` on whichever box is scrolling; these rules and the three
     beside the nest are the whole of what the stylesheet knows about it.

     A MASK AND NOT A GRADIENT BACKGROUND, for the reason section 5 of
     concept-mint.css gives: 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. The scrollbar is deliberately left visible on both — these
     are not the skin's hidden-scrollbar strips, and the fade is the second
     signal rather than the only one. */
  .concept-mint--desk .cm-side > .cm-nav--side[data-cm-fade="down"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
  }
  .concept-mint--desk .cm-side > .cm-nav--side[data-cm-fade="up"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px);
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px);
  }
  .concept-mint--desk .cm-side > .cm-nav--side[data-cm-fade="both"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
  }

  /* `flex: none` says the thing the min-height only implied: a destination is
     never shrunk and never scrolled away. Five of them at --cm-tap is the fixed
     cost of this column and everything else is laid out around it. */
  .concept-mint--desk .cm-side .cm-nav__item {
    flex: none;
    flex-direction: row; justify-content: flex-start;
    gap: 10px;
    min-height: var(--cm-tap);
    padding: 0 10px;
    font-size: 14px;
    text-align: left;
  }
  .concept-mint--desk .cm-side .cm-nav__item[aria-current="page"] {
    background: var(--cm-accent-bg);
  }
  /* The mark moves from under the destination to beside it, which is where a
     vertical list reads it. */
  .concept-mint--desk .cm-side .cm-nav__item[aria-current="page"]::after {
    left: 0; right: auto; top: 8px; bottom: 8px;
    width: 3px; height: auto;
  }

  /* ---------- 4. The current group's sections, nested ----------------------
     app.js's own sub-tab strip, indented under the destination it belongs to
     rather than drawn as a bar across the top of the screen. Same node, same
     links, same aria-current — concept-mint.css section 5 styles it as a joined
     horizontal bar and every one of those rules is scoped to a direct child of
     #app, so none of them reaches it here. */

  /* THE NEST IS A FLOOR AND NOT A CEILING, and `min-height` is the load-bearing
     declaration in this rule. It was `max-height: min(38vh, 244px)` until
     2026-09-10, argued for as "five rows show and the rest scroll", and the cap
     was wrong twice over.

     Wrong on its own terms: at 1440x900 it stopped at 244px with about 100px of
     empty column sitting under the last destination. It was discarding sections
     while the room to draw them went unused.

     Wrong in a way the cap could not even see, and this is the part that hurt.
     Every destination beside it carries a min-height, so the nest was the only
     child of the nav column that COULD shrink — and the flex algorithm gives
     the whole deficit to whatever can take it. On a short window it collapsed
     far below its own cap: 76px at a 650px viewport, three rows of ten; 0px at
     520px, the entire strip gone with the column above it fitting perfectly.
     A player reported it as "Contacts was being completely skipped".

     So the cap becomes a FLOOR, in the same declaration slot and doing the
     opposite job:

       flex: 0 1 auto   take the space the destinations leave, up to the height
                        of the strip itself, and give it back when the window
                        shrinks — but only down to
       min-height       three rows. Below that the nest stops giving and the
                        column takes over (section 3).

     `0` for the grow factor and not `1`, and the difference is only visible on
     a tall window: with a grow factor this box stretches past its own content,
     which pushes Colonies and everything under it to the floor of the sidebar
     and runs the indent rule 168px past the last section at 1440x1200. It has
     nothing to gain by being taller than the strip inside it.

     THREE ROWS is the smallest nest that still reads as a list rather than as a
     clipped label, and 136px is that: 3 * 44 for the rows plus 2 * 2 for the
     gaps between them. It is not tuned to any particular window — the render
     harness's demo carries an "Exit demo" button the live game does not, which
     is 56px of sidebar a real player gets back, so a number fitted to a demo
     render would be the wrong number for everybody. */
  .concept-mint--desk .cm-side .sub-tabbar {
    display: flex; flex-direction: column; align-items: stretch;
    flex: 0 1 auto;
    min-height: 136px;
    gap: 2px;
    margin: 2px 0 6px 16px;
    padding: 0 0 0 10px;
    background: none;
    border: 0; border-left: 1px solid var(--cm-line-mid);
    border-radius: 0;
    /* Sideways is not a direction this strip has anything in: the labels are
       nowrap and the column is 240px, so `hidden` here is what stops
       `overflow-y: auto` from implying a horizontal scrollbar as well. */
    overflow-x: hidden; overflow-y: auto;
    overscroll-behavior-y: contain;
  }
  /* AND IT GETS ITS SCROLLBAR BACK. game.css styles `.sub-tabbar` unscoped as a
     horizontal phone strip and hides the bar — `scrollbar-width: none`, plus a
     `::-webkit-scrollbar` rule that displays none, the same hidden-scrollbar
     idiom every sideways rail in this client uses — and that reaches this node
     wherever it sits. Down here the strip is vertical and it is the box that
     gives way first, so hiding its only structural signal is exactly the bug
     this rule is fixing. The fade is the second signal, not the only one.

     Both syntaxes, because they are not interchangeable: the standard property
     is what Firefox reads, and Chrome falls back to the legacy pseudo-element
     path for any element the page has written a `::-webkit-scrollbar` rule for,
     which game.css has. Colour comes from the tokens, so both themes paint it. */
  .concept-mint--desk .cm-side .sub-tabbar {
    scrollbar-width: thin;
    scrollbar-color: var(--cm-edge-ui) transparent;
  }
  .concept-mint--desk .cm-side .sub-tabbar::-webkit-scrollbar {
    display: block; width: 8px;
  }
  .concept-mint--desk .cm-side .sub-tabbar::-webkit-scrollbar-track { background: transparent; }
  .concept-mint--desk .cm-side .sub-tabbar::-webkit-scrollbar-thumb {
    background: var(--cm-edge-ui); border-radius: 999px;
  }

  /* The nest's own edge, drawn from the same measurement and the same attribute
     the column uses — see section 3 for why it is a mask and why it is JS. */
  .concept-mint--desk .cm-side .sub-tabbar[data-cm-fade="down"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
  }
  .concept-mint--desk .cm-side .sub-tabbar[data-cm-fade="up"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px);
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px);
  }
  .concept-mint--desk .cm-side .sub-tabbar[data-cm-fade="both"] {
    -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
    mask-image: linear-gradient(180deg, rgba(0, 0, 0, .15), rgba(0, 0, 0, 1) 26px, rgba(0, 0, 0, 1) calc(100% - 26px), rgba(0, 0, 0, .15));
  }
  /* 44px rather than the screen's own 48px --cm-tap floor, and it is the same
     trade concept-mint.css makes for --cm-header-icon on the phone header: 44
     is WCAG 2.2 AAA and the render harness's own minimum, and this is a
     secondary tier under a destination list that is already paying 48. It does
     not go lower. 34px would read better with a mouse — this block is
     desktop-only — but tools/render/layoutFacts.mjs measures every `a` at
     `minTapPx` with no exemption for a non-touch layout, so 34 would turn a
     clean `small-tap=0` into ten findings on the one screen a player lives on. */
  .concept-mint--desk .cm-side .sub-tabbar a {
    display: flex; align-items: center;
    min-height: 44px;
    padding: 0 10px;
    border: 0; border-radius: var(--cm-radius-sm);
    background: none;
    color: var(--cm-muted);
    font-size: 13px; font-weight: 600;
    text-transform: none;
    white-space: nowrap;
  }
  .concept-mint--desk .cm-side .sub-tabbar a:hover { color: var(--cm-text); text-decoration: none; }
  .concept-mint--desk .cm-side .sub-tabbar a[aria-current="page"] {
    background: var(--cm-accent-bg);
    color: var(--cm-accent);
    border-bottom-color: transparent;
  }

  /* ---------- 5. The content column ---------------------------------------
     The strips first, full width of the column, then <main> and the rail side
     by side beneath them. <main> keeps every scroller rule concept-mint.css
     gives it — it is simply no longer a direct child of #app, so those rules
     are restated here rather than inherited.

     THE 880px CAP IS A max-width WITH AUTO MARGINS, which in a flex row is what
     centres it: the column grows to fill the space the rail leaves, stops at
     880, and the leftover goes to the two margins. A line of text 1,000px long
     is a line nobody reads the end of. */

  .concept-mint--desk .cm-desk {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column;
  }
  .concept-mint--desk .cm-desk__body {
    flex: 1 1 auto; min-height: 0;
    display: flex; align-items: stretch;
  }
  .concept-mint--desk .cm-desk__body > main.game-main {
    flex: 1 1 auto; min-width: 0; min-height: 0;
    width: auto; max-width: var(--cm-col-w);
    margin: 0 auto;
    padding: 16px 16px 28px;
    overflow-y: auto;
    overscroll-behavior-y: contain;
    background: var(--cm-bg);
  }
  /* The map stage is full bleed at every width — the chart IS the screen. */
  .concept-mint--desk .cm-desk__body > main.game-main.wide {
    display: flex; flex-direction: column;
    max-width: none;
    margin: 0;
    padding: 0;
  }

  /* ---------- 6. The rail --------------------------------------------------
     The row you opened, beside the list you opened it from. A scroller of its
     own, so the list does not move while you read it. */

  .concept-mint--desk .cm-rail {
    flex: 0 0 var(--cm-rail-w);
    min-width: 0; min-height: 0;
    padding: 16px 16px 28px;
    border-left: 1px solid var(--cm-line);
    background: var(--cm-bg-1);
    overflow-y: auto;
    overscroll-behavior-y: contain;
  }
  /* A rail with nothing opened in it says which list it is waiting on. */
  .concept-mint--desk .cm-rail .cm-empty { margin-top: 20px; }

  /* The <style> node the shell writes the rail's selection mark into. The rule
     it carries names the exact route the rail is showing, so only the shell can
     write it; this is the guarantee that the node itself never draws. */
  .concept-mint--desk .cm-rail-selected { display: none; }

  /* ---------- 7. The map's own sheet IS the map's rail ---------------------
     The mint map opens the system you tap in a cmSheet at the foot of the
     screen, and that is the right shape for a thumb. On a desk it docks down
     the right-hand side instead — the same sheet, the same close button, the
     same content, in the place this layout puts a detail. Nothing is mounted
     twice for the map, which is why it is the one rail with no box of its own.

     The scrim goes with it. A full-viewport wash to close a panel that is not
     covering anything would only swallow the first click on the sidebar. */

  .concept-mint--desk .cm-sheet {
    top: 0; right: 0; bottom: 0; left: auto;
    width: min(var(--cm-rail-w), 46vw);
    max-height: none;
    padding: 16px 16px 28px;
    border: 0; border-left: 1px solid var(--cm-line);
    border-radius: 0;
    box-shadow: -18px 0 40px var(--cm-scrim);
  }
  .concept-mint--desk .cm-sheet__grabber { display: none; }
  .concept-mint--desk .cm-sheet__scrim { display: none; }

  /* ---------- 8. Density ---------------------------------------------------
     Two columns for the kit's own short shapes, once there is a column wide
     enough for two of them. Tiles already flow; these are the two that were
     one-per-row at every width. */

  .concept-mint--desk .cm-desk__body > main.game-main .cm-cta-caption {
    max-width: 60ch;
  }
  .concept-mint--desk .cm-rail .cm-tiles--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
