/* Shared table styling: the solo game and the online client both use this. */
:root{
  --felt:#12603a; --felt2:#08301d;
  --card:#fbfaf4; --ink:#191919; --red:#c1272d;
  --gold:#dcbb63; --line:rgba(255,255,255,.16);
  --cw:54px; --ch:76px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:radial-gradient(ellipse 120% 90% at 50% -10%,var(--felt) 0%,var(--felt2) 75%) fixed;
  color:#eef4ef;min-height:100vh;font-size:14px;
}
#app{max-width:1080px;margin:0 auto;padding:14px 16px 40px}

header{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 16px;
  border-bottom:1px solid var(--line);padding-bottom:10px;margin-bottom:14px}
h1{font-size:19px;margin:0;letter-spacing:.02em;font-weight:600}
h1 span{color:var(--gold)}
.contract{font-size:14px;color:var(--gold);font-weight:600}
.muted{color:#a9c0b2}
button{
  font:inherit;font-weight:550;padding:7px 13px;border-radius:7px;cursor:pointer;
  border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.09);color:#eef4ef;
}
button:hover:not(:disabled){background:rgba(255,255,255,.17)}
button:disabled{opacity:.32;cursor:default}
button.primary{background:var(--gold);color:#22180a;border-color:var(--gold)}
button.primary:hover:not(:disabled){background:#eccd77}
#board[hidden]{display:none}
.choose{display:flex;gap:8px;margin:16px 0 18px}
.choose button{flex:1}
.choose button.on{background:var(--gold);color:#22180a;border-color:var(--gold)}
#setup .modal{max-width:400px;text-align:center}
#setup .sub{margin-bottom:0}
.acts{display:flex;gap:8px;justify-content:center}
.acts button{min-width:132px}
.acts button[hidden]{display:none}

.panel{background:rgba(0,0,0,.2);border:1px solid var(--line);border-radius:10px;padding:11px 13px;margin-bottom:12px}
.panel h2{font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:#9fbcab;margin:0 0 9px}

/* cards */
.card{
  width:var(--cw);height:var(--ch);border-radius:6px;background:var(--card);color:var(--ink);
  border:1px solid #b9b4a4;box-shadow:0 1px 3px rgba(0,0,0,.4);
  display:flex;flex-direction:column;justify-content:space-between;padding:4px 5px;
  font-weight:650;line-height:1;user-select:none;flex:0 0 auto;position:relative;
}
.card .r{font-size:15px}
.card .s{font-size:15px;align-self:flex-end}
.card.red{color:var(--red)}
.card.joker{background:linear-gradient(150deg,#fff 40%,#ffe9b0);color:#8a5a00}
.card.joker .r{font-size:12px}
.card.sel{outline:2px solid var(--gold);transform:translateY(-9px);box-shadow:0 6px 12px rgba(0,0,0,.5)}
.card.click{cursor:pointer}
.card.click:hover{transform:translateY(-4px)}
.card.sel.click:hover{transform:translateY(-11px)}
.card.small{--cw:40px;--ch:56px;width:40px;height:56px;padding:3px 4px;border-radius:5px}
.card.small .r{font-size:11px}.card.small .s{font-size:11px}
.card.small.joker .r{font-size:8px}
.back{
  width:var(--cw);height:var(--ch);border-radius:6px;flex:0 0 auto;
  background:repeating-linear-gradient(45deg,#7d1c22 0 5px,#611519 5px 10px);
  border:1px solid #3d0e11;box-shadow:0 1px 3px rgba(0,0,0,.4);
}
.back.small{width:40px;height:56px}
.cards{display:flex;gap:5px;flex-wrap:wrap}

/* melds */
.meld{display:flex;gap:3px;background:rgba(255,255,255,.05);border:1px solid var(--line);
  border-radius:8px;padding:6px;align-items:center}
.meld.target{cursor:pointer;border-color:var(--gold);background:rgba(220,187,99,.14)}
.meld.target:hover{background:rgba(220,187,99,.3)}
.meld.frozen{opacity:.5;border-style:dashed}
.meld.unstage{cursor:pointer}
.meld.unstage:hover{background:rgba(255,255,255,.13);border-color:rgba(255,255,255,.35)}
/* The table is a row per player rather than one wrapping flow of melds. The
   name reads up the left edge once, instead of being repeated on every meld —
   clearer about who owns what, and it hands the width back to the cards. */
#table{display:flex;flex-direction:column;gap:9px;min-height:30px}
.prow{display:flex;align-items:stretch;gap:6px;min-width:0}
.prow > .owner{font-size:10px;color:#9fbcab;writing-mode:vertical-rl;transform:rotate(180deg);
  letter-spacing:.05em;flex:0 0 auto;text-align:center;overflow:hidden}
/* a player with more melds than fit simply wraps onto a second line of their row */
.prow .melds{display:flex;flex-wrap:wrap;gap:9px;flex:1 1 0;min-width:0;
  align-items:flex-start;align-content:flex-start}

/* first-run nudge and the sign-up prompts */
.newHere{margin:10px 0 2px;font-size:13px;color:#cfe3d8;
  background:rgba(220,187,99,.12);border:1px solid rgba(220,187,99,.35);
  border-radius:8px;padding:8px 10px}
.newHere b{display:block;margin-bottom:2px}
.nudge{font-size:12px;color:#9fbcab;margin:-4px 0 8px;line-height:1.45;text-align:left}
/* after a game that went unranked, so it should read as a consequence, not decoration */
.nudge.missed{margin:10px 0 0;padding:9px 11px;border-radius:8px;text-align:center;
  background:rgba(220,187,99,.1);border:1px solid rgba(220,187,99,.3);color:#cfe3d8}

/* accounts and the leaderboard */
.acctStrip{margin-top:14px;font-size:12.5px;color:#9fbcab}
.keyBox{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;word-break:break-all;
  background:rgba(0,0,0,.3);border:1px solid var(--line);border-radius:8px;padding:10px 12px;
  margin:4px 0 12px;user-select:all;text-align:left}
.recordCard{background:rgba(255,255,255,.05);border:1px solid var(--line);border-radius:10px;
  padding:12px;margin-bottom:12px}
.recordName{font-size:18px;font-weight:700;margin-bottom:10px}
.recordGrid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.recordGrid div{display:flex;flex-direction:column;gap:2px}
.recordGrid b{font-size:16px}
.recordGrid span{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:#9fbcab}
.lbHead{font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:#9fbcab;
  margin:0 0 6px;text-align:left}
.lbRow{display:flex;align-items:baseline;gap:8px;padding:5px 7px;border-radius:6px;text-align:left}
.lbRow:nth-child(odd){background:rgba(255,255,255,.04)}
/* your own line, so you can find yourself without reading every row */
.lbRow.lbMe{background:rgba(220,187,99,.16);box-shadow:inset 0 0 0 1px rgba(220,187,99,.4)}
.lbPos{width:1.6em;color:#9fbcab;font-size:12px;flex:0 0 auto}
.lbName{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.lbVal{flex:0 0 auto;font-variant-numeric:tabular-nums;font-size:13px}

/* seats */
#seats{display:flex;gap:10px;flex-wrap:wrap}
.seat{flex:1 1 150px;border:1px solid var(--line);border-radius:9px;padding:8px 10px;background:rgba(0,0,0,.16)}
.seat.active{border-color:var(--gold);background:rgba(220,187,99,.11)}
.seat .nm{font-weight:650;display:flex;justify-content:space-between;gap:8px;align-items:baseline}
.seat .st{font-size:11.5px;color:#9fbcab;margin-top:3px}
.chip{font-size:10px;background:var(--gold);color:#22180a;border-radius:4px;padding:1px 5px;font-weight:700}

/* centre */
#center{display:flex;gap:26px;align-items:flex-end;justify-content:center;padding:4px 0 2px}
.pile{text-align:center}
.pile .lbl{font-size:10.5px;color:#9fbcab;margin-top:5px;letter-spacing:.05em}
.empty{width:var(--cw);height:var(--ch);border:1px dashed rgba(255,255,255,.28);border-radius:6px}

#hand{min-height:var(--ch)}
#actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:11px}
#hint{font-size:12.5px;color:var(--gold);min-height:17px;margin-top:8px}

#log{height:104px;overflow-y:auto;font-size:12.5px;line-height:1.55;color:#bcd2c4}
#log div{padding:1px 0;border-bottom:1px solid rgba(255,255,255,.05)}
#log b{color:#eef4ef;font-weight:600}

.overlay{position:fixed;inset:0;background:rgba(0,0,0,.72);display:flex;align-items:center;
  justify-content:center;padding:20px;z-index:20}
.modal{background:#10331f;border:1px solid var(--gold);border-radius:12px;padding:22px 26px;
  max-width:580px;width:100%;box-shadow:0 18px 50px rgba(0,0,0,.6)}
.modal h2{font-size:18px;margin:0 0 4px;color:var(--gold);text-transform:none;letter-spacing:0}
.modal .sub{font-size:12.5px;color:#9fbcab;margin-bottom:14px}
.scroll{overflow-x:auto;margin-bottom:16px}
table{width:100%;border-collapse:collapse;font-size:13.5px;margin-bottom:16px}
.scroll table{margin-bottom:0}
th,td{text-align:left;padding:5px 7px;border-bottom:1px solid var(--line);white-space:nowrap}
th{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:#9fbcab;font-weight:600}
th.n,td.n{text-align:right;font-variant-numeric:tabular-nums}
td .ct{color:#7f9c8b;font-size:11.5px}
tr.hl td{background:rgba(220,187,99,.13)}
tr.tot td{border-top:2px solid var(--gold);border-bottom:none;padding-top:8px;font-weight:700}
td.best{color:var(--gold)}

details{margin-top:14px;font-size:12.5px;color:#bcd2c4}
summary{cursor:pointer;color:#9fbcab;font-size:11px;text-transform:uppercase;letter-spacing:.09em}
details ul{margin:9px 0 0;padding-left:18px;line-height:1.65}
details table{margin:10px 0 4px}

/* header controls and the solo/online split on the setup card */
.topbar{margin-left:auto;display:flex;gap:8px;align-items:center}
#gameBtns{display:flex;gap:8px}
#gameBtns[hidden]{display:none}
button.wide{width:100%;padding:10px 13px}
.orbar{display:flex;align-items:center;gap:10px;margin:16px 0 12px;color:#7f9c8b;font-size:11px;
  text-transform:uppercase;letter-spacing:.12em}
.orbar::before,.orbar::after{content:"";flex:1;height:1px;background:var(--line)}
.modal .rules ul{margin:10px 0 0;padding-left:18px;line-height:1.65;color:#bcd2c4;font-size:12.5px}
.modal .rules table{margin-bottom:4px}

/* The card you just picked up. A sort drops it anywhere in the hand, so it gets
   a moment of glow that settles into a quiet ring for the rest of your turn. */
@keyframes freshpulse{
  0%   { box-shadow:0 0 0 3px rgba(220,187,99,.95), 0 0 22px rgba(220,187,99,.65); }
  100% { box-shadow:0 0 0 2px rgba(220,187,99,.6),  0 2px 8px rgba(0,0,0,.4); }
}
.card.fresh{ animation:freshpulse 1.1s ease-out forwards; }
@media (prefers-reduced-motion:reduce){
  .card.fresh{ animation:none; box-shadow:0 0 0 2px rgba(220,187,99,.6); }
}

/* long-form help panels (how to play / house rules) */
.modal .rules{max-height:66vh;overflow-y:auto;padding-right:4px}
.modal .rules p.lead{color:#cfe0d5;font-size:13px;line-height:1.6;margin:0 0 4px}
.modal .rules h3{font-size:11px;text-transform:uppercase;letter-spacing:.09em;
  color:var(--gold);margin:16px 0 6px;font-weight:600}
.modal .rules ol,.modal .rules ul{margin:6px 0 0;padding-left:20px;line-height:1.65;
  color:#bcd2c4;font-size:12.5px}
.modal .rules li{margin-bottom:5px}
.modal .rules li b{color:#eef4ef}

/* open-table browser */
.tableRow{display:flex;align-items:center;justify-content:space-between;gap:10px;
  border:1px solid var(--line);border-radius:9px;padding:9px 12px;margin-bottom:8px;text-align:left}
.tableRow button{flex:0 0 auto}
.lbl2{font-size:10.5px;text-transform:uppercase;letter-spacing:.1em;color:#7f9c8b;
  margin:14px 0 -6px;text-align:left}

/* a meld whose joker the selected card can buy back */
.meld.swappable{cursor:pointer;border-style:dashed;border-color:#7fd6a6;
  background:rgba(127,214,166,.13)}
.meld.swappable:hover{background:rgba(127,214,166,.26)}

/* mid joker-swap: the source meld previews the exchange, and the joker itself
   rides in your hand until you place it */
.meld.swapping{border-style:dashed;border-color:#7fd6a6;background:rgba(127,214,166,.13)}
.card.carrying{outline:2px solid #7fd6a6;box-shadow:0 0 16px rgba(127,214,166,.55);
  transform:translateY(-6px)}

/* ---------------------------------------------------------------- phones */
/* One screenful, no scrolling. The big savings are the six panels' worth of
   chrome, a single-row seat strip, a much shorter log, and stacked melds. */
@media (max-width: 700px){
  :root{ --cw:46px; --ch:64px; }
  #app{ padding:8px 10px 16px; }

  header{ padding-bottom:7px; margin-bottom:8px; gap:4px 10px; }
  h1{ font-size:16px; }
  /* round info sits beside the title; it shrinks with an ellipsis rather than
     pushing the line, and the buttons take the row underneath. */
  /* flex-basis 0 is the point: with `auto` the text's own width can push the
     line over and wrap it away from the title. At 0 it never causes a wrap —
     it just takes what's left and ellipsises if the round name is long. */
  .contract{ font-size:11px; flex:1 1 0; min-width:0;
             overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .topbar{ gap:6px; order:3; width:100%; margin-left:0; }
  .topbar button{ padding:5px 9px; font-size:12px; }

  /* Panel chrome is charged six times over, so a couple of pixels each is worth
     ~45px of table — the difference between seeing two rows of melds and one. */
  .panel{ padding:5px 9px; margin-bottom:5px; }
  .panel h2{ font-size:9.5px; margin:0 0 3px; }

  /* seats: four must fit across without scrolling, since a strip you have to
     discover you can swipe is worse than no strip at all. Five still scrolls. */
  #seats{ flex-wrap:nowrap; overflow-x:auto; gap:4px; scrollbar-width:none; }
  #seats::-webkit-scrollbar{ display:none; }
  .seat{ flex:1 1 0; min-width:0; padding:4px 5px; }
  .seat .nm{ font-size:11px; gap:3px; }
  .seat .nm > span:first-child{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .seat .st{ font-size:9px; margin-top:1px; white-space:nowrap; }
  .seat .muted{ font-size:9.5px; }
  /* "DOWN" is 30px of a 84px seat and got ellipsised to "DO…". An arrow says the
     same thing in 9px, and the how-to explains it. */
  .seat .chip{ font-size:0; line-height:0; padding:1px 3px; display:inline-block;
               vertical-align:middle; }
  .seat .chip::after{ content:"\2193"; font-size:9.5px; line-height:1.3;
                      font-weight:700; display:inline-block; }

  /* Melds show every card whole — overlapping them into slivers saved width but
     made a nearly empty table in the early rounds look like a filing cabinet.
     The room now comes from the cards being small rather than half-hidden. */
  .meld{ padding:2px; gap:0; }
  /* one label per row instead of one per meld, so it can afford to be readable */
  .prow > .owner{ font-size:9px; }
  .meld .card.small{ width:30px; height:40px; padding:2px; border-radius:4px; }
  .meld .card.small .r{ font-size:9.5px; }
  .meld .card.small .s{ font-size:9px; }
  /* A meld only stacks once lay-offs have grown it. Three cards — the size a
     contract meld is laid at — stay whole, which is the common case and the one
     that has to look right; past that the cards slide under each other so the
     player's row still fits on one line. A covered card only has to show its
     rank, and 14px is enough for the widest one at this size. */
  .meld .card.small:first-child:nth-last-child(n+4) ~ .card.small{
    margin-left:-16px; box-shadow:-2px 0 4px rgba(0,0,0,.5); }
  .meld .card.small:first-child:nth-last-child(n+4) .r,
  .meld .card.small:first-child:nth-last-child(n+4) ~ .card.small .r{
    font-size:8.5px; margin-left:-1px; }

  /* "JOKER" is unreadable mush in 26px of card; the star isn't. */
  .meld .card.small.joker .r{ font-size:0; }
  .meld .card.small.joker .r::after{ content:"★"; font-size:11px; }
  #table{ gap:3px; overflow-y:auto; height:100%; }
  .prow{ gap:3px; }
  .prow .melds{ gap:2px; }

  /* Lay the board out as a column that fills the viewport, and let the table —
     the one panel whose size depends on how the game is going — absorb whatever
     is left over and scroll inside, so the page itself doesn't have to.
     #app keeps a definite height so the table can *shrink* to soak up a deficit,
     not just grow into a surplus — that keeps your hand on screen. Once the table
     hits its floor the surplus overflows and the page scrolls, which is the right
     order: reference information gets squeezed before anything you touch. */
  html, body{ height:100%; }
  #app{ min-height:100%; height:100%; display:flex; flex-direction:column; }
  #board{ flex:1 1 auto; display:flex; flex-direction:column; min-height:0; }
  #board > .panel{ flex:0 0 auto; }
  /* must out-specify `#board > .panel` above, hence the descendant id */
  /* The table takes whatever height is spare, so it scrolls only when the melds
     genuinely can't fit. `align-content:flex-start` (set on #table above) is what
     keeps the melds their own size instead of stretching to fill it. */
  #board > #tablePanel{ flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
  /* The floor. Being the only panel that flexes, the table also absorbs every
     *deficit* — open the set-aside panel on a short screen and it was squeezed to
     8px, slicing a row of cards in half, which reads as a rendering fault rather
     than as "scroll me". Two whole rows is the floor; past that the page scrolls,
     which at least looks like what it is. */
  #tablePanel #table{ flex:1 1 auto; min-height:95px; overflow-y:auto; }

  /* the hand is what you touch, so it gets the room it needs to stay 2 rows */
  #hand .card{ width:46px; height:64px; }
  /* "JOKER" is 36px of type in a 28px space at the full size, so it spilled off
     the card. Shrunk to fit rather than clipped. */
  .card.joker .r{ font-size:8.5px; letter-spacing:-.2px; }

  #center{ gap:16px; padding:0; }
  /* exactly the hand's size — a 2px difference reads as "wrong" without
     looking obviously wrong */
  #center .card, #center .back, #center .empty{ width:46px; height:64px; }
  .pile .lbl{ font-size:9px; margin-top:2px; letter-spacing:.03em; }

  .cards{ gap:4px; }
  #actions{ gap:6px; margin-top:6px; }
  #actions button{ padding:6px 10px; font-size:12.5px; }
  #hint{ font-size:11.5px; margin-top:4px; }

  /* Exactly four lines, fixed. Each entry is one line box plus its padding and
     rule, so the height is derived from those rather than guessed. */
  #board > #logPanel{ flex:0 0 auto; }
  #board > #logPanel #log{ flex:none; font-size:10.5px; line-height:1.4;
                           height:calc((10.5px * 1.4 + 3px) * 4); }

  .modal{ padding:16px 18px; }
  .modal .rules{ max-height:60vh; }
}

/* Narrower phones (iPhone SE 2/3, mini). At 375px a 46px card only fits six to a
   row, so a 13-card hand needs three rows and overflows a short screen. 40px
   restores seven per row and two rows. */
@media (max-width: 389px){
  #hand .card{ width:40px; height:56px; }
  #center .card, #center .back, #center .empty{ width:40px; height:56px; }
}

/* Small phones (SE-sized). The hand is the biggest consumer: dropping the card
   a few pixels takes it from three rows to two, which is the whole difference. */
@media (max-width: 360px){
  :root{ --cw:40px; --ch:56px; }
  /* 36px keeps a 13-card hand at two rows here; 40 tipped it to three and pushed
     the page over. Centre matches so the piles and your hand stay one size. */
  #hand .card{ width:36px; height:50px; }
  #center .card, #center .back, #center .empty{ width:36px; height:50px; }
  #board > #tablePanel{ min-height:0; }
  .seat .nm{ font-size:10px; }
  #app{ padding:6px 8px 12px; }
  /* keep the round on the title line here too */
  h1{ font-size:14px; }
  .contract{ font-size:10px; }
  .card.joker .r{ font-size:7.5px; }
}
