* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: linear-gradient(180deg, #7f1d1d 0%, #991b1b 55%, #7f1d1d 100%);
  color: #fef2f2; user-select: none; -webkit-user-select: none;
  touch-action: none; overflow: hidden;
}
#app { height: 100%; display: flex; flex-direction: column; max-width: min(100%, 860px); margin: 0 auto; }

#hdr { display: flex; align-items: center; gap: 8px; padding: 8px 12px; padding-top: max(8px, env(safe-area-inset-top)); }
#hdr .pill { background: rgba(0,0,0,0.22); border: 2px solid rgba(255,255,255,0.16); border-radius: 999px; padding: 6px 11px; font-weight: 800; font-size: 15px; min-width: 44px; min-height: 44px; display: flex; align-items: center; cursor: pointer; justify-content: center; color: inherit; font-family: inherit; }
#hdrHome { border: none; background: #fbbf24; color: #7f1d1d; font-size: 18px; }
#hdrStatus { flex: 1; min-width: 0; text-align: center; font-weight: 800; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #fecaca; }

.scr { flex: 1; display: none; flex-direction: column; overflow-y: auto; padding: 6px 14px 18px; }
/* The table gets the full width. 14px of padding either side costs the card
   size directly -- seven columns divide whatever is left, so 28px of margin is
   9% off every card on the narrowest phone. The menu and help screens keep
   their padding; only the board gives it up. */
#scr-play { padding: 6px 4px 6px; }
.scr.on { display: flex; }

