/* Chinese quiet luxury skin (Jason 18391, 18393, 18394, 13 Nov 2026): ink-wash dark ground, rice-paper ink, antique gold,
   celadon hairlines, one vermilion seal (dealer mark, Win). Song-style serif headings. Layout rules unchanged from mj-v19. */
:root {
  --bg: #181d1b; --bg2: #131715; --panel: rgba(236, 228, 210, 0.04); --panel2: rgba(0, 0, 0, 0.26);
  --ink: #ece4d2; --ink2: rgba(236, 228, 210, 0.6); --line: rgba(170, 190, 178, 0.18); --line2: rgba(170, 190, 178, 0.34);
  --brass: #b9985c; --brass2: #dcc48e; --brass-dim: rgba(185, 152, 92, 0.38); --cream: #f1ebdd; --dark: #17150f;
  --vermilion: #a83a2a; --celadon: #9fb8a8;
  --felt: var(--bg); --felt2: var(--bg2); --accent: var(--brass);
  --tile-w: min(50px, calc((100vw - 80px) / 17.6)); --tile-h: calc(var(--tile-w) * 1.387); --small-w: min(32px, calc(100vw / 38)); --small-h: calc(var(--small-w) * 1.387);
  --sans: -apple-system, "SF Pro Text", "Helvetica Neue", "PingFang TC", "Heiti TC", "Noto Sans CJK TC", sans-serif;
  --serif: var(--sans); /* one family throughout (Jason 18399, 13 Nov 2026: too many fonts; unify on the cleanest). Hierarchy comes from size, weight and spacing. */
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--ink); font-family: var(--sans); font-size: 22px; line-height: 1.35; overscroll-behavior: none; -webkit-user-select: none; user-select: none; -webkit-font-smoothing: antialiased; }
body { background: radial-gradient(ellipse at 50% 28%, #222926 0%, var(--bg) 60%, #101412 100%); background-attachment: fixed; }
.hidden { display: none !important; }
.screen { min-height: 100%; padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
h1, h2, h3 { font-family: var(--serif); font-weight: 500; letter-spacing: 0.01em; }
#setup h1::before { content: ''; display: inline-block; width: 0.42em; height: 0.42em; background: var(--vermilion); box-shadow: inset 0 0 0 1.5px rgba(241, 235, 221, 0.55), inset 0 0 0 3px var(--vermilion); margin-right: 0.35em; vertical-align: 0.08em; border-radius: 1px; }
small { font-size: 0.6em; opacity: 0.7; font-weight: 400; }
button { font: inherit; color: var(--ink); background: var(--panel); border: 1px solid var(--line2); border-radius: 6px; padding: 10px 20px; cursor: pointer; transition: background 0.15s, border-color 0.15s, transform 0.1s; }
button:active { transform: scale(0.98); background: rgba(255, 255, 255, 0.09); }
button.big { font-size: 26px; padding: 15px 30px; min-width: 180px; }
button.primary { background: var(--brass); border-color: var(--brass); color: var(--dark); font-weight: 500; }
button.primary small { opacity: 0.6; }
button.small { font-size: 17px; padding: 6px 14px; letter-spacing: 0.02em; }
button small { display: block; }
button:disabled { opacity: 0.4; cursor: default; }
input, select { font: inherit; }
/* setup */
/* setup fits one iPad screen (Jason 18401, 13 Nov 2026): compact rows, no light input boxes; inputs are hairline underlines on the dark ground */
#setup { padding: calc(18px + env(safe-area-inset-top)) calc(28px + env(safe-area-inset-right)) calc(18px + env(safe-area-inset-bottom)) calc(28px + env(safe-area-inset-left)); max-width: 1100px; margin: 0 auto; display: flex; flex-direction: column; gap: 12px; min-height: 100dvh; justify-content: center; }
#setup h1 { margin: 0; font-size: 34px; }
.hint { margin: 0; color: var(--ink2); font-size: 17px; } .hint span { display: block; font-size: 15px; opacity: 0.8; }
.seats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 0; }
.seat { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px 8px; text-align: center; }
.seat .wind { font-size: 13px; color: var(--celadon); letter-spacing: 0.1em; text-transform: uppercase; }
.seat .avatar { width: 68px; height: 68px; border-radius: 50%; background: var(--bg2); margin: 6px auto; overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: 28px; border: 1px solid var(--brass-dim); box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--line); }
.seat .avatar img { width: 100%; height: 100%; object-fit: cover; }
.seat input[type=text] { width: 100%; font: inherit; font-size: 20px; padding: 4px 6px; border: 0; border-bottom: 1px solid var(--line2); border-radius: 0; background: transparent; color: var(--ink); text-align: center; outline: none; }
.seat input[type=text]:focus { border-bottom-color: var(--brass); }
.seat .photorow { display: flex; gap: 6px; justify-content: center; align-items: start; margin-top: 6px; } .seat .photorow > * { height: 23px; line-height: 17px; box-sizing: border-box; }
.seat label.photo { display: inline-block; margin-top: 0; font-size: 14px; background: transparent; border: 1px solid var(--line); border-radius: 6px; padding: 2px 10px; color: var(--ink2); }
.seat label.photo input { display: none; }
.seat button.unphoto { margin: 0; font-size: 14px; padding: 2px 10px; border: 1px solid var(--line); border-radius: 6px; color: var(--ink2); background: transparent; }
.seat .kind { font-size: 16px; opacity: 0.8; margin-top: 6px; }
.options { display: flex; flex-wrap: wrap; gap: 14px 22px; align-items: center; margin: 0; font-size: 18px; color: var(--ink2); }
.options input[type=number] { width: 84px; font: inherit; font-size: 20px; padding: 3px 6px; border: 0; border-bottom: 1px solid var(--line2); border-radius: 0; background: transparent; color: var(--ink); outline: none; text-align: center; }
.options input[type=number]:focus { border-bottom-color: var(--brass); }
.options input[type=checkbox] { width: 24px; height: 24px; vertical-align: middle; accent-color: var(--brass); }
.row { display: flex; gap: 16px; flex-wrap: wrap; }
/* table */
#table { display: flex; flex-direction: column; height: 100vh; height: 100dvh; padding: calc(6px + env(safe-area-inset-top)) calc(6px + env(safe-area-inset-right)) calc(6px + env(safe-area-inset-bottom)) calc(6px + env(safe-area-inset-left)); gap: 4px; } /* the screen's own padding was overridden here, so the top row sat under the iPad status bar (Jason 18408) */
/* opponents (Jason 18409): one row of tile backs each; the top opponent centred between the info and the buttons */
.top { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: start; gap: 10px; min-height: 120px; max-height: 24vh; flex: none; overflow: hidden; }
.topbtns { display: flex; gap: 6px; justify-self: end; flex-wrap: wrap; justify-content: flex-end; }
.topbtns button.small { font-size: 15px; padding: 5px 10px; }
.opp-top { justify-self: center; width: min(560px, 42vw); align-items: center; } /* a fixed width: in an auto track 100% followed the content and the discards wrapped early (14 Nov) */
.opp-top .tiles, .opp-top .melds { justify-content: center; } .opp-top .discards { justify-content: center; width: 100%; } /* full width, else auto-fill gives one column (seen 14 Nov) */
.opp > .tiles { flex-wrap: nowrap; }
.opp > .tiles .tile { flex: 1 1 0; min-width: 0; width: auto; max-width: var(--small-w); height: auto; aspect-ratio: 240 / 336; }
.middle { flex: 1; display: flex; gap: 8px; min-height: 0; overflow: hidden; }
.bottom { flex: none; }
#table.dense { --small-w: 26px; --small-h: 36px; }
/* whole-pixel tile widths (Jason 18457, 14 Nov 2026): the top row's backs were flex-squeezed to 27.3 px and every edge fell between pixels; the side columns at a whole 32 px were crisp */
@supports (width: round(down, 10px, 1px)) {
  :root { --small-w: round(down, min(32px, calc(100vw / 38)), 1px); --tile-w: round(down, min(50px, calc((100vw - 80px) / 17.6)), 1px); }
  .opp > .tiles:not(.vert) { width: 100%; }
  .opp > .tiles:not(.vert) .tile { flex: none; width: min(var(--small-w), round(down, calc((100% - (var(--n) - 1) * 2px) / var(--n)), 1px)); }
  :root { --small-h: round(down, calc(var(--small-w) * 1.387), 1px); } /* whole-pixel heights too (Jason 18482, 14 Nov 2026): the top row's faces turn a half circle about the tile's centre, and at 44.38 px tall that centre sat between pixels, so every face was resampled soft */
  .opp-top { width: round(down, min(560px, 42vw), 1px); }
}
.opp-top .discards { max-height: calc(var(--small-h) * 2 + 4px); overflow: hidden; }
.me .discards { max-height: calc(var(--small-h) * 2 + 4px); overflow: hidden; flex: 1; }
.opp { overflow: hidden; }
.last .claim { font-size: 28px; font-family: var(--serif); color: var(--brass2); }
.meld.newmeld .tile { outline: 2px solid var(--brass); outline-offset: 1px; border-radius: 4px; }
.info { font-size: 17px; line-height: 1.4; min-width: 150px; color: var(--celadon); }
.info b { color: var(--ink); font-weight: 500; }
.opp { background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.opp-left, .opp-right { width: clamp(250px, 24vw, 310px); flex: none; } /* narrower again (Jason 18449): the height is what the side players need */ /* widened from 290 (Jason 18437, 14 Nov 2026): the centre needs little, the side players' discards need the room */
.who { display: flex; align-items: center; gap: 8px; font-size: 18px; }
.who .av { width: 40px; height: 40px; border-radius: 50%; background: var(--bg2); overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: 20px; font-family: var(--serif); border: 1px solid var(--line2); flex: none; }
.who .av img { width: 100%; height: 100%; object-fit: cover; }
.who.turn .av { border-color: var(--brass); box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--brass); }
/* whose turn (Jason 18449, 18453, 14 Nov 2026): the thinking player's whole panel glows and pulses in their seat colour; the band thickens too */
.opp.turn { animation: oppglow 1.2s ease-in-out infinite alternate; border-color: var(--seat); }
.me.turn { animation: meglow 1.2s ease-in-out infinite alternate; }
@keyframes oppglow {
  from { background-color: color-mix(in srgb, var(--seat) 7%, transparent); box-shadow: inset 0 3px 0 var(--seat), 0 0 0 1px var(--seat), 0 0 12px 0 color-mix(in srgb, var(--seat) 35%, transparent); } /* no scale in the pulse (14 Nov 2026): a panel growing 1.2% resamples every face in it, soft, for as long as that player thinks */
  to { background-color: color-mix(in srgb, var(--seat) 18%, transparent); box-shadow: inset 0 3px 0 var(--seat), 0 0 0 2px var(--seat), 0 0 34px 8px color-mix(in srgb, var(--seat) 75%, transparent); }
}
@keyframes meglow {
  from { background-color: color-mix(in srgb, var(--seat) 7%, transparent); box-shadow: inset 4px 0 0 var(--seat), 0 0 0 1px var(--seat), 0 0 12px 0 color-mix(in srgb, var(--seat) 35%, transparent); }
  to { background-color: color-mix(in srgb, var(--seat) 18%, transparent); box-shadow: inset 4px 0 0 var(--seat), 0 0 0 2px var(--seat), 0 0 34px 8px color-mix(in srgb, var(--seat) 75%, transparent); }
}
.discards .tile.newest { outline: 2px solid var(--brass); outline-offset: 1px; border-radius: 4px; box-shadow: 0 0 12px 2px rgba(199, 168, 108, 0.45); }
.last .av { width: 64px; height: 64px; border-radius: 50%; background: var(--bg2); overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: 28px; font-family: var(--serif); border: 1px solid var(--brass); flex: none; }
.last .av img { width: 100%; height: 100%; object-fit: cover; }
.last .lname { font-size: 24px; font-family: var(--serif); display: flex; flex-direction: column; line-height: 1.15; }
.last .lname small { font-size: 16px; font-family: var(--sans); opacity: 0.75; }
.last .tile.lastd { width: 68px; height: 94px; filter: drop-shadow(0 0 12px rgba(199, 168, 108, 0.55)); animation: pop 0.25s ease-out; }
@keyframes pop { from { transform: scale(0.6); opacity: 0.3; } to { transform: scale(1); opacity: 1; } }
.who .pts { margin-left: auto; color: var(--brass2); font-variant-numeric: tabular-nums; }
.who .dealer { background: var(--vermilion); color: var(--cream); border-radius: 3px; padding: 1px 7px; font-size: 14px; letter-spacing: 0.06em; font-family: var(--serif); box-shadow: inset 0 0 0 1px rgba(241, 235, 221, 0.35); }
.tiles { display: flex; flex-wrap: wrap; gap: 2px; align-items: flex-end; }
.tile { width: var(--tile-w); height: var(--tile-h); position: relative; flex: none; }
.tile svg { width: 100%; height: 100%; display: block; }
.tile .photo { width: 100%; height: 100%; position: relative; border-radius: 9%/6.5%; overflow: hidden; background: #efe9d8; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 0 0 0.5px rgba(0, 0, 0, 0.25); }
.tile .photo img { width: 100%; height: 100%; display: block; object-fit: cover; pointer-events: none; }
.tile .photo .num { position: absolute; left: 4%; top: 3%; min-width: 1.25em; height: 1.25em; line-height: 1.25em; text-align: center; font-size: 0.55em; font-weight: 600; color: #222; background: rgba(255, 255, 255, 0.85); border: 1px solid #888; border-radius: 50%; }
.tile.sm .photo .num { font-size: 0.5em; }
.tile.sm { width: var(--small-w); height: var(--small-h); }
.tile.md { width: 44px; height: 61px; }
.tile.flower svg rect:first-child { fill: #f1e2c3; }
.tile.flower .photo { box-shadow: 0 0 0 2px var(--brass), 0 1px 2px rgba(0, 0, 0, 0.45); }
.tile.claimed { transform: rotate(-90deg) translate(0, 0); margin: 0 10px; }
.tile.back .bk { width: 100%; height: 100%; box-sizing: border-box; background: #2a3833; border: 1px solid #1a4a32; border-radius: 12% / 8.5%; position: relative; } /* CSS borders, not SVG strokes: crisp at any size (Jason 18457) */
.tile.back .bk::after { content: ''; position: absolute; inset: 14% 16%; border: 1px solid rgba(159, 211, 180, 0.6); border-radius: 3px; }
.tile.back .bk.side { border-radius: 8.5% / 12%; } .tile.back .bk.side::after { inset: 16% 14%; }
.meld { display: flex; gap: 1px; margin-right: 8px; align-items: flex-end; }
.melds { display: flex; flex-wrap: wrap; align-items: flex-end; }
.discards { display: grid; grid-template-columns: repeat(auto-fill, var(--small-w)); gap: 2px; }
.center { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; min-width: 0; overflow: hidden; } /* words stay inside the centre (Jason 18443) */
.pool { display: none; }
.last { min-height: 100px; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; font-size: 20px; max-width: 100%; text-align: center; }
.last .tile { width: 62px; height: 86px; }
.msg { font-size: 21px; text-align: center; min-height: 30px; color: var(--brass2); font-family: var(--serif); }
.me { display: flex; align-items: center; gap: 10px; margin: 2px 0 4px; flex-wrap: wrap; border-radius: 10px; padding: 2px 6px; }
.me .melds .tile { width: 34px; height: 47px; }
.hand { display: flex; gap: 4px; align-items: flex-end; justify-content: center; min-height: calc(var(--tile-h) + 18px); }
.handrow { display: flex; align-items: flex-end; gap: 8px; }
.handrow .hand { flex: 1; min-width: 0; }
.handrow .sort { flex: none; margin-bottom: 4px; }
.hand .tile { transition: transform 0.12s; cursor: pointer; touch-action: none; }
.hand .tile.barred { opacity: 0.45; }
.hand .tile.dragging { transition: none; z-index: 5; opacity: 0.9; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.5)); }
.hand .tile.sel { transform: translateY(-22px); }
.hand .tile.sel svg rect:first-child { stroke: var(--brass); stroke-width: 4; }
.hand .tile.sel .photo { box-shadow: 0 0 0 2.5px var(--brass), 0 6px 14px rgba(0, 0, 0, 0.45); }
.hand .tile.drawn { margin-left: 18px; }
.hand .tile.hint svg rect:first-child { stroke: var(--brass2); stroke-width: 4; }
.tile.hint .photo { box-shadow: 0 0 0 2.5px var(--brass2), 0 1px 2px rgba(0, 0, 0, 0.45); }
.actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; min-height: 56px; margin-top: 2px; }
.actions button { font-size: 22px; padding: 6px 20px; min-width: 110px; }
.actions button.win { background: var(--vermilion); border-color: var(--vermilion); color: var(--cream); font-weight: 500; box-shadow: inset 0 0 0 1px rgba(241, 235, 221, 0.3); }
.actions button.pass { background: transparent; border-color: var(--line); color: var(--ink2); }
.actions button small { font-size: 15px; }
.overlay { position: fixed; inset: 0; background: rgba(10, 14, 12, 0.7); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center; padding: 20px; z-index: 10; }
.box { background: #1b201e; border: 1px solid var(--line2); outline: 1px solid var(--line); outline-offset: 4px; border-radius: 8px; padding: 22px 28px; max-width: 920px; width: 100%; max-height: 92vh; overflow: auto; box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55); }
.box h2 { margin: 0 0 10px; font-size: 32px; }
.box p { color: var(--ink2); margin: 0 0 12px; }
.box .namein { display: block; width: min(100%, 420px); margin: 6px auto 18px; font: inherit; font-size: 28px; text-align: center; padding: 6px; border: 0; border-bottom: 1px solid var(--line2); border-radius: 0; background: transparent; color: var(--ink); outline: none; }
.box .namein:focus { border-bottom-color: var(--brass); }
.box .tiles .tile { width: 48px; height: 66px; }
.box table { width: 100%; border-collapse: collapse; font-size: 21px; margin: 10px 0; }
.box td { padding: 5px 8px; border-bottom: 1px solid var(--line); }
.box td.n { text-align: right; color: var(--brass2); font-variant-numeric: tabular-nums; }
.box .row { margin-top: 16px; }
.pay { display: flex; gap: 12px; flex-wrap: wrap; font-size: 21px; }
.pay span { border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px; font-variant-numeric: tabular-nums; }
.pay .plus { color: #bfd9b8; } .pay .minus { color: #d9a7a0; }
/* side seats (Jason 18416, 14 Nov 2026): the tile backs stand on their sides in one column at the table edge; melds and discards sit beside the column.
   At the reveal (a winner's concealed tiles shown face up) the panel goes back to the plain column so the faces read upright. */
.opp-left, .opp-right { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr); column-gap: 8px; row-gap: 4px; align-items: start; }
.opp-right { grid-template-columns: minmax(0, 1fr) auto; }
.opp-left > .who, .opp-right > .who { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
.opp-left > .tiles.vert { grid-column: 1; grid-row: 2 / 4; } .opp-right > .tiles.vert { grid-column: 2; grid-row: 2 / 4; }
.opp-left > .melds { grid-column: 2; grid-row: 2; } .opp-right > .melds { grid-column: 1; grid-row: 2; justify-content: flex-end; }
.opp-left > .discards { grid-column: 2; grid-row: 3; } .opp-right > .discards { grid-column: 1; grid-row: 3; }
.opp-left > .discards, .opp-right > .discards { max-height: none; min-height: 0; overflow: hidden; align-self: stretch; align-content: start; }
.opp.reveal { display: flex; }
.tiles.vert { display: flex; flex-direction: column; flex-wrap: nowrap; gap: 2px; width: var(--side-h, var(--small-h)); align-self: stretch; min-height: 0; align-items: flex-start; }
.opp-right > .tiles.vert { align-items: flex-end; }
.opp > .tiles.vert .tile { flex: none; width: auto; max-width: 100%; height: min(var(--side-w, var(--small-w)), calc((100% - (var(--n) - 1) * 2px) / var(--n))); aspect-ratio: 336 / 240; }
/* side seats at a real table (Jason 18433, 14 Nov 2026): the left player faces right, so their faces are turned a quarter clockwise, their discard rows run
   top to bottom and the next row sits nearer the centre; the right player faces left: faces a quarter anticlockwise, rows bottom to top, next row nearer the
   centre. The right player's melds and discards are the left layout turned a half circle, with the tile inside turned a quarter back. Landscape only. */
@media (orientation: landscape) {
  .opp.sideways { --side-w: 32px; --side-h: calc(var(--side-w) * 1.387); grid-template-rows: auto minmax(0, 1fr); grid-template-columns: auto auto minmax(0, 1fr); }
  @supports (width: round(down, 10px, 1px)) { .opp.sideways { --side-h: round(down, calc(var(--side-w) * 1.387), 1px); } } /* the quarter turn about a whole-pixel centre, same reason */
  .opp-right.sideways { grid-template-columns: minmax(0, 1fr) auto auto; }
  .opp-left.sideways > .tiles.vert { grid-column: 1; grid-row: 2; } .opp-left.sideways > .melds { grid-column: 2; grid-row: 2; } .opp-left.sideways > .discards { grid-column: 3; grid-row: 2; }
  .opp-right.sideways > .tiles.vert { grid-column: 3; grid-row: 2; } .opp-right.sideways > .melds { grid-column: 2; grid-row: 2; } .opp-right.sideways > .discards { grid-column: 1; grid-row: 2; }
  .opp.sideways > .melds { display: flex; flex-direction: column; flex-wrap: wrap; align-content: flex-start; align-items: flex-start; justify-content: flex-start; gap: 6px 4px; align-self: stretch; min-height: 0; overflow: hidden; }
  .opp.sideways .meld { flex-direction: column; margin: 0; gap: 1px; align-items: flex-start; }
  .opp.sideways > .discards { display: grid; grid-auto-flow: column; grid-template-rows: repeat(auto-fill, var(--side-w)); grid-auto-columns: var(--side-h); gap: 2px; align-self: stretch; justify-content: start; align-content: start; max-height: none; overflow: hidden; } /* as many per row as the height holds (Jason 18437), so the rows do not pile into columns */
  .opp-right.sideways > .melds, .opp-right.sideways > .discards { transform: rotate(180deg); }
  .opp.sideways .meld .tile, .opp.sideways > .discards .tile { width: var(--side-h); height: var(--side-w); }
  .opp.sideways .meld .tile > *, .opp.sideways > .discards .tile > * { position: absolute; width: var(--side-w); height: var(--side-h); left: calc(50% - var(--side-w) / 2); top: calc(50% - var(--side-h) / 2); transform: rotate(90deg); }
}
@media (max-height: 500px) and (orientation: landscape) { .opp.sideways { --side-w: 22px; } }
/* across player (Jason 18445, 14 Nov 2026): their faces are upside down from the near seat, their first discard sits at their left, our right, rows run toward the centre */
.opp-top:not(.reveal) .melds .tile > *, .opp-top:not(.reveal) .discards .tile > * { transform: rotate(180deg); }
.opp-top:not(.reveal) .discards { direction: rtl; }
.opp-top:not(.reveal) .melds { flex-direction: row-reverse; justify-content: center; } .opp-top:not(.reveal) .meld { flex-direction: row-reverse; margin: 0 0 0 8px; }
/* seat colours and textures (Jason 18418, 18422, 14 Nov 2026): one colour and one hairline pattern per seat, on the setup card and on the table.
   k0 antique gold, fine diagonal hatch; k1 celadon, dot grid; k2 dusk blue, horizontal hairlines; k3 rouge, lattice. All at low strength. */
.seat, .opp, .me { --wash: color-mix(in srgb, var(--seat, transparent) 10%, transparent); --thread: color-mix(in srgb, var(--seat, transparent) 16%, transparent); }
.k0 { --pattern: repeating-linear-gradient(135deg, var(--thread) 0 1px, transparent 1px 9px); }
.k1 { --pattern: radial-gradient(circle, var(--thread) 0.8px, transparent 1.2px); --pattern-size: 9px 9px; }
.k2 { --pattern: repeating-linear-gradient(180deg, var(--thread) 0 1px, transparent 1px 8px); }
.k3 { --pattern: repeating-linear-gradient(45deg, var(--thread) 0 1px, transparent 1px 11px), repeating-linear-gradient(-45deg, var(--thread) 0 1px, transparent 1px 11px); }
.seat { position: relative; border-top: 2px solid var(--seat, var(--line)); background-color: var(--bg2); background-image: linear-gradient(180deg, var(--wash), transparent 70%), var(--pattern, none); background-size: auto, var(--pattern-size, auto); }
.seat .avatar { border-color: var(--seat); box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--seat); }
.seat .wind { color: var(--seat); }
.opp { --thread: color-mix(in srgb, var(--seat, transparent) 10%, transparent); border-top: 2px solid var(--seat, var(--line)); background-color: rgba(0, 0, 0, 0.26); background-image: linear-gradient(180deg, var(--wash), transparent 55%), var(--pattern, none); background-size: auto, var(--pattern-size, auto); }
.me { border-left: 3px solid var(--seat, var(--line)); background-image: linear-gradient(90deg, var(--wash), transparent 40%); }
.who .av { border-color: var(--seat); }
@media (max-width: 1100px) { .opp-left, .opp-right { width: 300px; } }
@media (max-width: 900px) { .opp-left, .opp-right { width: 150px; } .seats { grid-template-columns: repeat(2, 1fr); } .actions button { font-size: 22px; min-width: 100px; } }
@media (orientation: portrait) { .middle { flex-direction: column; } .opp-left, .opp-right { width: auto; display: flex; }
  .tiles.vert { flex-direction: row; width: auto; align-self: auto; align-items: flex-end; } /* side seats are full-width rows here: the tiles lie sideways in a row */
  .opp > .tiles.vert .tile { flex: 1 1 0; min-width: 0; width: auto; max-width: var(--small-h); height: auto; aspect-ratio: 336 / 240; } }

/* stage 2: people on the app, invites (13 Nov 2026) */
.online { margin: 0; padding: 10px 16px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); display: grid; grid-template-columns: 1fr auto; column-gap: 16px; row-gap: 4px; align-items: center; }
.online h2 { margin: 0; font-size: 20px; grid-column: 1; } .online h2 small { font-size: 14px; opacity: .7; margin-left: 8px; }
.online .hint { margin: 0; grid-column: 1; font-size: 15px; }
.online .row { grid-column: 2; grid-row: 1 / 4; }
.online .row button.big { font-size: 22px; padding: 12px 24px; min-width: 0; }
.invstatus, #lobbynote, .backtable { grid-column: 1 / -1; } #lobbynote:empty, .invstatus:empty, .backtable:empty { display: none; }
.backtable { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 6px 0; } .backtable .sentline { font-size: 18px; }
.people { display: flex; flex-wrap: wrap; gap: 10px; min-height: 48px; grid-column: 1; }
.person { display: flex; flex-direction: column; align-items: center; width: 108px; padding: 8px 6px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); cursor: pointer; }
.person.sel { border-color: var(--brass); background: rgba(199, 168, 108, 0.12); }
.person.busy { opacity: .5; cursor: default; }
.person .avatar { width: 58px; height: 58px; border-radius: 50%; overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: 24px; font-family: var(--serif); background: var(--bg2); border: 1px solid var(--line2); }
.person .avatar img { width: 100%; height: 100%; object-fit: cover; }
.person .pname { font-size: 17px; margin-top: 4px; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .person small { font-size: 12px; opacity: .7; letter-spacing: 0.06em; text-transform: uppercase; }
.nobody { opacity: .6; padding: 12px 0; font-size: 18px; }
.invstatus .sentline { margin: 10px 0; font-size: 18px; } .invstatus .st { display: inline-block; margin: 4px 0 0 10px; padding: 2px 10px; border-radius: 7px; border: 1px solid var(--line); }
.invstatus .st.yes { border-color: #8fb58a; color: #bfd9b8; } .invstatus .st.no, .invstatus .st.expired { border-color: #b08a86; color: #d9a7a0; }
.box .avatar.big { width: 96px; height: 96px; border-radius: 50%; overflow: hidden; margin: 0 auto 10px; display: flex; align-items: center; justify-content: center; font-size: 40px; font-family: var(--serif); background: var(--bg2); border: 1px solid var(--brass-dim); }
.box .avatar.big img { width: 100%; height: 100%; object-fit: cover; }
.who button.small { margin-left: 8px; padding: 2px 8px; font-size: 13px; }

/* phones (Jason 18374, 13 Nov 2026: iPhone 18 Pro, 402x874 portrait / 874x402 landscape in CSS px). Nothing here touches the iPad. */
@media (max-width: 500px), (max-height: 500px) {
  :root { --small-w: 20px; --small-h: 28px; }
  #table.dense { --small-w: 18px; --small-h: 25px; }
  #table { padding: calc(4px + env(safe-area-inset-top)) calc(4px + env(safe-area-inset-right)) calc(4px + env(safe-area-inset-bottom)) calc(4px + env(safe-area-inset-left)); gap: 3px; }
  .info { font-size: 14px; min-width: 96px; line-height: 1.25; }
  .who { font-size: 15px; gap: 6px; } .who .av { width: 30px; height: 30px; font-size: 16px; } .who .dealer { font-size: 12px; }
  .opp { padding: 4px 6px; gap: 2px; border-radius: 10px; }
  .opp .tiles .tile.back { width: 13px; height: 18px; } .opp .tiles.vert .tile.back { width: 18px; height: 13px; }
  .opp .discards { max-height: calc(var(--small-h) * 2 + 2px); overflow: hidden; }
  .me .discards { max-height: calc(var(--small-h) * 2 + 2px); }
  .me .melds .tile { width: 30px; height: 42px; }
  .last { height: 72px; gap: 8px; font-size: 15px; } .last .av { width: 40px; height: 40px; font-size: 18px; } .last .lname { font-size: 18px; } .last .lname small { font-size: 13px; }
  .last .tile, .last .tile.lastd { width: 44px; height: 61px; } .last .claim { font-size: 22px; }
  .msg { font-size: 16px; min-height: 22px; }
  .hand { gap: 3px; } .hand .tile.drawn { margin-left: 10px; }
  .actions { gap: 8px; min-height: 52px; margin-top: 2px; } .actions button { font-size: 20px; padding: 4px 14px; min-width: 84px; border-radius: 8px; } .actions button small { font-size: 12px; }
  button.small { font-size: 14px; padding: 4px 9px; }
  .box { padding: 14px; border-radius: 14px; } .box h2 { font-size: 24px; } .box table { font-size: 17px; } .pay { font-size: 17px; gap: 8px; } .box .tiles .tile { width: 34px; height: 47px; }
  button.big { font-size: 21px; padding: 12px 20px; min-width: 140px; }
  #setup { padding: calc(14px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right)) calc(14px + env(safe-area-inset-bottom)) calc(14px + env(safe-area-inset-left)); justify-content: flex-start; } #setup h1 { font-size: 28px; } .seat .avatar { width: 64px; height: 64px; font-size: 28px; } .seat input[type=text] { font-size: 18px; } .online { display: block; }
  .person { width: 92px; } .person .avatar { width: 50px; height: 50px; }
  .guide { font-size: 16px; } .guide h3 { font-size: 19px; }
  /* all three opponents the same way on a phone (Jason 18463, 14 Nov 2026): plain columns, faces upright, backs lying in one row, one width.
     The real-table turns (side seats sideways, across player upside down) stay iPad-only. */
  .opp-left, .opp-right, .opp.sideways { display: flex; align-items: stretch; } /* the grid's align-items: start would shrink-wrap the discards to one column */
  .opp > .who, .opp > .tiles { flex: none; } .opp > .discards { min-height: 0; }
  .opp-right > .melds { justify-content: flex-start; }
  .opp-left > .discards, .opp-right > .discards { max-height: calc(var(--small-h) * 2 + 2px); align-self: auto; }
  .tiles.vert { flex-direction: row; flex-wrap: nowrap; width: auto; align-self: auto; align-items: flex-end; } .opp-right > .tiles.vert { align-items: flex-end; }
  .opp .tiles.vert .tile.back { width: 13px; height: 18px; }
  .tile.back .bk.side { border-radius: 12% / 8.5%; } .tile.back .bk.side::after { inset: 14% 16%; }
  .opp.sideways > .melds { display: flex; flex-direction: row; flex-wrap: wrap; align-content: normal; align-items: flex-end; justify-content: flex-start; gap: 0; align-self: auto; min-height: 0; }
  .opp.sideways .meld { flex-direction: row; margin: 0 8px 0 0; gap: 1px; align-items: flex-end; }
  .opp.sideways > .discards { display: grid; grid-auto-flow: row; grid-template-rows: none; grid-template-columns: repeat(auto-fill, var(--small-w)); grid-auto-columns: auto; gap: 2px; align-self: auto; justify-content: start; align-content: start; max-height: calc(var(--small-h) * 2 + 2px); }
  .opp-right.sideways > .melds, .opp-right.sideways > .discards { transform: none; }
  .opp.sideways .meld .tile, .opp.sideways > .discards .tile { width: var(--small-w); height: var(--small-h); }
  .opp.sideways .meld .tile > *, .opp.sideways > .discards .tile > * { position: static; width: 100%; height: 100%; transform: none; }
  .opp-top:not(.reveal) .melds .tile > *, .opp-top:not(.reveal) .discards .tile > * { transform: none; }
  .opp-top:not(.reveal) .discards { direction: ltr; }
  .opp-top:not(.reveal) .melds, .opp-top:not(.reveal) .meld { flex-direction: row; } .opp-top:not(.reveal) .meld { margin: 0 8px 0 0; }
  .opp-top { align-items: stretch; justify-self: stretch; } .opp-top .tiles, .opp-top .melds, .opp-top .discards { justify-content: flex-start; }
}
@media (max-width: 500px) and (orientation: portrait) {
  :root { --tile-w: calc((100vw - 60px) / 9.4); }
  #table { display: grid; grid-template-columns: 1fr auto auto auto auto auto; align-content: start; height: auto; min-height: 100dvh; overflow-y: auto; }
  .top, .middle, .topbtns { display: contents; }
  #info { grid-column: 1; grid-row: 1; display: flex; gap: 10px; flex-wrap: wrap; align-items: center; min-width: 0; }
  #btn-lang2 { grid-column: 2; grid-row: 1; } #btn-guide2 { grid-column: 3; grid-row: 1; } #btn-mute { grid-column: 4; grid-row: 1; } #btn-pause { grid-column: 5; grid-row: 1; } #btn-menu { grid-column: 6; grid-row: 1; }
  #btn-lang2, #btn-guide2, #btn-mute, #btn-pause, #btn-menu { align-self: start; padding: 6px 8px; }
  #p2 { grid-column: 1 / -1; grid-row: 2; } #p1 { grid-column: 1 / -1; grid-row: 3; } #p3 { grid-column: 1 / -1; grid-row: 4; }
  .center { grid-column: 1 / -1; grid-row: 5; } .bottom { grid-column: 1 / -1; grid-row: 6; }
  .opp-left, .opp-right, .opp-top { width: auto; flex: none; }
  .hand { flex-wrap: wrap; row-gap: 26px; min-height: 0; padding-top: 22px; }
}
@media (max-height: 500px) and (orientation: landscape) {
  :root { --tile-w: calc((100vw - 140px) / 17.6); }
  .top { max-height: 118px; min-height: 0; }
  /* the three opponents side by side across the top, one width each (Jason 18463); info, the centre and the buttons share the middle row */
  #table { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto minmax(78px, 1fr) auto; column-gap: 6px; row-gap: 4px; }
  .top, .middle { display: contents; }
  #p1 { grid-column: 1; grid-row: 1; } #p2 { grid-column: 2; grid-row: 1; } #p3 { grid-column: 3; grid-row: 1; }
  .opp-left, .opp-right, .opp-top { width: auto; max-height: 140px; justify-self: stretch; }
  .last { height: 56px; min-height: 0; } .last .tile, .last .tile.lastd { width: 38px; height: 53px; } .last .av { width: 34px; height: 34px; }
  .topbtns { flex-wrap: nowrap; gap: 4px; } .topbtns button.small { font-size: 12px; padding: 3px 6px; }
  #info { grid-column: 1; grid-row: 2; align-self: center; } .center { grid-column: 2; grid-row: 2; } .topbtns { grid-column: 3; grid-row: 2; align-self: start; justify-self: end; }
  .bottom { grid-column: 1 / -1; grid-row: 3; }
  .hand { min-height: calc(var(--tile-h) + 14px); }
  .hand .tile.sel { transform: translateY(-12px); }
  .actions { min-height: 46px; }
}
.titlerow { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0; } .titlerow h1 { margin: 0; }
.titlebtns { display: flex; gap: 8px; }
#btn-lang { font-size: 18px; } #btn-lang2 { min-width: 44px; }
button.stop { border-color: rgba(168, 58, 42, 0.7); color: #e0b3aa; } /* stop game (Jason 18403): one quiet red hairline, top right of the table */

@media (min-height: 760px) and (min-width: 1000px) { .seat .avatar { width: 88px; height: 88px; font-size: 34px; } .people { min-height: 60px; } #setup { gap: 16px; } }
/* rules picker, Charleston multi-select, the American card (Jason 18378, 13 Nov 2026) */
.options label.off { display: none; }
.options .grp { display: inline-flex; flex-wrap: wrap; gap: 14px 22px; align-items: center; } .options .grp + .grp { margin-left: 18px; } /* mj-v52: 玩法 and 程度 share one line */
.hints { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 28px; } @media (max-width: 999px) { .hints { grid-template-columns: 1fr; } } /* mj-v52: the two hints side by side on an iPad so the setup page still fits one screen */
#rulesrow button.small { font-size: 16px; padding: 6px 16px; }
#ruleshint { max-width: 760px; }
.tile.pick { outline: 2px solid var(--brass); transform: translateY(-10px); }
.card { max-height: 70vh; overflow: auto; text-align: left; margin: 10px 0; }
.card .fam { font-family: var(--serif); margin: 14px 0 4px; color: var(--brass2); font-size: 19px; }
.card .hand { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: 6px; }
.card .hand:nth-child(even) { background: rgba(255, 255, 255, 0.04); }
.card .hand.near { background: rgba(199, 168, 108, 0.16); }
.card .pat { font-family: var(--sans); font-variant-numeric: tabular-nums; font-size: 20px; letter-spacing: 1px; flex: 1; }
.card .pat .a { color: #e3a89c; } .card .pat .b { color: #b3d6b0; } .card .pat .c { color: #a9c4e0; } .card .pat .x { color: #f6f1dc; }
.card .val { min-width: 48px; text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }
.card .dist { min-width: 96px; text-align: right; color: var(--ink2); font-size: 15px; }
.card .dist.zero { color: var(--brass2); }
.note { color: var(--ink2); font-size: 14px; margin: 4px 0 8px; text-align: left; }

/* how to play (Jason 18391, 13 Nov 2026) */
.guidehead { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 6px; }
.guidehead h2 { margin: 0; }
.guidesel { font-size: 18px; padding: 8px 36px 8px 14px; border-radius: 8px; border: 1px solid var(--line2); background: var(--panel); color: var(--ink); -webkit-appearance: none; appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23c7a86c' stroke-width='1.5'/></svg>"); background-repeat: no-repeat; background-position: right 12px center; }
.guidesel option { color: #1a1812; background: var(--cream); }
.guide { max-height: 66vh; overflow: auto; text-align: left; font-size: 19px; line-height: 1.5; padding-right: 6px; border-top: 1px solid var(--line); margin-top: 8px; }
.guide h3 { font-size: 22px; margin: 18px 0 6px; color: var(--brass2); }
.guide p { margin: 0 0 10px; color: var(--ink); }
.guide ul { margin: 0 0 10px; padding-left: 22px; } .guide li { margin: 0 0 6px; }
.pausebox { width: auto; text-align: center; padding: 36px 56px; } .pausebox h2 { margin: 0 0 22px; font-size: 34px; }
/* Home-screen app on the iPad (Jason 18484, 14 Nov 2026): iPadOS keeps a blurred strip behind the status bar that fades down to about three times the
   bar's height, and the `black` status-bar style of mj-v28 did not stop it; the top edges of the Tutorial, Sound and Pause buttons sat in that
   fade and smeared. The table starts below the fade. Where the bar is opaque the inset is 0 and this adds nothing. */
@media (min-height: 600px) { #table { padding-top: calc(6px + env(safe-area-inset-top) * 3); } } /* no display-mode test: the manifest says fullscreen, and in a browser tab the inset is 0 anyway */

/* ===== bridge (15 Nov 2026): cards, trick, auction, bidding box; the skin above is the mahjong skin unchanged ===== */
:root { --card-w: min(74px, calc((100vw - 90px) / 13.6)); --card-h: calc(var(--card-w) * 1.4); --cs-w: min(34px, calc(100vw / 36)); --cs-h: calc(var(--cs-w) * 1.4); }
.card { width: var(--card-w); height: var(--card-h); position: relative; flex: none; transition: transform 0.12s; }
.card svg { width: 100%; height: 100%; display: block; border-radius: 7%/5%; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); }
.card.sm { width: var(--cs-w); height: var(--cs-h); }
.card.legal svg { box-shadow: 0 0 0 2px var(--brass), 0 1px 2px rgba(0, 0, 0, 0.5); }
.card.dim { opacity: 0.45; }
.hand .card { margin-left: calc(var(--card-w) * -0.28); } .hand .card:first-child { margin-left: 0; }
.hand .card.legal { transform: translateY(-8px); }
.hand .card.hint svg { box-shadow: 0 0 0 3px var(--brass2), 0 1px 2px rgba(0, 0, 0, 0.5); }
.hand .gap { width: 10px; flex: none; }
.hand { min-height: calc(var(--card-h) + 14px); align-items: flex-end; padding-top: 10px; }
.backs { display: flex; gap: 2px; } .backs .card { margin-left: calc(var(--cs-w) * -0.45); } .backs .card:first-child { margin-left: 0; }
.opp-left .backs, .opp-right .backs { flex-direction: column; align-items: center; gap: 0; } .opp-left .backs .card, .opp-right .backs .card { margin-left: 0; margin-top: calc(var(--cs-h) * -0.62); transform: rotate(90deg); } .opp-left .backs .card:first-child, .opp-right .backs .card:first-child { margin-top: 0; }
.opp-left .backs, .opp-right .backs { padding: calc(var(--cs-w) * 0.2) 0; }
/* dummy: face up, one column per suit (top panel) or rows (side panels) */
.dummy { display: flex; gap: 8px; justify-content: center; } .dummy .col { display: flex; flex-direction: column; } .dummy .col .card { margin-top: calc(var(--cs-h) * -0.68); } .dummy .col .card:first-child { margin-top: 0; }
.opp-left .dummy, .opp-right .dummy { flex-direction: column; gap: 4px; } .opp-left .dummy .col, .opp-right .dummy .col { flex-direction: row; } .opp-left .dummy .col .card, .opp-right .dummy .col .card { margin-top: 0; margin-left: calc(var(--cs-w) * -0.5); } .opp-left .dummy .col .card:first-child, .opp-right .dummy .col .card:first-child { margin-left: 0; }
.dummy .card.legal { transform: translateY(-4px); }
.opp-top { width: min(640px, 48vw); }
.top { max-height: 30vh; }
/* trick area */
.trick { position: relative; width: min(44vw, 380px); height: min(30vh, 250px); flex: none; }
.trick .slot { position: absolute; width: var(--card-w); height: var(--card-h); }
.trick .slot.n { left: 50%; top: 0; transform: translateX(-50%); } .trick .slot.s { left: 50%; bottom: 0; transform: translateX(-50%); }
.trick .slot.w { left: 8%; top: 50%; transform: translateY(-50%); } .trick .slot.e { right: 8%; top: 50%; transform: translateY(-50%); }
.trick .slot .card { animation: pop 0.18s ease-out; }
.trick .slot.won .card svg { box-shadow: 0 0 0 2px var(--brass2), 0 1px 2px rgba(0, 0, 0, 0.5); }
/* auction */
.auction { width: min(60vw, 520px); background: var(--panel2); border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; max-height: 32vh; overflow: auto; }
.auction table { width: 100%; border-collapse: collapse; font-size: 19px; font-variant-numeric: tabular-nums; }
.auction th { font-weight: 500; color: var(--celadon); font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase; padding: 2px 6px; border-bottom: 1px solid var(--line); }
.auction td { padding: 3px 6px; text-align: center; height: 30px; }
.auction td.red { color: #d9a7a0; } .auction td.cur { outline: 1px solid var(--brass); border-radius: 4px; } .auction td.dealer::before { content: ''; }
.auction td.wait { color: var(--ink2); }
/* bidding box */
.bidbox { display: flex; flex-direction: column; gap: 6px; align-items: center; width: 100%; }
.bidbox .lv, .bidbox .st, .bidbox .ot { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; }
.bidbox button { min-width: 56px; padding: 8px 12px; font-size: 22px; }
.bidbox .st button.red { color: #e0a79f; } .bidbox .lv button.on { background: var(--brass); color: var(--dark); border-color: var(--brass); }
.bidbox .ot button { font-size: 19px; }
.bidbox .sugg { font-size: 17px; color: var(--celadon); }
.actions { min-height: 54px; }
.info .vul { color: #d9a7a0; } .info .nv { color: var(--celadon); }
.who .tag { background: var(--panel); border: 1px solid var(--line2); border-radius: 3px; padding: 1px 7px; font-size: 13px; letter-spacing: 0.06em; color: var(--brass2); }
.who .hcp { color: var(--ink2); font-size: 15px; }
.sheet { width: 100%; border-collapse: collapse; font-size: 20px; margin: 8px 0; font-variant-numeric: tabular-nums; }
.sheet th { font-weight: 500; color: var(--celadon); font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 8px; border-bottom: 1px solid var(--line2); }
.sheet td { padding: 4px 8px; text-align: right; border-bottom: 1px solid var(--line); } .sheet td:first-child { text-align: left; color: var(--ink2); }
.sheet tr.line td { border-bottom: 2px solid var(--brass-dim); }
.sheet td.g { color: var(--brass2); }
.box .contract { font-size: 30px; font-family: var(--serif); color: var(--brass2); margin: 4px 0 10px; }
.box .parts { color: var(--ink2); font-size: 18px; }
@media (max-height: 820px) { :root { --card-w: min(64px, calc((100vw - 90px) / 13.6)); } .top { max-height: 27vh; } }

/* ===== bridge palette (Jason 18664, 15 Nov 2026): different from the mahjong ink-wash green and gold, still quiet luxury.
   Midnight navy ground, ivory ink, champagne accent, pewter hairlines, one oxblood mark (the title seal, the dealer tag). ===== */
:root { --bg: #141a26; --bg2: #0e131c; --panel: rgba(236, 230, 216, 0.04); --panel2: rgba(0, 0, 0, 0.28);
  --ink: #ece6d8; --ink2: rgba(236, 230, 216, 0.6); --line: rgba(190, 196, 210, 0.16); --line2: rgba(190, 196, 210, 0.32);
  --brass: #c8b48a; --brass2: #e2d3ad; --brass-dim: rgba(200, 180, 138, 0.38); --cream: #f1ece0; --dark: #15130e;
  --vermilion: #7f2f38; --celadon: #a3b1c6; --felt: var(--bg); --felt2: var(--bg2); --accent: var(--brass); }
body { background: radial-gradient(ellipse at 50% 28%, #1d2534 0%, var(--bg) 60%, #0b0f16 100%); background-attachment: fixed; }
.box { background: #171d29; }
.info .vul { color: #d9a3a8; } .auction td.red { color: #d9a3a8; } .bidbox .st button.red { color: #e0a7ac; }
.pay .plus { color: #bcd3c4; } .pay .minus { color: #d9a3a8; }
