/* ═══════════════════════════════════════════════════════════════
   careiti-appshell.css — the app uses the whole screen

   Measured before this file: post-login pages occupied 69% of a landscape
   iPad and 80% of an iPad Pro, almost all of it in a single column, with
   374px of bare paper down the sides.

   The cause was my own --ct-max: 820px. That number is a READING measure —
   it exists so a paragraph does not run to 60 characters a line — and it is
   correct for the evidence pages and the marketing site. It is wrong for an
   app. A rewards list, a mission list, a game hub and a session history are
   COLLECTIONS, not prose: nobody reads them left to right, and holding them
   to a paragraph's width wastes a third of the screen while forcing the
   reader to scroll past items that would have fit side by side.

   So the rule is by content type, not by breakpoint:
     collections  → fill the screen, flow into as many columns as fit
     prose        → keep the reading measure

   `:has()` is what lets a stylesheet tell the two apart. Where it is
   unsupported the page simply keeps today's single column — the same
   behaviour as before this file, never worse.
   ═══════════════════════════════════════════════════════════════ */

:root { --ct-wide: min(96vw, 1240px); }

@media (min-width: 740px) {

  /* ── Collections take the screen ─────────────────────────────── */
  body[data-ct="app"] .container:has(.gcard),
  body[data-ct="app"] .container:has(.fcard),
  body[data-ct="app"] .container:has(.reward-card),
  body[data-ct="app"] .container:has(.mission-card),
  body[data-ct="app"] .container:has(.tier-card),
  body[data-ct="app"] .wrap:has(.reward-card),
  body[data-ct="app"] .wrap:has(.mission-card),
  body[data-ct="app"] .page:has(.session-card),
  body[data-ct="app"] .records-wrap:has(.session-card),
  body[data-ct="app"] .c-wrap:has(.gcard),
  body[data-ct="app"] .tabs-wrap,
  body[data-ct="app"] .dash-wrap,
  body[data-ct="app"] .container:has(.row),
  body[data-ct="app"] .container:has(.lb-row),
  body[data-ct="app"] .container:has(.board-head),
  /* /science is nine cards of ~210 characters each, not an essay. I had
     .sci-card in the PROSE list below, so the reading measure was applied
     to something nobody reads left-to-right — 653px of cards inside a
     1178px screen. Gated on :has(.sci-card) so this cannot reach the other
     meaning of .c-wrap (the memory game's flip card), which is the
     collision that has already broken this file three times. */
  body[data-ct="app"] .c-wrap:has(.sci-card),
  body[data-ct="app"] .container:has(.sci-card),
  body[data-ct="app"] [data-collection] {
    max-width: var(--ct-wide);
  }

  /* ── and flow into as many columns as fit ────────────────────── */
  body[data-ct="app"] .games-grid,
  body[data-ct="app"] .feat-grid,
  body[data-ct="app"] .cards,
  body[data-ct="app"] .game-cards,
  body[data-ct="app"] [data-collection-grid] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(260px, 26vw, 340px), 1fr));
    gap: clamp(14px, 1.6vw, 24px);
    /* Cards in a collection are peers, so they are the same height. With
       `align-items:start` each one was only as tall as its own text, and a
       row containing a two-line description sat taller than its neighbours —
       measured 197px against 174px on a landscape iPad. `stretch` equalises
       within a row; `grid-auto-rows: 1fr` equalises across rows too, so the
       whole grid reads as one set rather than a ragged stack. */
    align-items: stretch;
    grid-auto-rows: 1fr;
  }

  /* Lists that were never a grid at all — a stack of cards in a block
     container. Given a parent that holds several, they become one.

     Matched by STRUCTURE, not by the parent's class name. The previous
     version named the parents it expected (.wrap, .container,
     .progress-wrap, .records-wrap, .page) and /missions put its nine
     cards in `div.anim-up` — an animation wrapper with no semantic class
     — so it stayed a single column 1090px wide. That is the third time
     in this project a hand-written list of class names has covered only
     the cases someone remembered.

     `:has(> .x ~ .x)` reads as "a parent with at least two of these as
     direct children", which is the actual condition for wanting a grid.
     One card is not a collection, and gridding its parent would stretch
     a lone card across the screen. */
  /* Whatever else is in that container spans the row. Selecting the
     parent by its contents means the parent may hold more than cards —
     /rewards keeps a heading and a .filter-tabs row in the same section,
     and both became 338px grid cells beside the cards. The condition that
     makes something a column is "it is one of the cards", so everything
     else spans. Stated here rather than by listing .filter-tabs and
     friends, because the next such element has not been written yet. */
  body[data-ct="app"] :has(> .reward-card ~ .reward-card) > *:not(.reward-card),
  body[data-ct="app"] :has(> .mission-card ~ .mission-card) > *:not(.mission-card),
  body[data-ct="app"] :has(> .session-card ~ .session-card) > *:not(.session-card) {
    grid-column: 1 / -1;
  }

  body[data-ct="app"] :has(> .reward-card ~ .reward-card),
  body[data-ct="app"] :has(> .mission-card ~ .mission-card),
  body[data-ct="app"] :has(> .session-card ~ .session-card) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(280px, 28vw, 380px), 1fr));
    gap: clamp(14px, 1.6vw, 24px);
    align-items: start;
  }

  /* Headers, tab bars, summaries and anything explicitly marked keep the
     full width above the grid so the page still reads top-to-bottom. */
  body[data-ct="app"] .wrap > h1,
  body[data-ct="app"] .wrap > h2,
  body[data-ct="app"] .container > h1,
  body[data-ct="app"] .container > h2,
  body[data-ct="app"] .container > .hero,
  body[data-ct="app"] .container > .page-header,
  body[data-ct="app"] .records-wrap > .page-header,
  body[data-ct="app"] .cgm-switch,
  body[data-ct="app"] .cgm-note,
  body[data-ct="app"] .cht-open,
  body[data-ct="app"] [data-span-all] { grid-column: 1 / -1; }

  /* ── Prose ───────────────────────────────────────────────────── */
  body[data-ct="app"] .sci-card,
  body[data-ct="app"] .evidence-body,
  body[data-ct="app"] .legal,
  body[data-ct="app"] article { max-width: 100%; }

  /* The bottom nav follows the wider shell so it does not float in the
     middle of a screen whose content now reaches the edges. */
  body[data-ct="app"] .bnav-dark,
  body[data-ct="app"] .bnav,
  body[data-ct="app"] .c-nav { width: min(var(--ct-wide), 100%); }
}