#scr-menu { align-items: center; text-align: center; gap: 12px; justify-content: center; }
#scr-menu h1 { font-size: clamp(32px, 9vw, 44px); color: #ffffff; }
#scr-menu .sub { color: #fecaca; font-weight: 600; margin-bottom: 4px; }
#tierRow { display: flex; gap: 8px; width: 100%; }
.tierCard { flex: 1; background: rgba(0,0,0,0.2); border: 3px solid rgba(255,255,255,0.14); border-radius: 16px; padding: 10px 4px; font-weight: 800; font-size: 14px; line-height: 1.35; cursor: pointer; color: #fef2f2; font-family: inherit; }
.tierCard small { display: block; color: #fecaca; font-weight: 700; font-size: 11.5px; }
.tierCard .te { font-size: 26px; display: block; }
.tierCard.sel { border-color: #fbbf24; background: rgba(251,191,36,0.14); }
/* Settings, behind a disclosure. Same shape as word-search and cross-math so
   a player who has met one has met them all. */
#custom { width: 100%; margin: 2px 0; text-align: left; background: rgba(0,0,0,0.2); border: 3px solid rgba(255,255,255,0.13); border-radius: 16px; padding: 6px 12px 10px; }
#custom > summary { list-style: none; cursor: pointer; font-weight: 800; font-size: 16px; padding: 10px 2px; min-height: 44px; display: flex; align-items: center; gap: 8px; }
#custom > summary::-webkit-details-marker { display: none; }
#custom > summary::before { content: "▸"; transition: transform .12s; }
#custom[open] > summary::before { transform: rotate(90deg); }
.field { display: flex; align-items: center; gap: 10px; margin: 7px 0; }
.field .lbl { flex: 0 0 104px; font-size: 13.5px; font-weight: 800; color: #fecaca; }
.seg { flex: 1; display: flex; gap: 6px; }
.seg button { flex: 1; min-height: 44px; border-radius: 11px; border: 2px solid rgba(255,255,255,0.16); background: rgba(0,0,0,0.24); color: #fef2f2; font-family: inherit; font-weight: 800; font-size: 13.5px; cursor: pointer; padding: 4px 2px; }
.seg button.on { background: #fbbf24; border-color: #d97706; color: #7f1d1d; min-height: 44px;}
#optNote { font-size: 12.5px; line-height: 1.45; color: #fecaca; font-weight: 600; margin: 8px 2px 2px; }

button.big { width: 100%; border-radius: 16px; min-height: 56px; font-size: 19px; font-weight: 800; background: rgba(0,0,0,0.2); color: #fef2f2; border: 3px solid rgba(255,255,255,0.14); cursor: pointer; font-family: inherit; }
button.big:active { transform: translateY(2px); }
button.big.primary { background: #fbbf24; border-color: #d97706; color: #7f1d1d; min-height: 44px;}

/* play */
#playTop { display: flex; align-items: center; justify-content: space-between; font-weight: 800; padding: 2px 2px 6px; font-size: 15px; min-height: 22px; }

#stageWrap { flex: 1; position: relative; min-height: 0; }
canvas#stage { display: block; touch-action: none; }

/* The "dealing" line. It exists because the deal SEARCHES for a winnable hand
   before it shows one, and a blank table for even 200ms reads as a dead tap.
   It sits over the table rather than replacing the screen, so nothing jumps. */

/* Centred, and it stays centred. It was moved to the bottom for one release,
   to keep it off the cards it was describing — but that was treating the
   symptom. The panel CARRIES the cards now (see the result rows in app.js), so
   there is nothing behind it that has to be read, and centre is where the most
   important message in the game belongs. A panel in a corner puts its buttons
   next to the home indicator and makes the eye travel for the one thing it
   most wants.
   overflow-y stays: a four-player summary is a tall panel on a short phone,
   and a message that runs off the top is worse than one that scrolls. */
.ovl { position: absolute; inset: 0; display: none; align-items: flex-start; justify-content: center; background: rgba(40,8,12,0.55); border-radius: 12px; padding: 16px; overflow-y: auto; }
.ovl.on { display: flex; }
.ovlCard { text-align: center; width: 100%; max-width: 320px; display: flex; flex-direction: column; gap: 10px; margin: auto;}
/* THE OVERLAY REPORTS ON THE TABLE, SO IT MUST NOT HIDE THE TABLE.
   It was a 90%-opaque curtain over the felt — and what it says is "Robin took
   three tricks", "the pot goes to Kit", "kings and fours". Every one of those
   sentences is about cards the player can no longer see. That is not a tuning
   nit; it is the overlay defeating its own purpose, the same shape as a word
   game refusing a word for being too hard.
   The fix is not just less alpha, which would leave white text on a busy felt.
   The scrim goes down to a dim, and the WORDS move onto a panel of their own,
   so the message is more legible than before and the table is still there
   around it. Overlays whose board is irrelevant once they appear — a game-over
   in an arcade game — are left opaque on purpose. */
.ovlCard { background: rgba(48,10,14,0.96); border: 2px solid rgba(255,255,255,0.16);
            border-radius: 18px; padding: 16px 14px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.45); margin: auto;}

#ovlTitle { font-size: 26px; font-weight: 800; color: #ffffff; }
#ovlSub { color: #fecaca; font-weight: 700; min-height: 22px; line-height: 1.45; }

#scr-how .card { background: rgba(0,0,0,0.2); border: 3px solid rgba(255,255,255,0.13); border-radius: 16px; padding: 14px; margin-bottom: 10px; font-size: 15px; line-height: 1.55; font-weight: 600; }
#scr-how h2 { margin-bottom: 8px; color: #ffffff; }

/* The legend (docs/offline-games-pwa.md R-L1). One column of swatches at a
   fixed width so the eye can run the column instead of the text. The suit
   swatches are built from cards.js and the ink colours come from render.js —
   nothing here restates a colour the game paints, which is how a legend ends
   up showing a shade the product no longer uses. */
.legend { display: flex; flex-direction: column; gap: 7px; }
.lgRow { display: flex; align-items: center; gap: 10px; }
.lgArt { flex: none; width: 46px; display: flex; align-items: center; justify-content: center; }

.lgRing { width: 26px; height: 37px; border-radius: 4px; background: rgba(255,255,255,0.1); }
.lgRing.gold  { box-shadow: 0 0 0 3px #fbbf24; }

.lgTxt { display: flex; flex-direction: column; min-width: 0; }
.lgTxt b { font-size: 14px; font-weight: 800; }
.lgTxt small { font-size: 12.5px; color: #fecaca; line-height: 1.3; font-weight: 600; }

#toast { position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%); background: #ffffff; color: #7f1d1d; font-weight: 800; padding: 9px 16px; border-radius: 999px; opacity: 0; transition: opacity 0.25s; pointer-events: none; z-index: 40; max-width: calc(100vw - 32px); text-align: center; }
#toast.on { opacity: 1; }

/* docs/offline-pwa.md R-C15 — the PAGE must never scroll. The product is a
   fixed frame: header, a named scroll region, footer. If the document scrolls
   too, the header scrolls away and a drag that reaches the end of the inner
   region chains out and drags the whole table under the player's thumb. */
html, body { overflow: hidden; overscroll-behavior: none; }
.scr { overscroll-behavior: contain; }

/* --- hearts only ---------------------------------------------------------- */
#playTop { font-size: 13px; gap: 8px; }
/* THE ROW IS ALWAYS HERE, EVEN WHEN IT HAS NOTHING TO SAY.
   `visibility` hides it, not `display`, so the box keeps its place in the
   layout. Hiding it with display:none made #stageWrap taller, which re-fitted
   the canvas, which re-laid the whole table — so every card resized and slid
   the moment the row appeared, and slid back when it went. Reserving the
   height removes the cause; toggling a class only ever chased the symptom.
   min-height is the 44px touch floor plus this row's own padding. */
#passRow { flex: none; display: block; min-height: 60px; visibility: hidden;
           padding: 8px 4px max(4px, env(safe-area-inset-bottom)); }
#passRow.on { visibility: visible; }

.lgPip { font-size: 22px; color: #0f172a; background: #fff; border-radius: 4px; padding: 1px 5px; }
.lgPip.red { color: #dc2626; }
.lgQ { color: #dc2626; margin-left: -14px; font-size: 13px; }
.lgDim { width: 26px; height: 37px; border-radius: 4px; background: #fff; box-shadow: inset 0 0 0 40px rgba(15,60,35,0.55); display: inline-block; }
.lgRing { width: 26px; height: 37px; border-radius: 4px; background: #fff; box-shadow: 0 0 0 3px #fbbf24; display: inline-block; }
.lgMoon { font-size: 20px; }

/* The tricks record. A wide overlay because the content is a table of four
   cards a row, and a narrow column would wrap every one of them. */
#btnTricks, #btnPlayForMe { flex: none; min-width: 34px; min-height: 34px; border-radius: 10px; border: 2px solid rgba(255,255,255,0.16); background: rgba(0,0,0,0.24); color: inherit; font-size: 15px; cursor: pointer; font-family: inherit; padding: 0 6px; }
#btnTricks:active, #btnPlayForMe:active { transform: translateY(1px); }
/* #266. Lit, not tinted: automation the player cannot see cannot be trusted. */
#btnPlayForMe[aria-pressed="true"] { background: #f59e0b; border-color: #fbbf24; color: #1c1917; }
.ovlCard.wide { max-width: 460px; margin: auto;}
#ovlTitle2 { font-size: 22px; font-weight: 800; color: #ffffff; }
#trickList { max-height: 46vh; max-height: 46dvh; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 4px; text-align: left; padding: 2px; }
#trickList:empty::after { content: "Nothing yet — the first trick will show up here."; color: #fecaca; font-weight: 700; font-size: 14px; }
.trRow { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 13px; padding: 5px 6px; border-radius: 8px; background: rgba(255,255,255,0.05); }
.trNo { flex: none; width: 20px; color: #fecaca; font-variant-numeric: tabular-nums; }
/* The cards take exactly the room the cards need — `flex: 1` gave the column a
   whole row's width and pushed the winner's name to the far edge, leaving a
   band of dead space in the middle of every line. A column sized to its
   content puts the name right beside the trick it belongs to. */
.trCards { flex: 0 1 auto; display: flex; gap: 4px; flex-wrap: wrap; }
.trC { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; height: 26px; border-radius: 4px; background: #fff; color: #0f172a; font-size: 12px; font-weight: 800; border: 1px solid #94a3b8; }
.trC.red { color: #dc2626; }
.trC.win { box-shadow: 0 0 0 3px #fbbf24; }
.trPts { flex: 0 0 auto; font-size: 12px; font-weight: 800; color: #fca5a5;
         font-variant-numeric: tabular-nums; padding-left: 4px; }
.trWho { flex: 1 1 auto; font-size: 12px; color: #fbbf24; text-align: left; padding-left: 2px; white-space: nowrap; }

/* THE SCOREBOARD ROW (R-T5, R-C19). Fixed height, and nothing in it changes
   width by more than a digit. Four chips because there are four players and
   no teams; the one in front is marked, because "lowest is winning" is the
   rule of Hearts that a scoreboard of bare numbers hides. */
#playTop { font-size: 13px; gap: 4px; min-height: 30px; align-items: stretch;
           justify-content: flex-start; padding: 2px 2px 3px; }
#playTop .gap { flex: 1 1 auto; min-width: 0; }
.chip { flex: 0 1 auto; min-width: 0; display: inline-flex; align-items: center;
        gap: 4px; padding: 0 7px; border-radius: 999px; background: rgba(0,0,0,0.26);
        border: 2px solid rgba(255,255,255,0.14); line-height: 1; }
.chip i { font-style: normal; font-size: 10px; font-weight: 800; opacity: 0.72;
          letter-spacing: 0.02em; overflow: hidden; text-overflow: ellipsis; }
.chip b { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; }
/* Yours, so you can find it without reading all four. */
#sc0 { border-color: rgba(254,202,202,0.55); color: #fecaca; }
.chip.lead { background: rgba(74,222,128,0.16); border-color: rgba(74,222,128,0.6); }

/* The message. Its own row, reserved whether or not there is anything to say
   — an empty line that holds its height cannot move the table. */
#msgLine { flex: none; min-height: 20px; display: flex; align-items: center;
           justify-content: center; padding: 0 4px 3px; }
#msgOut { font-weight: 800; font-size: 13px; white-space: nowrap;
          overflow: hidden; text-overflow: ellipsis; max-width: 100%; }

/* THE RESULT ROWS (docs/offline-games-pwa.md, "a result must carry its
   evidence"). One row per player or per team: who, the thing itself, what it
   was worth. Same class names as Poker's showdown, because it is the same idea
   and a second vocabulary for it would drift.
   `#ovlSub` becomes a column here rather than a paragraph, so the rows stack
   and their columns line up. */
#ovlSub { display: flex; flex-direction: column; gap: 5px; min-height: 0; }
.sdRow { display: flex; align-items: center; gap: 7px; padding: 5px 7px;
         border-radius: 10px; background: rgba(255,255,255,0.05);
         border: 2px solid transparent; text-align: left; }
.sdRow.you  { background: rgba(255,255,255,0.10); }
.sdRow.win  { border-color: #4ade80; background: rgba(74,222,128,0.14); }
.sdWho   { flex: 0 0 52px; font-size: 13px; font-weight: 800; }
.sdHand  { flex: 1 1 auto; font-size: 12px; font-weight: 700; line-height: 1.25;
           color: #fecaca; }
.sdSwing { flex: 0 0 auto; font-size: 13px; font-weight: 800;
           font-variant-numeric: tabular-nums; color: #fca5a5; }
.sdSwing.up { color: #4ade80; }

/* The Settings panel's help line. It was in the markup with no rule behind it,
   so it rendered at body size in body colour where every other product shows
   it small and muted -- `just check-settings` found it once the guard started
   deriving the panel's OWN class vocabulary instead of demanding `.field` and
   `.seg` by name. Markup with no rules behind it is not a control. */
.blurb { margin: 6px 0 2px; font-size: 12.5px; line-height: 1.45; color: #fecaca; }
