* { 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;
  /* A cool blue felt, and deliberately not the green of the rummy pair or the
     saloon red of Pitch: this is the thinking game on the shelf, and the shelf
     is easier to navigate when the colour is part of the name. */
  background: linear-gradient(180deg, #0c4a6e 0%, #075985 55%, #0c4a6e 100%);
  color: #f0f9ff; 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: #38bdf8; color: #0c4a6e; 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: #bae6fd; }

.scr { flex: 1; display: none; flex-direction: column; overflow-y: auto; padding: 6px 14px 18px; }
/* The table gets the full width: side padding comes straight off the card size. */
#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: #bae6fd; 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: #f0f9ff; font-family: inherit; }
.tierCard small { display: block; color: #bae6fd; font-weight: 700; font-size: 11.5px; }
.tierCard .te { font-size: 26px; display: block; }
.tierCard.sel { border-color: #38bdf8; background: rgba(56,189,248,0.16); }

/* Settings, behind a disclosure — the same shape as every other product's. */
#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); }
/* WRAPS (R-G26.9). A settings row is [label][segmented control], and the
   control's width is decided by its option labels at runtime. Measured at
   320px this row ran 4px past the screen edge, so the last option was
   cut in half — a control you cannot see or reliably hit. Wrapping drops
   the control onto its own line ONLY when it has to; at 375px and wider
   nothing moves. */
.field { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 7px 0; }
.field .lbl { flex: 0 0 104px; font-size: 13.5px; font-weight: 800; color: #bae6fd; }
.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: #f0f9ff; font-family: inherit; font-weight: 800; font-size: 13.5px; cursor: pointer; padding: 4px 2px; }
.seg button.on { background: #38bdf8; border-color: #0284c7; color: #0c4a6e; min-height: 44px;}
.blurb { margin: 6px 0 2px; font-size: 12.5px; line-height: 1.45; color: #bae6fd; }

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

/* --- play ----------------------------------------------------------------- */
/* THE SCOREBOARD ROW (R-C19). Fixed height, and nothing in it changes width by
   more than a digit, so a message arriving cannot shove the numbers sideways. */
#playTop { display: flex; font-size: 13px; gap: 5px; min-height: 30px;
           align-items: stretch; justify-content: flex-start; padding: 2px 2px 3px;
           font-weight: 800; }
#playTop .gap { flex: 1 1 auto; min-width: 0; }
.chip { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
        padding: 0 8px; 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; }
.chip b { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; }
.chip#trumpChip.set { border-color: #38bdf8; background: rgba(56,189,248,0.18); }
.chip#trumpChip.red b { color: #fecaca; }

/* R13. THE OVER/UNDER CHIP, AND IT IS THE MOST USEFUL THING ON THE SCREEN.
   `5/4` means five tricks bid and four to be had: the table is fighting and
   somebody is going down. `3/4` means one is going spare and will be handed to
   whoever least wants it. Colour says which, and the numbers say it too —
   colour is never the only carrier. */
.chip#pressChip.over  { border-color: #fca5a5; background: rgba(252,165,165,0.16); }
.chip#pressChip.over b  { color: #fecaca; }
.chip#pressChip.under { border-color: #fbbf24; background: rgba(251,191,36,0.14); }
.chip#pressChip.under b { color: #fde68a; }

#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%; }

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

/* THE BID ROW IS ALWAYS HERE, EVEN WITH NOTHING TO SAY. `visibility`, not
   `display`: hiding it with display:none makes #stageWrap taller, which re-fits
   the canvas, which re-lays the whole table — so every card resizes and slides
   the moment the row appears, and slides back when it goes (R-C19). */
#bidRow { flex: none; display: flex; flex-wrap: wrap; gap: 6px; justify-content: center;
          align-items: center; min-height: 60px; visibility: hidden;
          padding: 8px 4px max(4px, env(safe-area-inset-bottom)); }
#bidRow.on { visibility: visible; }
.bidBtn { min-width: 48px; min-height: 44px; border-radius: 12px; font-family: inherit;
          font-weight: 800; font-size: 16px; cursor: pointer; color: #f0f9ff;
          background: rgba(0,0,0,0.24); border: 2px solid rgba(255,255,255,0.16); padding: 0 10px; }
.bidBtn:active { transform: translateY(2px); }
/* The game's own estimate, marked in gold. The opponents bid on this number and
   there is no reason to make a nine-year-old guess blind at the one move that
   is entirely a guess. */
.bidBtn.hint { border-color: #fbbf24; color: #fbbf24; }
/* R12. THE HOOK, SHOWN RATHER THAN REMOVED. The dealer may not make the bids
   add up, and the barred number is greyed IN PLACE with the reason on it —
   dropping it from the row would make the row one shorter and teach nothing.
   Kept tappable so the explanation has somewhere to come from. */
.bidBtn.hook { opacity: 0.42; border-style: dashed; color: #bae6fd; cursor: default; }
.bidBtn.hook:active { transform: none; }

.ovl { position: absolute; inset: 0; display: none; align-items: flex-start; justify-content: center; background: rgba(3,44,66,0.55); border-radius: 12px; padding: 16px; overflow-y: auto; }
.ovl.on { display: flex; }
/* The overlay REPORTS ON THE TABLE, so it must not hide the table: the scrim is
   a dim and the words sit on a panel of their own. */
.ovlCard { text-align: center; width: 100%; max-width: 360px; display: flex; flex-direction: column; gap: 10px;
           background: rgba(4,42,64,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: #bae6fd; font-weight: 700; min-height: 22px; line-height: 1.45;
          display: flex; flex-direction: column; gap: 5px; }

/* THE RESULT ROWS ("a result must carry its evidence"). One row per player:
   what they said, what they got, what it was worth. Same class names as the
   other card games, because it is the same idea and a second vocabulary for it
   would drift. */
.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 62px; font-size: 13px; font-weight: 800; }
.sdHand { flex: 1 1 auto; font-size: 12px; font-weight: 700; line-height: 1.25; color: #bae6fd; }
.sdSwing { flex: 0 0 auto; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; color: #fca5a5; }
.sdSwing.up { color: #4ade80; }

/* --- help ----------------------------------------------------------------- */
#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; }
#scr-how ul { margin: 6px 0 0 18px; }
#scr-how li { margin: 3px 0; }

/* The legend (R-L1). One column of swatches at a fixed width, so the eye can
   run the column instead of the prose. */
.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; }
.lgTxt { display: flex; flex-direction: column; min-width: 0; }
.lgTxt b { font-size: 14px; font-weight: 800; }
.lgTxt small { font-size: 12.5px; color: #bae6fd; line-height: 1.3; font-weight: 600; }
.lgCard { width: 26px; height: 37px; border-radius: 4px; background: #fff; display: inline-block; }
.lgCard.tr { box-shadow: inset 0 0 0 2px #f59e0b; }
.lgCard.dim { box-shadow: inset 0 0 0 40px rgba(15,23,42,0.55); }
.lgCard.live { box-shadow: 0 0 0 3px #4ade80; }
/* The seat swatch is the whole game in two characters, so the legend shows the
   two states that matter rather than describing them. */
.lgSeat { display: inline-flex; align-items: center; justify-content: center; min-width: 34px;
          height: 24px; border-radius: 7px; background: rgba(0,0,0,0.3);
          font-weight: 800; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.lgSeat.exact { color: #4ade80; box-shadow: inset 0 0 0 2px #4ade80; }
.lgSeat.over { color: #fca5a5; box-shadow: inset 0 0 0 2px #fca5a5; }
.lgBid { display: inline-flex; align-items: center; justify-content: center; min-width: 30px; height: 26px;
         border-radius: 7px; background: rgba(0,0,0,0.3); border: 2px solid rgba(255,255,255,0.2);
         font-weight: 800; font-size: 12px; }
.lgBid.hint { border-color: #fbbf24; color: #fbbf24; }
.lgBid.hook { opacity: 0.42; border-style: dashed; color: #bae6fd; }
.lgD { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
       border-radius: 999px; background: #38bdf8; color: #052e3f; font-weight: 800; font-size: 14px; }

#toast { position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%); background: #ffffff; color: #0c4a6e; 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. */
html, body { overflow: hidden; overscroll-behavior: none; }
.scr { overscroll-behavior: contain; }

/* A TURNED PHONE HAS NO SPARE ROWS (R-T6). Every line of chrome here is a line
   the felt does not get, and at 375px of window height the felt is what the
   game IS. The text shrinks and the reserved rows tighten; the 44px touch floor
   on the bid buttons does not move, because that is the one thing that must
   never give way. The bid row also has more buttons than any other game here —
   eleven at a ten-card hand — so it wraps rather than scrolls. */
@media (orientation: landscape) and (max-height: 500px) {
  #hdr { padding: 4px 10px; padding-top: max(4px, env(safe-area-inset-top)); }
  #playTop { padding: 0 4px 2px; font-size: 12px; min-height: 0; }
  #msgLine { min-height: 15px; padding: 0 4px 1px; }
  #msgOut { font-size: 11.5px; }
  #bidRow { min-height: 52px; padding: 4px 4px max(2px, env(safe-area-inset-bottom)); }
  .bidBtn { min-width: 44px; padding: 0 7px; }
}
/* #228: the landscape footer float lives in version.js, which owns the footer's
   layout for every product. Nothing product-specific is left here. */