/* Very wide landscape: cap the column count so cards do not shrink into a
   contact sheet. Four across is the most this content reads well at. */
@media (min-width: 1500px) {
  body[data-ct="app"] .games-grid,
  body[data-ct="app"] .feat-grid,
  body[data-ct="app"] [data-collection-grid] {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Below 760px nothing here applies: phones keep the single column, which
   is right for their width.

   The gate used to be 900px, and that number quietly excluded the device
   this project exists for. A 10.9" iPad in PORTRAIT is 820 CSS px; an
   11" Pro is 834; a mini is 744. All three sat under 900, so every
   collection on the app rendered as one narrow column with a third of the
   screen left blank — measured 80% used on /science at 820, against 93%
   at 1194. Portrait is also how someone reads on a tablet in their lap.

   740 is chosen so the 744px mini clears it too — 760 did not, which is
   exactly the sort of off-by-a-device that a comment can assert and a
   measurement cannot. The grid does not need a
   second breakpoint to stay sensible: auto-fill with a 260px minimum
   yields two columns at 740-1000 and more only when there is room. */


/* ── /my ────────────────────────────────────────────────────────
   The shell stays a block — see careiti-fit.css for why gridding it broke
   the page. What uses the width is the card column INSIDE it, whose children
   are all cards and therefore safe to flow. Selected as "the child of
   .dash-wrap that is neither the header nor the tab bar", because the markup
   gives that div no class of its own. */
@media (min-width: 740px) {
  body[data-ct="app"] .dash-wrap > div:not(.dash-header):not(.tab-bar) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(300px, 30vw, 420px), 1fr));
    gap: clamp(14px, 1.6vw, 24px);
    /* Blocks sitting side by side are the same height. `start` left each
       one at its own content height — measured 253px against 225px on a
       landscape iPad — so the two columns ended at different places and
       the panel read as unfinished rather than as a pair.

       `stretch` matches within a ROW, which is the right unit: it does
       not force a lone block on the last row to the height of a tall row
       above it, the way `grid-auto-rows: 1fr` would. */
    align-items: stretch;
  }
  /* Stretch only sizes the grid ITEM. The card drawn inside has to be
     told to take that height, and to lay its own contents out down the
     column, or the extra space lands wherever block flow leaves it. */
  body[data-ct="app"] .dash-wrap > div:not(.dash-header):not(.tab-bar) > * {
    display: flex;
    flex-direction: column;
    min-height: 100%;
  }
  body[data-ct="app"] .dash-header,
  body[data-ct="app"] .tab-bar { width: 100%; }
  /* Tab labels wrapped one character per line inside a 358px cell. */
  body[data-ct="app"] .tab-bar { white-space: nowrap; }
}


/* ── Equal-height cards need their insides laid out ─────────────
   A card that is taller than its content leaves the gap wherever the block
   flow happens to put it, which reads as a mistake. Making the card a
   column and pushing the tag row to the bottom means the extra height lands
   in one deliberate place: between the description and the tags. */
body[data-ct="app"] .gcard,
body[data-ct="app"] .fcard,
body[data-ct="app"] .reward-card,
body[data-ct="app"] .mission-card {
  display: flex;
  flex-direction: column;
}
body[data-ct="app"] .gcard .gtags,
body[data-ct="app"] .gcard .gtag-row { margin-top: auto; padding-top: 10px; }
body[data-ct="app"] .fcard > div:last-child { margin-top: auto; }

/* /science wraps each card in an unclassed div, so the GRID stretches the
   wrapper and the card inside it keeps its content height — the row looks
   equal to within a pixel or two and the card borders do not line up.
   Stretch has to be passed down to whatever is actually drawn. */
@media (min-width: 740px) {
  body[data-ct="app"] .game-cards > * { display: flex; }
  body[data-ct="app"] .game-cards > * > .sci-card,
  body[data-ct="app"] .game-cards > .sci-card { flex: 1; width: 100%; }
}
