  :root{
    --felt:#2C8A5A; --felt-deep:#123528; --felt-lip:#35624B;
    --ivory:#FBF8F1; --ivory-shade:#E9E2D2;
    --verm:#F0552B; --verm-deep:#C33A1C;
    --jade:#A9C4B4; --jade-dim:#6E8A7B;
    --gold:#F4BE3A;
    --suit-red:#D63A2C; --suit-ink:#22201A;
    --plate:#0F1E18; --label:#A6DBBC; --label-deep:#3E8A62;
    --disp:'Fraunces', Georgia, 'Times New Roman', serif;
    --ui:'Karla', 'Avenir Next', 'Segoe UI', sans-serif;
  }
  html,body{height:100%;}
  html{
    /* clean, calm surround — no pattern; light enough for the dark top-bar text, lets the felt sit forward */
    background-color:#E7E0D2;
    background-image:radial-gradient(ellipse at 50% 12%, #EFE9DC 0%, #E2DACB 55%, #D3CAB7 100%);
  }
  /* phones: scale the rem base so the felt's contents (cards, plates, stacks) shrink to fit. desktop stays 16px. */
  html{font-size:clamp(8.5px, 2.6vmin, 16px);}
  body{
    margin:0; font-family:var(--ui); color:var(--jade);
    /* the parlor floor: warm cherrywood, lamp pooling over the table */
    background:transparent;
    overflow:hidden; -webkit-user-select:none; user-select:none;
  }
  /* the whole play field: one centered, capped stage so the seats hug the felt,
     not the window edge — felt + seats scale together (rem base = 16px) */
  #stage{
    position:fixed; left:50%; top:50%; transform:translate(-50%,-50%);
    width:min(94vw, 66.25rem); height:min(92%, 53.5rem); z-index:0;
  }
  #feltoval{
    position:absolute; left:50%; top:46%; transform:translate(-50%,-50%);
    width:80%; height:64%;
    border-radius:50%; z-index:0;
    background:radial-gradient(ellipse at 50% 38%, #3BB978 0%, #22A063 52%, #0E7A45 100%);
    box-shadow:
      inset 0 0.375rem 1.5rem rgba(0,0,0,.24),
      0 0 0 0.8125rem #8A5E3C,
      0 0 0 1rem #6A4326,
      0 1rem 2.5rem rgba(0,0,0,.28);
  }
  /* ---------- chairs: wood backs pulled up to the table, tucked under the rail ---------- */
  .chair{display:none; position:absolute; z-index:0; border-radius:999px;
    background:linear-gradient(160deg, #7C5334 0%, #5A3B22 100%);
    box-shadow:inset 0 0.125rem 0 rgba(255,226,190,.16), inset 0 -0.375rem 0.75rem rgba(0,0,0,.2),
      0 0.5rem 1.125rem rgba(0,0,0,.24);}
  #chair-n{left:50%;   top:4%;    transform:translate(-50%,-50%); width:12%; height:9%;}
  #chair-s{left:50%;   top:78%;   transform:translate(-50%,-50%); width:12%; height:9%;}
  #chair-w{left:5%;    top:40%;   transform:translate(-50%,-50%); width:5%;  height:24%;}
  #chair-e{left:95%;   top:40%;   transform:translate(-50%,-50%); width:5%;  height:24%;}
  #table{position:absolute; inset:0; z-index:1;
    display:grid; height:100%; box-sizing:border-box; padding:1.125rem 1.625rem 1.25rem;
    grid-template-rows:auto 1fr auto;
    grid-template-columns:9.375rem minmax(0,1fr) 9.375rem; grid-template-areas:"north north north" "west center east" "south south south";}

  /* ---------- brand ---------- */
  #brand{position:fixed; top:14px; left:20px; z-index:5; line-height:1;}
  #brand h1{font-family:var(--disp); font-weight:800; font-size:34px; margin:0; color:var(--felt-deep); letter-spacing:.06em;}
  .brandmark{height:44px; width:auto; display:block;}
  #brand h1 span{color:var(--verm);}
  #brand small{display:block; margin-top:4px; font-size:11.5px; letter-spacing:.06em; color:#2A5744; font-style:italic;}
  #topbtns{position:fixed; top:16px; right:20px; z-index:25; display:flex; gap:8px; align-items:center;}
  #menubtn{width:38px; height:38px; padding:0; display:grid; place-items:center; font-size:17px; line-height:1;}
  #menu{position:fixed; top:62px; right:20px; z-index:25; display:none; flex-direction:column; gap:1rem;
    background:var(--plate); border:1px solid rgba(169,196,180,.28); border-radius:14px;
    padding:1.1rem 1.2rem; min-width:230px; box-shadow:0 18px 44px rgba(0,0,0,.55);}
  #menu.open{display:flex;}
  /* App/phone fix (2026-10-01): the menu is taller than a landscape phone,
     so Table Pace, Daily/Live Table, Sign In etc. fell off the bottom with
     no way to reach them. Cap it to the viewport and let it scroll - the
     other parlor games already do this (#menu{max-height:88vh}). */
  /* vh, NOT dvh: Android WebView resolves dvh to 0, which collapsed the
     menu to a thin bar in the app (2026-10-01). */
  #menu{max-height:calc(100vh - 72px); overflow-y:auto; overscroll-behavior:contain;}
  /* short landscape screens: lay the groups out side by side instead */
  @media (max-height:520px) and (orientation:landscape){
    #menu.open{top:58px; flex-flow:row wrap; align-items:flex-start; gap:.6rem 1.4rem;
      max-width:calc(100vw - 40px); max-height:calc(100vh - 66px); padding:.8rem 1rem;}
    #menu>div{min-width:200px;}
    #menu>.menudivider{display:none;}
    #menu>.menuitem{width:auto; min-width:130px;}
  }
  /* every menu option is its own full-width row with room to tap; the grouped
     Table Options / Bot Difficulty buttons stack instead of crowding a line */
  #menu>div{display:flex; flex-direction:column; align-items:stretch; gap:.5rem;}
  .menuitem{display:block; width:100%; background:none; border:none; padding:.35rem 0; text-align:left; cursor:pointer;
    font-family:var(--ui); font-weight:600; font-size:14.5px; color:var(--ivory); letter-spacing:.03em;}
  .menuitem:hover{color:var(--verm);}
  .menulabel{font-size:11.5px; letter-spacing:.05em; color:var(--jade-dim); margin-bottom:0;}
  .diffpills{display:flex; gap:6px;}
  .menurec{margin-top:.5rem; font-size:.78rem; opacity:.78; display:flex; flex-direction:column; gap:2px;}
  .menurec div{display:flex; align-items:baseline; gap:.45rem;}
  .menurec span{opacity:.8; min-width:4.6em;}
  .pill{font-family:var(--ui); font-weight:600; font-size:12px; color:var(--jade); background:rgba(255,255,255,.05);
    border:1px solid rgba(169,196,180,.28); border-radius:999px; padding:5px 11px; cursor:pointer;}
  .pill:hover{background:rgba(255,255,255,.1);}
  .pill.active{background:var(--verm); border-color:var(--verm); color:var(--ivory);}
  .menudivider{border:none; border-top:1px solid rgba(169,196,180,.16); margin:0; width:100%;}
  .ghostbtn{font-family:var(--ui); font-weight:600; font-size:12.5px; letter-spacing:.08em; color:var(--jade);
    background:rgba(255,255,255,.05); border:1px solid rgba(169,196,180,.28); border-radius:999px; padding:7px 14px; cursor:pointer;}
  .ghostbtn:hover{background:rgba(255,255,255,.1);}
  /* topbar sits on the white page: dark ink + visible border so New Game / menu read */
  #topbtns .ghostbtn{color:var(--felt-deep); background:rgba(18,53,40,.05); border-color:rgba(18,53,40,.34);}
  #topbtns .ghostbtn:hover{background:rgba(18,53,40,.12);}
  #topbtns .exitbtn{text-decoration:none; display:inline-flex; align-items:center;}
  .ghostbtn:focus-visible,button:focus-visible{outline:2px solid var(--gold); outline-offset:2px;}

  /* ---------- seats ---------- */
  .seat{display:flex; flex-direction:column; align-items:center; gap:8px; padding:12px;}
  #seat-north{grid-area:north; padding-top:18px;}
  #seat-west{grid-area:west; justify-content:center; align-items:flex-start;}
  #seat-east{grid-area:east; justify-content:center; align-items:flex-end;}
  /* ---------- seats sit on the FELT ELLIPSE, not on the stage box ----------
     The intent below was always "felt-relative", but the offsets resolved
     against each seat's GRID CELL, and the grid fills the whole stage while
     #feltoval is an ellipse inset inside it (width:80%, height:64%, centred
     at 50%/46%). So the north row landed ~90px ABOVE the felt — colliding
     with the header and the live-table banner — and the side columns landed
     out in the beige margin as free-floating stacks of card backs. Players
     were arranged around the stage's bounding box, not around the table.

     Making the three seats non-positioned hands their absolute children back
     to #table, which is inset:0 of #stage — the SAME box the oval's own
     percentages use. So these numbers are now genuinely felt-relative:

         centre (50%, 46%)   semi-axes a = 40%, b = 32%
         rim: top 14%   bottom 78%   left 10%   right 90%

     Plates ride just OUTSIDE the rim (that is the player, in their chair);
     card backs sit just INSIDE it (that is their hand, on the table). */
  #seat-north, #seat-west, #seat-east{position:static;}

  /* Anchored by the edge facing the table, so clearance does not depend on
     how long the name is ("Ray" cleared, "Fubar" sat on the rim).
     rim outer = ellipse + 16px;  margin = 16px rim + 14px gap = 1.875rem */
  #seat-north .plate{position:absolute; z-index:3; left:50%; top:14%;
    transform:translate(-50%,-100%); margin-top:-1.875rem;}
  #seat-west  .plate{position:absolute; z-index:3; left:10%; top:46%;
    transform:translate(-100%,-50%); margin-left:-1.875rem;}
  #seat-east  .plate{position:absolute; z-index:3; left:90%; top:46%;
    transform:translate(0,-50%); margin-left:1.875rem;}
  /* The side plates used to be text-only, from when they sat half on the rim
     and every pixel counted. They sit clear of the table now, so there is no
     reason north gets a suit and east/west do not. Every player carries the
     same label. (Leslie spotted the inconsistency, 2026-09-20.) */
  /* You joins the button row (Pass  Play  You  Hint) — flows inline, JS moves the node into #controls */
  body:not(.live) #seat-you{display:flex; align-items:center; padding:0;}
  body:not(.live) #seat-you .plate{position:static; transform:none;}
  body.live #seat-you{display:flex; align-items:center; padding:0;}
  body.live #seat-you .plate{position:static; transform:none;}

  /* ---------- your own avatar is NOT a control ----------
     It wore a pill background, border, 999px radius and an orange turn ring
     while sitting in the button row, so it read as a dead button. Strip the
     chrome; turn state moves onto the avatar and the name. */
  /* Your label is the SAME label as everyone else's - avatars.js hides the
     .dot and drops the avatar in its place, so the suit circle becomes your
     face and the spacing stays the game's own. What made it read as a dead
     button was never the pill; it was the hard 2px ring the turn state drew
     around it while it sat in a row of real buttons. That ring is gone from
     every plate now (see .seat.turn below), so nothing needs stripping here. */

  /* live: drop the top nameplate clear of the fixed #livebar ("your turn!") bar;
     solo keeps top:2% for cross-board consistency. still above the felt edge (~14%). */
  body.live #seat-north .plate{top:8%;}
  .plate{display:flex; align-items:center; gap:0.42rem; background:var(--label); border:1px solid rgba(18,53,40,.22);
    border-radius:999px; padding:0.3rem 0.7rem 0.3rem 0.44rem; transition:box-shadow .25s, border-color .25s;}
  .plate .dot{width:1.5rem; height:1.5rem; border-radius:50%; background:var(--label-deep); color:var(--ivory);
    display:grid; place-items:center; font-size:0.8rem;}
  .plate .pname{font-weight:800; font-size:0.82rem; color:var(--felt-deep); letter-spacing:.03em;}
  .plate .pcount{font-size:0.72rem; color:#2A5744; font-variant-numeric:tabular-nums; white-space:nowrap;}
  .plate .pname{white-space:nowrap;}
  /* GLOW, NOT A RING. A hard 0 0 0 Npx ring is what a focused button wears,
     and next to Pass/Play that is exactly how it read. The border already
     changes colour; the glow carries the urgency. (Note for whoever is next:
     an animation's box-shadow beats a normal declaration, so a ring left in
     these keyframes comes back even where a rule says box-shadow:none.) */
  .seat.turn .plate{border-color:var(--verm); box-shadow:0 0 16px rgba(224,80,46,.55); animation:turnpulse 1.3s ease-in-out infinite;}
  @keyframes turnpulse{0%,100%{box-shadow:0 0 12px rgba(240,85,43,.5);} 50%{box-shadow:0 0 28px rgba(240,85,43,.92);}}
  .seat.lastcard .plate{border-color:var(--gold); box-shadow:0 0 18px rgba(227,179,65,.5); animation:goldpulse 1.2s ease-in-out infinite;}
  @keyframes goldpulse{50%{box-shadow:0 0 30px rgba(227,179,65,.85);}}
  .plate .flag{font-size:10px; font-weight:800; letter-spacing:.12em; color:var(--felt-deep); background:var(--gold);
    padding:2px 7px; border-radius:999px; display:none;}
  .seat.lastcard .flag{display:inline-block;}
  .recline{margin:.55rem 0 .2rem; font-size:13px; color:#EDF8F1; letter-spacing:.02em; opacity:1 !important;}
  .recline b{color:var(--gold); font-weight:800;}
  .seat .said{min-height:16px; font-size:12px; color:var(--jade-dim); font-style:italic;}
  .backs{display:flex;}
  .cardback{width:1.75rem; height:2.5rem; border-radius:0.3125rem; margin-left:-1.125rem;
    background:linear-gradient(135deg, var(--verm) 0%, var(--verm-deep) 100%); border:0.125rem solid var(--ivory);
    box-shadow:0 0.125rem 0.3125rem rgba(0,0,0,.4); position:relative;}
  .cardback:first-child{margin-left:0;}
  .cardback:last-child::after{content:'B'; position:absolute; inset:0; display:grid; place-items:center;
    color:rgba(251,248,241,.75); font-size:0.75rem; font-weight:800; font-family:var(--disp);}
  /* side players sit sideways to us, so their cards are dealt landscape and fanned vertically */
  #seat-west .backs, #seat-east .backs{flex-direction:column;}
  /* tighter overlap: at -1.25rem thirteen backs built a 176px brick wall up
     the side of the felt. -1.45rem reads as a fanned hand held side-on. */
  #seat-west .cardback, #seat-east .cardback{width:2.5rem; height:1.75rem; margin-left:0; margin-top:-1.45rem;}
  #seat-west .cardback:first-child, #seat-east .cardback:first-child{margin-top:0;}
  /* pin each face-down hand just inside the felt rim in felt-relative % so it tracks the table at any screen size */
  #seat-north .backs{position:absolute; left:50%; top:22%; transform:translate(-50%,-50%);}
  #seat-west  .backs{position:absolute; left:18%;  top:46%;  transform:translate(-50%,-50%);}
  #seat-east  .backs{position:absolute; left:82%;  top:46%;  transform:translate(-50%,-50%);}

  /* ---------- center ---------- */
  #center{position:absolute; z-index:1; left:50%; top:45.5%; transform:translate(-50%,-50%);
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:0.3rem;}
  /* one message level for all table narration: a classy banner below the top cards, one at a time */
  #msg{position:absolute; z-index:6; left:50%; top:33%; transform:translate(-50%,-50%);
    text-align:center; pointer-events:none; max-width:min(56%, 30rem); line-height:1.35;
    font-family:var(--disp); font-size:15px; color:var(--ivory); letter-spacing:.02em;
    background:rgba(12,23,19,.76); border:1px solid rgba(251,248,241,.15);
    padding:7px 20px; border-radius:1.25rem; box-shadow:0 8px 22px rgba(0,0,0,.4);
    opacity:0; transition:opacity .3s ease;}
  #msg.show{opacity:1;}
  /* "Last played: X" — pinned on its own in the band between the north stack and the center card, not glued to the card column */
  #trickowner{position:absolute; left:50%; top:30%; transform:translate(-50%,-50%); z-index:1; width:max-content; font-size:14px; letter-spacing:.05em; color:#DEEBE2; min-height:16px; text-align:center;}
  #trickowner b{color:var(--gold);}
  #trickcards{display:flex; gap:6px; min-height:6.7rem; align-items:center;}
  #trickname{display:none; font-family:var(--disp); font-size:17px; color:var(--ivory); min-height:24px; text-align:center; text-wrap:balance;}
  #tablemsg{font-size:13px; color:var(--jade); min-height:18px; text-align:center; max-width:420px;}
  #tablemsg .accent{color:var(--gold); font-weight:800;}
  .passchips{display:flex; gap:6px; min-height:20px;}
  body:not(.live) #passchips{display:none;} /* passes now speak through the one banner, not center chips */
  .passchip{font-size:10.5px; font-weight:800; letter-spacing:.1em; color:var(--jade-dim);
    border:1px dashed rgba(169,196,180,.35); border-radius:999px; padding:2px 9px;}

  /* ---------- cards ---------- */
    /* THE PILE IS THE CENTRE OF THE TABLE (Leslie, 2026-09-21).
     Measured at 1249x831 before this change: felt centre y=385, but the pile
     sat at 396, under 55px of dead felt below the opponents' card backs and
     another 54px below the "Last played" line. Three small moves, not one:
       - the middle cards grow 3.5 -> 3.75rem wide (the hand stays 3.9rem, so
         it is still the larger of the two, which is the rule);
       - #trickowner rides up from 33% to 30%, tucking under the card backs
         instead of floating between them and the pile;
       - #center moves 49% -> 47.5%, which puts the CARDS' centre on the felt's
         centre rather than the column's box centre (the column carries the
         trick name and table message below the cards, so centring the box
         leaves the cards high).
     #trickcards also loses 0.5rem of min-height slack it was never using. */
  .card{width:4.6rem; height:6.6rem; border-radius:0.55rem; background:linear-gradient(160deg, var(--ivory) 0%, var(--ivory-shade) 100%);
    box-shadow:0 0.1875rem 0.5rem rgba(0,0,0,.45); position:relative; flex:none; font-family:var(--ui);}
  .card .corner{position:absolute; top:0.35rem; left:0.5rem; line-height:1; font-weight:800; font-size:1.05rem;}
  .card .corner small{display:block; font-size:0.9rem;}
  .card .pip{position:absolute; bottom:0.4rem; right:0.55rem; font-size:1.7rem;}
  .card.red{color:var(--suit-red);} .card.ink{color:var(--suit-ink);}
  .tcard{animation:land .3s ease-out;}
  @keyframes land{from{transform:translateY(-14px) scale(1.06); opacity:0;} to{transform:none; opacity:1;}}

  /* ---------- south / hand ---------- */
  #south{position:absolute; left:0; right:0; top:82.5%; display:flex; flex-direction:column; align-items:center; gap:0.5rem; padding:0.35rem 0.75rem 0; z-index:2;}
  /* #selinfo rides on the FELT now, in the gap between 'Last played' (30%) and
     the centre pile (47.5%) — near the action, not down by the buttons. Light
     text + shadow for the green. */
  #selinfo{position:absolute; left:50%; top:34%; transform:translate(-50%,-50%); z-index:2;
    width:max-content; max-width:90%; min-height:20px; font-size:14px; text-align:center;
    color:#DEEBE2; font-weight:600; text-shadow:0 1px 2px rgba(0,0,0,.35);}
  #selinfo .good{color:#8FE3B4; font-family:var(--disp); font-size:16px;}
  #selinfo .bad{color:#F2A98F; font-style:italic;}
  #hand{position:absolute; left:50%; top:62%; transform:translate(-50%,-50%); z-index:2; display:flex; justify-content:center; padding:0;}
  /* Hand cards are larger than the centre cards (Leslie), but the overlap has
     to leave the CORNER readable or the size gains nothing: at -1.95rem on a
     3.9rem card exactly half of every card was covered, so all you could see
     was the rank crushed against the next card's edge, and only the very last
     card showed its big pip — which read as a rendering fault. Leave 2.6rem
     of each card showing: rank AND suit clear, 13 cards still ~562px wide. */
  #hand .card{width:3.9rem; height:5.5rem; margin-left:-1.3rem; cursor:pointer; transition:transform .14s ease, box-shadow .14s ease; bottom:0;}
  /* the hand reads a step larger than the table (Leslie, 2026-09-20): these
     are the cards you have to actually read. The corner rank and pip grow
     with it - spade against club is the hard pair, and size fixes it. */
  #hand .card .corner{font-size:1.0625rem; top:0.375rem; left:0.5rem;}
  #hand .card .corner small{font-size:0.9375rem;}
  /* The big pip moves to the bottom-LEFT in the hand. Bottom-right put it in
     the strip the next card overlaps, so every card showed a sliced-off sliver
     of a suit and only the last card showed a whole one. On the left it is
     always fully visible, which also gives a second, large read of the suit —
     the spade/club problem is a size problem before it is a colour one. */
  #hand .card .pip{font-size:1.875rem; bottom:0.375rem; left:0.5rem; right:auto;}
  #hand .card:first-child{margin-left:0;}
  #hand .card:hover{transform:translateY(-8px);}
  #hand .card.sel{transform:translateY(-20px); box-shadow:0 0 0 2.5px var(--verm), 0 10px 18px rgba(0,0,0,.5);}
  #hand .card.dim{filter:brightness(.65) saturate(.7); cursor:default;}
  #hand .card.dim:hover{transform:none;}
  /* #149 drag-to-reorder: touch-action:none lets a finger drag a card instead of
     scrolling; .dragging lifts the card and follows the pointer. */
  #hand .card{touch-action:none;}
  #hand .card.dragging{transform:translateY(-0.75rem) scale(1.05); z-index:6; transition:none;
    box-shadow:0 0.6rem 1.2rem rgba(0,0,0,.5); cursor:grabbing;}
  /* Buttons: kept byte-for-byte in step with games/shared/suite.css, whose
     block carries the reasoning. Summary: the prediction side's rules from
     platform/www/css/core/app_core.css - .45rem rounded rectangle, a 1px
     border AT REST so the hover outline cannot shift the row, a shared
     min-width so the action row lines up, and the orange's 14px halo cut back
     to a short shadow. (Leslie, 2026-09-22.) If you change one file, change
     the other; this one wins on the Bonzai phone skin. */
  #controls{display:flex; gap:12px; align-items:center; justify-content:center;}
  .btn{font-family:var(--ui); font-weight:700; letter-spacing:.03em; font-size:0.86rem;
    display:inline-flex; align-items:center; justify-content:center;
    padding:0.55rem 1.15rem;
    border:1px solid transparent; border-radius:0.45rem; cursor:pointer;
    transition:background .18s ease, border-color .18s ease, box-shadow .18s ease, transform .1s ease;}
  #controls .btn{min-width:7.25rem; min-height:2.375rem;}
  .btn:active:not(:disabled){transform:scale(.98);}
  /* the selector list is specificity, not decoration - #playbtn (1,0,0) beats
     .btn:hover (0,3,0). See games/shared/suite.css for the whole note. */
  .btn:hover:not(:disabled),
  #controls .btn:hover:not(:disabled){border-color:var(--gold); box-shadow:0 0 0 0.125rem rgba(244,190,58,.26);}
  #playbtn{background:var(--verm); color:var(--ivory); border-color:rgba(0,0,0,.14);
    box-shadow:0 0.125rem 0.375rem rgba(195,58,28,.22);}
  #playbtn:hover:not(:disabled){background:#E8613F;}
  #passbtn{background:transparent; color:var(--felt-deep); border-color:rgba(18,53,40,.45);}
  #passbtn:hover:not(:disabled){background:rgba(18,53,40,.06);}
  .btn:disabled{opacity:.32; cursor:default; box-shadow:none;}
  #hintbtn{padding:0.6rem 0.95rem; color:var(--felt-deep);}

  /* ---------- toast + overlay ---------- */
  #toast{position:fixed; top:64px; left:50%; transform:translateX(-50%) translateY(-8px); z-index:60;
    background:var(--gold); color:var(--felt-deep); font-weight:800; letter-spacing:.06em; font-size:14px;
    padding:10px 22px; border-radius:999px; box-shadow:0 6px 18px rgba(0,0,0,.5); opacity:0; pointer-events:none;
    transition:opacity .25s, transform .25s;}
  #toast.err{background:var(--verm); color:var(--ivory); font-size:15px;
    border:2px solid var(--ivory); max-width:min(88vw, 620px); text-align:center;}
  #toast.show{opacity:1; transform:translateX(-50%) translateY(0);}
  #overlay{position:fixed; inset:0; background:rgba(9,15,12,.86); z-index:30; display:none; place-items:center;}
  #overlay.show{display:grid;}
  #panel{position:relative; box-sizing:border-box; background:linear-gradient(165deg, #23BE72 0%, #149A56 100%);
    border:1px solid rgba(255,255,255,.20); border-radius:18px; padding:24px 20px;
    max-width:440px; width:min(88vw,440px); max-height:84%; overflow-y:auto; text-align:center; box-shadow:0 22px 55px rgba(0,0,0,.5);}
  #panel h2{font-family:var(--disp); font-weight:800; color:var(--ivory); font-size:25px; margin:0 0 4px; text-wrap:balance;}
  #panel h2 .accent{color:var(--verm);}
  #panel p{font-size:13px; line-height:1.5; margin:8px 0; color:#E9F6EE;}
  #panel .standings{margin:12px 0; text-align:left; font-variant-numeric:tabular-nums; color:#E9F6EE;}
  #panel .standings div{display:flex; justify-content:space-between; gap:12px; padding:6px 2px; border-bottom:1px solid rgba(255,255,255,.18); font-size:13.5px;}
  #panel .standings b{color:var(--ivory);}
  #panel .rules{text-align:left; font-size:13.5px; line-height:1.6; color:var(--jade);}
  #panel .rules h3{font-family:var(--disp); color:var(--ivory); font-size:16px; margin:16px 0 4px;}
  #panel .rules .rsuits{color:var(--ivory); font-size:15px; letter-spacing:.05em;}
  /* ---------- live tables ---------- */
  /* 2-4 seat live tables reuse the solo grid seats (see liveRender), so the grid
     seats stay visible and the overlay is empty. Only a 5-8 seat ring table
     (body.ring) hides the grid seats and uses the #liveseats overlay. */
  body.live.ring #seat-north, body.live.ring #seat-west, body.live.ring #seat-east{visibility:hidden;}
  body.live .diffpills{opacity:.35; pointer-events:none;}
  #liveseats{position:fixed; inset:0; z-index:2; pointer-events:none; display:none;}
  body.live.ring #liveseats{display:block;}
  .liveseat{position:absolute; transform:translate(-50%,-50%); display:flex; flex-direction:column; align-items:center; gap:5px;}
  /* ring plates carry the suit too, matching the solo seats */
  .liveseat .backs{display:flex;}
  .liveseat .cardback{width:26px; height:37px; margin-left:-17px; border-width:1.5px;}
  .liveseat .cardback:first-child{margin-left:0;}
  .liveseat .cardback:last-child::after{font-size:11px;}
  #livebar{position:fixed; top:16px; left:50%; transform:translateX(-50%); z-index:26;
    display:none; align-items:center; gap:10px; background:var(--plate);
    border:1px solid rgba(169,196,180,.28); border-radius:999px; padding:6px 8px 6px 16px;}
  body.live #livebar{display:flex;}
  #livebar .codechip{display:none;}   /* invite code lives in the lobby, not the turn bar */
  #livebar .lstatus{font-size:15px; font-weight:800; color:var(--ivory); font-style:normal; letter-spacing:.01em;}
  #livebar .lstatus.myturn{color:var(--verm);}
  /* chat drawer */
  #chatbtn{position:fixed; right:20px; bottom:20px; z-index:45; display:none;}
  /* live: the Chat button rides in the button row next to Play, not the corner.
     Filled + a speech-bubble glyph so it reads as chat and stands out from the
     Pass/Play buttons instead of hiding as a faint ghost button. */
  body.live #chatbtn{display:inline-flex; align-items:center; gap:5px;
    position:static; right:auto; bottom:auto;
    background:var(--label); color:var(--felt-deep); border:1px solid var(--label-deep);
    font-weight:800; letter-spacing:.03em; padding:7px 15px;
    box-shadow:0 3px 10px rgba(0,0,0,.4), 0 0 0 2px rgba(166,219,188,.25);}
  body.live #chatbtn::before{content:'\1F4AC'; font-size:1rem; line-height:1; margin-right:1px;}
  body.live #chatbtn:hover{background:var(--label-deep); color:var(--ivory); border-color:var(--label-deep);}
  #chatdrawer{position:fixed; top:0; right:-320px; width:300px; height:100%; z-index:46;
    background:var(--plate); border-left:1px solid rgba(169,196,180,.25);
    display:flex; flex-direction:column; transition:right .25s ease; box-shadow:-12px 0 30px rgba(0,0,0,.4);}
  #chatdrawer.open{right:0;}
  #chatdrawer header{padding:14px 16px; font-family:var(--disp); font-weight:800; color:var(--ivory);
    border-bottom:1px solid rgba(169,196,180,.16); display:flex; justify-content:space-between; align-items:center;}
  #chatlog{flex:1; overflow-y:auto; padding:12px 16px; display:flex; flex-direction:column; gap:8px; font-size:13.5px;}
  #chatlog .cmsg b{color:var(--gold);}
  #chatlog .cmsg{color:var(--jade); line-height:1.45; word-break:break-word;}
  #chatform{display:flex; gap:8px; padding:12px; border-top:1px solid rgba(169,196,180,.16);}
  #chatform input{flex:1; background:rgba(255,255,255,.06); border:1px solid rgba(169,196,180,.3);
    border-radius:999px; padding:9px 14px; color:var(--ivory); font-family:var(--ui); font-size:13.5px;}
  #chatform input:focus{outline:2px solid var(--gold);}
  #chatbadge{background:var(--verm); color:var(--ivory); border-radius:999px; font-size:10.5px; font-weight:800;
    padding:1px 7px; margin-left:6px; display:none;}
  /* live modal forms */
  .lform{display:flex; flex-direction:column; gap:12px; text-align:left; margin:14px 0;}
  .lform label{font-size:12.5px; color:var(--jade-dim);}
  .lform input, .lform select{background:rgba(255,255,255,.06); border:1px solid rgba(169,196,180,.3);
    border-radius:10px; padding:10px 14px; color:var(--ivory); font-family:var(--ui); font-size:14.5px; width:100%; box-sizing:border-box;}
  .lform .lrow{display:flex; gap:10px; align-items:center;}
  /* modal sits on the bright-green panel — dark-panel-safe contrast, not the
     felt's muted jade (which vanished on the green). */
  .lform label{color:#08281c; font-weight:700;}
  /* dropdowns: a solid white control with dark text, and a white option list
     with dark text. The native list was white text on the white system menu —
     invisible when opened; these two rules fix both the closed value and the list. */
  .lform select{background:#ffffff; color:#08281c; font-weight:600;
    border-color:rgba(0,0,0,.28); -webkit-appearance:menulist; appearance:menulist;}
  .lform select option{background:#ffffff; color:#08281c;}
  .lobbylist{text-align:left; margin:14px 0; display:flex; flex-direction:column; gap:8px;}
  .lobbylist .lseat{display:flex; gap:10px; align-items:center; font-size:14.5px;}
  .lobbylist .lseat .dot{width:24px;height:24px;border-radius:50%;background:var(--felt-lip);display:grid;place-items:center;font-size:12px;color:var(--ivory);}

  /* ================= ANIMATIONS (v7) ================= */
  /* felt: slow light sheen sweeping the table */
  #feltoval::after{content:''; position:absolute; inset:0; border-radius:50%; pointer-events:none; z-index:0;
    background:linear-gradient(115deg, transparent 40%, rgba(255,255,255,.09) 50%, transparent 60%);
    background-size:220% 220%; animation:sheen 8s ease-in-out infinite;}
  @keyframes sheen{0%{background-position:145% 40%;} 55%,100%{background-position:-145% 60%;}}

  /* a played card flies in FROM the seat that played it */
  .toss-you  {animation:tossBottom .3s cubic-bezier(.2,.8,.3,1);}
  .toss-north{animation:tossTop    .3s cubic-bezier(.2,.8,.3,1);}
  .toss-west {animation:tossLeft   .3s cubic-bezier(.2,.8,.3,1);}
  .toss-east {animation:tossRight  .3s cubic-bezier(.2,.8,.3,1);}
  @keyframes tossBottom{from{transform:translateY(70px)  scale(.85); opacity:0;} to{transform:none; opacity:1;}}
  @keyframes tossTop   {from{transform:translateY(-70px) scale(.85); opacity:0;} to{transform:none; opacity:1;}}
  @keyframes tossLeft  {from{transform:translateX(-80px) scale(.85); opacity:0;} to{transform:none; opacity:1;}}
  @keyframes tossRight {from{transform:translateX(80px)  scale(.85); opacity:0;} to{transform:none; opacity:1;}}

  /* deal-in at the start of a hand (stagger set inline) */
  .card.deal{animation:dealin .36s ease-out backwards;}
  @keyframes dealin{from{transform:translateY(26px) rotate(-4deg); opacity:0;} to{transform:none; opacity:1;}}
  .cardback.deal{animation:flipin .42s ease-out backwards;}
  @keyframes flipin{from{transform:perspective(320px) rotateY(85deg) scale(.92); opacity:0;} to{transform:none; opacity:1;}}

  /* selected hand card: live glow */
  #hand .card.sel{animation:selglow 1s ease-in-out infinite alternate;}
  @keyframes selglow{from{box-shadow:0 0 0 2.5px var(--verm), 0 10px 18px rgba(0,0,0,.5);}
                     to  {box-shadow:0 0 0 2.5px var(--verm), 0 0 15px 3px rgba(240,85,43,.75), 0 10px 18px rgba(0,0,0,.5);}}

  /* buttons: press bounce. THE HOVER LIFT IS GONE ON PURPOSE - the hover
     answer is now the outline, and a button that both lifts AND outlines
     reads as two effects fighting. The press stays; it is the only motion. */
  .btn:active:not(:disabled){transform:scale(.96); transition:transform .06s;}

  /* table clears: label wipes in */
  .tableclear{display:inline-block; animation:clearwipe .45s ease-out;}
  @keyframes clearwipe{from{opacity:0; transform:scale(.7); letter-spacing:.45em;} to{opacity:1; transform:none; letter-spacing:normal;}}

  /* overlay panels pop in */
  #overlay.show #panel{animation:panelpop .3s cubic-bezier(.2,.9,.3,1.25);}
  #panel .btn{margin-top:6px;}
  @keyframes panelpop{from{transform:scale(.9); opacity:0;} to{transform:none; opacity:1;}}

  /* WIN: confetti burst inside the win panel */
  .winburst{position:absolute; left:0; right:0; top:0; height:100%; pointer-events:none; z-index:2; overflow:hidden;}
  .winburst i{position:absolute; top:12%; left:50%; width:9px; height:14px; border-radius:2px; opacity:0;
    animation:confetti 1.4s ease-out forwards;}
  .winburst i:nth-child(1){background:var(--gold); animation-delay:0s;   --dx:-115px; --rot:440deg;}
  .winburst i:nth-child(2){background:var(--verm); animation-delay:.06s; --dx:-65px;  --rot:-360deg;}
  .winburst i:nth-child(3){background:#3BB978;      animation-delay:.11s; --dx:-25px;  --rot:300deg;}
  .winburst i:nth-child(4){background:var(--gold); animation-delay:.03s; --dx:25px;   --rot:-280deg;}
  .winburst i:nth-child(5){background:var(--verm); animation-delay:.13s; --dx:65px;   --rot:380deg;}
  .winburst i:nth-child(6){background:#3BB978;      animation-delay:.08s; --dx:115px;  --rot:-440deg;}
  .winburst i:nth-child(7){background:var(--gold); animation-delay:.16s; --dx:-85px;  --rot:320deg;}
  .winburst i:nth-child(8){background:var(--verm); animation-delay:.1s;  --dx:85px;   --rot:-320deg;}
  @keyframes confetti{0%{opacity:1; transform:translate(-50%,0) rotate(0);}
                      100%{opacity:0; transform:translate(calc(-50% + var(--dx)), 250px) rotate(var(--rot));}}

  @media (prefers-reduced-motion: reduce){ *{animation:none !important; transition:none !important;} }
  @media (max-width:760px){
    #table{grid-template-columns:5.75rem minmax(0,1fr) 5.75rem;}
    .card{width:3.7rem; height:5.3rem;} .card .pip{font-size:1.5rem;} .card .corner{font-size:0.95rem;}
    #hand .card{margin-left:-1.5rem;}
    #brand h1{font-size:1.25rem;} #brand small{display:none;}
    /* phones: wider felt, no wood margin; re-pin the hands to the phone felt's rim */
    #feltoval{width:94%; height:64%;}
    /* Nobody fits BESIDE the felt at this width — a side plate anchored
       outside the rim lands at a negative x, off the screen. Leslie's rule
       still holds (players off the table), so the opponents line up ABOVE
       the felt: west top-left, north centred, east top-right. Their card
       backs stay on the felt where they belong. */
    #seat-west  .plate{left:0;    top:14%; transform:translate(0,-100%);     margin-left:0;}
    #seat-east  .plate{left:100%; top:14%; transform:translate(-100%,-100%); margin-left:0;}
    #seat-west .plate, #seat-east .plate, #seat-north .plate{margin-top:-2.1rem;}
    #hand .card{margin-left:-2.1rem;}
  }

  /* ============================================================
     Game replay (premium pilot) — chess-style step-through, all
     hands revealed. Scoped under #panel.rppanel + .rp-* so it never
     touches live play. ============================================================ */
  #panel.rppanel{ max-width:38rem; width:min(38rem,94vw); max-height:88vh; overflow:auto; text-align:center; }
  .rp-head{ display:flex; align-items:center; justify-content:space-between; gap:.5rem; margin-bottom:.3rem; }
  .rp-head h2{ margin:0; font-size:20px; }
  .rp-count{ font-size:12px; color:#E9F6EE; opacity:.85; font-variant-numeric:tabular-nums; white-space:nowrap; }
  .rp-play{ min-height:3.3rem; display:flex; align-items:center; justify-content:center; gap:.4rem; flex-wrap:wrap;
            padding:.4rem; border-top:1px solid rgba(255,255,255,.16); border-bottom:1px solid rgba(255,255,255,.16); }
  .rp-play .card{ width:2.2rem; height:3.1rem; margin-left:-.7rem; }
  .rp-play .card:first-child{ margin-left:0; }
  .rp-lead{ font-size:13px; color:#EDF8F1; }
  .rp-cap{ font-size:13px; color:#EDF8F1; min-height:1.2em; margin:.4rem 0 .2rem; text-align:center; line-height:1.4; }
  .rp-cap b{ color:var(--ivory); }
  .rp-cap .accent{ color:var(--verm); font-weight:800; }
  .rp-scrub{ width:100%; margin:.25rem 0; accent-color:var(--verm); cursor:pointer; }
  .rp-controls{ display:flex; align-items:center; justify-content:center; gap:.35rem; margin:.15rem 0 .4rem; }
  .rp-btn{ font-family:var(--ui); font-weight:800; font-size:15px; line-height:1; color:var(--ivory);
           background:rgba(0,0,0,.28); border:1px solid rgba(255,255,255,.28); border-radius:.4rem;
           padding:.4rem .7rem; cursor:pointer; transition:background .15s, border-color .15s; }
  .rp-btn:hover{ background:rgba(0,0,0,.44); border-color:var(--verm); }
  .rp-board{ display:flex; flex-direction:column; gap:.4rem; margin:.2rem 0 .3rem; }
  .rp-seat{ text-align:left; border:1px solid rgba(255,255,255,.14); border-radius:.5rem; padding:.35rem .5rem;
            background:rgba(0,0,0,.16); transition:background .15s, border-color .15s; }
  .rp-seat.turnnow{ border-color:var(--verm); box-shadow:0 0 0 1px var(--verm); }
  .rp-seat.moved{ background:rgba(240,85,43,.16); }
  .rp-splate{ display:flex; align-items:center; gap:.4rem; font-size:12.5px; color:var(--ivory); margin-bottom:.28rem; }
  .rp-splate .rp-dot{ font-size:13px; }
  .rp-splate .rp-name{ font-weight:800; }
  .rp-splate .rp-ct{ margin-left:auto; color:#E9F6EE; opacity:.82; font-variant-numeric:tabular-nums; }
  .rp-hand{ display:flex; flex-wrap:wrap; min-height:2.9rem; }
  .rp-hand .card{ width:2rem; height:2.9rem; border-radius:.3rem; margin-left:-1rem; box-shadow:0 2px 6px rgba(0,0,0,.4); }
  .rp-hand .card:first-child{ margin-left:0; }
  .rp-hand .card .corner{ top:.15rem; left:.22rem; font-size:.58rem; }
  .rp-hand .card .corner small{ font-size:.5rem; }
  .rp-hand .card .pip{ bottom:.15rem; right:.22rem; font-size:.75rem; }
  .rp-hand.empty{ align-items:center; }
  .rp-hand.empty:after{ content:'\2014 out \2014'; font-size:11px; color:var(--gold); opacity:.95; padding:.4rem 0; }
  .rp-foot{ display:flex; gap:.5rem; justify-content:center; margin-top:.5rem; flex-wrap:wrap; }

  /* ---- Start gate (task #140): the table waits for the player to Deal ---- */
  #startgate{position:absolute; left:50%; top:44%; transform:translate(-50%,-50%); z-index:6;
    display:flex; flex-direction:column; align-items:center; gap:0.55rem; text-align:center;}
  #startgate.hidden{display:none;}
  #startgate .sgbtn{font-family:var(--disp); font-weight:700; font-size:1.05rem; letter-spacing:.02em;
    color:var(--ivory); background:linear-gradient(160deg,var(--verm),var(--verm-deep));
    border:none; border-radius:999rem; padding:0.5rem 1.6rem; cursor:pointer;
    box-shadow:0 0.3rem 0.8rem rgba(0,0,0,.32), 0 0.15rem 0.45rem rgba(224,80,46,.32);}
  #startgate .sgbtn:hover{filter:brightness(1.07);}
  #startgate .sgmeta{font-size:0.82rem; color:var(--ivory); opacity:.9; line-height:1.5;}
