anvilsign in

collin/mahjong

1@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;600;900&display=swap');
2
3:root {
4 /* Depth of each player's strip. `--h-len` is floored so a window too narrow
5 to hold two strips shrinks the tiles rather than going negative. */
6 --depth: clamp(232px, 30vh, 330px);
7 --h-len: max(160px, calc(100vw - 2 * var(--depth)));
8 --v-len: 100vh;
9 /* Height the action buttons occupy, held whether or not any are showing.
10 The strip is built from its edge inwards, so a bar that grew when 打出
11 appeared would shove the melds and discards along with it — the reservation
12 is what keeps everything above it still. Sized for the tallest button: the
13 ones that name a tile (打出 五萬, 吃 三萬 四萬) carry a third line. */
14 --bar-h: 52px;
15 /* Largest tile a strip can hold. Edge inwards it has to fit one row of
16 discards (0.88 tiles tall), the melds (0.86), the button bar, the hand
17 (1.71 + 6px) and the nameplate (28px), plus its own padding, gaps and
18 margins — so 3.45 tiles plus 124px.
19
20 Tile size otherwise follows the strip's *length*, which is why a window
21 with less height than F11 kept full-size tiles and left the discards a
22 sliver of a row to be cut off in. */
23 --tile-fit: calc((var(--depth) - 124px) / 3.45);
24
25 --felt: #0f4534;
26 --felt-2: #0a3126;
27 --ivory: #f6f0e2;
28 --ivory-edge: #d9cfb6;
29 --ink: #21262b;
30 --gold: #d9b45c;
31 --red: #b3261e;
32 --green: #1c7a4b;
33 --blue: #1d5aa8;
34}
35
36* {
37 box-sizing: border-box;
38 -webkit-tap-highlight-color: transparent;
39}
40
41html,
42body,
43#root {
44 height: 100%;
45 margin: 0;
46 overflow: hidden;
47 overscroll-behavior: none;
48 touch-action: manipulation;
49 user-select: none;
50}
51
52body {
53 font-family: 'Noto Sans TC', system-ui, sans-serif;
54 color: var(--ivory);
55 background: var(--felt-2);
56}
57
58/* ---------- lobby ---------- */
59.lobby {
60 height: 100%;
61 display: flex;
62 flex-direction: column;
63 align-items: center;
64 justify-content: center;
65 gap: 0.5rem;
66 background: radial-gradient(ellipse at center, var(--felt) 0%, var(--felt-2) 75%);
67}
68.lobby h1 {
69 font-size: clamp(3rem, 9vw, 7rem);
70 font-weight: 900;
71 letter-spacing: 0.1em;
72 margin: 0 0 0.5rem;
73 color: var(--gold);
74}
75.lobby p {
76 margin: 0;
77 opacity: 0.75;
78 letter-spacing: 0.15em;
79}
80.lobby .hint {
81 opacity: 0.45;
82 font-size: 0.9rem;
83 margin-bottom: 1.5rem;
84}
85
86/* ---------- table ---------- */
87.table {
88 position: relative;
89 height: 100%;
90 width: 100%;
91 background: radial-gradient(ellipse at center, var(--felt) 0%, var(--felt-2) 80%);
92}
93
94.slot {
95 position: absolute;
96 overflow: hidden;
97}
98.slot-bottom {
99 bottom: 0;
100 left: var(--depth);
101 right: var(--depth);
102 height: var(--depth);
103}
104.slot-top {
105 top: 0;
106 left: var(--depth);
107 right: var(--depth);
108 height: var(--depth);
109}
110.slot-left {
111 left: 0;
112 top: 0;
113 width: var(--depth);
114 height: 100%;
115}
116.slot-right {
117 right: 0;
118 top: 0;
119 width: var(--depth);
120 height: 100%;
121}
122
123.seat {
124 position: absolute;
125 top: 50%;
126 left: 50%;
127 height: var(--depth);
128 display: flex;
129 flex-direction: column;
130 justify-content: flex-end;
131 align-items: center;
132 gap: 2px;
133 padding: 2px 8px 4px;
134 border-radius: 10px;
135 overflow: hidden;
136 transition: background 0.2s;
137}
138.slot-bottom .seat,
139.slot-top .seat {
140 width: var(--h-len);
141 --tile-w: min(calc((var(--h-len) - 40px) / 18), var(--tile-fit), 72px);
142}
143.slot-left .seat,
144.slot-right .seat {
145 width: var(--v-len);
146 --tile-w: min(calc((var(--v-len) - 40px) / 18), var(--tile-fit), 72px);
147}
148.seat.active {
149 background: linear-gradient(to top, rgba(217, 180, 92, 0.22), transparent 70%);
150}
151.seat.claiming {
152 background: linear-gradient(to top, rgba(179, 38, 30, 0.25), transparent 70%);
153 animation: pulse 1.1s ease-in-out infinite;
154}
155@keyframes pulse {
156 50% {
157 background: linear-gradient(to top, rgba(179, 38, 30, 0.45), transparent 70%);
158 }
159}
160
161/* ---------- tiles ---------- */
162/* Faces come from a 43x2 sprite sheet; the second row is the highlighted
163 variant, which we use for the tile a player has lifted to discard. */
164.tile {
165 position: relative;
166 flex: none;
167 --tw: var(--tile-w);
168 width: var(--tw);
169 height: calc(var(--tw) * 1.375);
170 border-radius: calc(var(--tw) * 0.1);
171 transition: transform 0.12s ease, filter 0.12s ease;
172}
173.tile.t-meld {
174 --tw: calc(var(--tile-w) * 0.62);
175}
176.tile.t-small {
177 --tw: calc(var(--tile-w) * 0.64);
178}
179.tile.face {
180 background-image: url('/tiles/tiles.svg');
181 background-repeat: no-repeat;
182 background-size: calc(var(--tw) * 43) calc(var(--tw) * 2.75);
183 background-position: calc(var(--col) * var(--tw) * -1) 0;
184 filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.45));
185}
186.tile.back {
187 background-image: url('/tiles/back.png');
188 background-size: 100% 100%;
189 filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.45));
190}
191.tile.tappable {
192 cursor: pointer;
193}
194.tile.raised {
195 transform: translateY(calc(var(--tw) * -0.28));
196 filter: drop-shadow(0 10px 12px rgba(0, 0, 0, 0.55));
197}
198/* Lifted tiles switch to the sheet's highlighted row. */
199.tile.face.raised {
200 background-position: calc(var(--col) * var(--tw) * -1) calc(var(--tw) * -1.375);
201}
202.tile.hl {
203 outline: 2px solid var(--gold);
204 outline-offset: 1px;
205 border-radius: calc(var(--tw) * 0.1);
206}
207.tile.dim {
208 opacity: 0.45;
209}
210
211/* ---------- seat sections ---------- */
212.hand {
213 display: flex;
214 gap: 2px;
215 /* the extra top room is where the 摸 tag sits */
216 height: calc(var(--tile-w) * 1.71 + 6px);
217 padding-top: calc(var(--tile-w) * 0.34);
218 align-items: flex-end;
219 flex: none;
220}
221/* Every hand tile sits in a draggable cell. */
222.hand-cell {
223 position: relative;
224 display: flex;
225 align-items: flex-end;
226 touch-action: none;
227 cursor: grab;
228}
229.hand-cell.dragging {
230 z-index: 5;
231 cursor: grabbing;
232}
233.hand-cell.dragging .tile {
234 transform: translateY(calc(var(--tile-w) * -0.2)) scale(1.06);
235 filter: drop-shadow(0 14px 18px rgba(0, 0, 0, 0.65));
236}
237.drawn-slot {
238 margin-left: calc(var(--tile-w) * 0.45);
239}
240.drawn-slot .tile {
241 outline: 2px solid var(--gold);
242 outline-offset: 1px;
243 border-radius: calc(var(--tw) * 0.1);
244}
245.drawn-tag {
246 position: absolute;
247 top: calc(var(--tile-w) * -0.3);
248 left: 0;
249 right: 0;
250 text-align: center;
251 font-size: calc(var(--tile-w) * 0.24);
252 font-weight: 600;
253 letter-spacing: 0.1em;
254 color: var(--gold);
255 white-space: nowrap;
256 pointer-events: none;
257}
258
259.melds {
260 display: flex;
261 gap: 10px;
262 flex-wrap: wrap;
263 justify-content: center;
264 min-height: calc(var(--tile-w) * 0.86);
265 flex: none;
266}
267.meld {
268 display: flex;
269 gap: 1px;
270}
271.meld.flowers {
272 margin-left: 12px;
273 padding-left: 12px;
274 border-left: 1px dashed rgba(246, 240, 226, 0.3);
275}
276.discards {
277 display: flex;
278 flex-wrap: wrap;
279 gap: 2px;
280 justify-content: center;
281 align-content: flex-start;
282 max-width: 94%;
283 min-height: 0;
284 margin-bottom: 2px;
285 flex: 1 1 0;
286 overflow-y: auto;
287 scrollbar-width: none;
288}
289
290.nameplate {
291 display: flex;
292 align-items: center;
293 gap: 8px;
294 font-size: 13px;
295 letter-spacing: 0.08em;
296 opacity: 0.9;
297 padding-top: 2px;
298 flex: none;
299}
300.nameplate .wind {
301 display: flex;
302 flex-direction: column;
303 align-items: center;
304 line-height: 1;
305 font-size: 18px;
306 font-weight: 900;
307 color: var(--gold);
308}
309.nameplate .wind em {
310 font-style: normal;
311 font-size: 8px;
312 font-weight: 600;
313 letter-spacing: 0.1em;
314 text-transform: uppercase;
315 opacity: 0.6;
316}
317.nameplate .wind.dealer {
318 color: #ff7a68;
319}
320.nameplate .tag {
321 font-size: 11px;
322 padding: 1px 6px;
323 border-radius: 999px;
324 background: rgba(217, 180, 92, 0.2);
325 border: 1px solid rgba(217, 180, 92, 0.5);
326}
327.nameplate .tag.ting {
328 background: rgba(46, 170, 120, 0.2);
329 border-color: rgba(46, 170, 120, 0.6);
330}
331.nameplate .tag.sacred {
332 background: rgba(179, 38, 30, 0.22);
333 border-color: rgba(224, 108, 96, 0.6);
334 color: #ffc9c2;
335}
336.nameplate .chips {
337 margin-left: 4px;
338 font-weight: 900;
339 font-size: 16px;
340 color: var(--gold);
341}
342
343.actionbar {
344 display: flex;
345 gap: 8px;
346 align-items: center;
347 justify-content: flex-end;
348 padding-right: calc(var(--tile-w) * 0.4);
349 align-self: stretch;
350 /* Reserved even when empty — see --bar-h. */
351 min-height: var(--bar-h);
352 flex-wrap: wrap;
353 flex: none;
354}
355/* Every button on the bar is the same height, so the row is the same height
356 whichever ones are up: without this a 打出 五萬 stands taller than a bare 過
357 and the strip shuffles itself every time you lift a tile. */
358.actionbar .btn {
359 height: var(--bar-h);
360 min-height: 0;
361 padding-top: 4px;
362 padding-bottom: 4px;
363}
364.waiting {
365 font-size: 12px;
366 opacity: 0.5;
367}
368.delta {
369 font-size: 20px;
370 font-weight: 900;
371}
372.delta.up {
373 color: #5fd39a;
374}
375.delta.down {
376 color: #ff8a80;
377}
378
379/* ---------- buttons ---------- */
380.btn {
381 font-family: inherit;
382 font-size: 17px;
383 font-weight: 400;
384 color: #1a1a1a;
385 background: linear-gradient(180deg, #f3e6c4, #d9b45c);
386 border: none;
387 border-radius: 8px;
388 padding: 6px 15px;
389 min-height: 46px;
390 box-shadow: 0 2px 0 #9a7d38;
391 cursor: pointer;
392 display: inline-flex;
393 align-items: center;
394 gap: 6px;
395}
396.btn:active {
397 transform: translateY(2px);
398 box-shadow: none;
399}
400.btn-sub {
401 font-size: 12px;
402 opacity: 0.7;
403}
404
405/* Bilingual label: the called term above, English cue below. */
406.bi {
407 display: flex;
408 flex-direction: column;
409 align-items: center;
410 justify-content: center;
411 line-height: 1.05;
412 gap: 1px;
413}
414.bi .zh {
415 font-size: 19px;
416 font-weight: 400;
417 letter-spacing: 0.06em;
418}
419.bi .en {
420 font-size: 9.5px;
421 font-weight: 600;
422 letter-spacing: 0.11em;
423 text-transform: uppercase;
424 opacity: 0.68;
425 white-space: nowrap;
426}
427.bi .bi-sub {
428 font-size: 11px;
429 opacity: 0.72;
430 white-space: nowrap;
431}
432.big-btn .bi .zh {
433 font-size: 24px;
434}
435.big-btn .bi .en {
436 font-size: 11px;
437}
438.btn.claim.hu {
439 background: linear-gradient(180deg, #ff8a7a, #c0392b);
440 color: #fff;
441 box-shadow: 0 2px 0 #7c231a;
442}
443.btn.claim.kong,
444.btn.claim.pung {
445 background: linear-gradient(180deg, #8fd3ff, #2b7ec0);
446 color: #fff;
447 box-shadow: 0 2px 0 #1c527d;
448}
449.btn.claim.chow {
450 background: linear-gradient(180deg, #9be3b7, #2e9e63);
451 color: #fff;
452 box-shadow: 0 2px 0 #1d6640;
453}
454.btn.sort {
455 min-height: 20px;
456 padding: 1px 8px;
457 font-size: 11px;
458 letter-spacing: 0.06em;
459 border-radius: 999px;
460}
461.btn.proceed {
462 background: linear-gradient(180deg, #f3e6c4, #d9b45c);
463}
464.btn.pass,
465.btn.ghost {
466 background: transparent;
467 color: rgba(246, 240, 226, 0.75);
468 border: 1px solid rgba(246, 240, 226, 0.35);
469 box-shadow: none;
470}
471.btn.discard {
472 background: linear-gradient(180deg, #fff2cf, #e0c070);
473}
474.big-btn {
475 font-size: 22px;
476 padding: 12px 34px;
477 min-height: 56px;
478}
479
480/* ---------- center ---------- */
481.center {
482 position: absolute;
483 inset: var(--depth);
484 display: flex;
485 flex-direction: column;
486 align-items: center;
487 justify-content: center;
488 gap: 10px;
489 pointer-events: none;
490}
491.center > * {
492 pointer-events: auto;
493}
494/* Everything in the centre reads on top of the wall square. */
495.info,
496.last-discard,
497.prompt,
498.result,
499.info {
500 display: flex;
501 flex-direction: column;
502 align-items: center;
503 gap: 2px;
504 opacity: 0.9;
505 text-align: center;
506}
507.info .round,
508.info .wall {
509 display: flex;
510 flex-direction: column;
511 align-items: center;
512 line-height: 1.05;
513}
514.info .wall {
515 margin-top: 10px;
516 padding-top: 10px;
517 border-top: 1px solid rgba(246, 240, 226, 0.14);
518}
519.info .big {
520 font-size: 40px;
521 font-weight: 400;
522 color: var(--gold);
523}
524.info .lbl {
525 font-size: 11px;
526 letter-spacing: 0.06em;
527 opacity: 0.6;
528}
529.info .hand-no {
530 margin-top: 8px;
531 font-size: 11px;
532 opacity: 0.5;
533 letter-spacing: 0.1em;
534}
535/* The wall: a square of four staggered sides, 18 stacks of two each, drawn
536 with the tileset's own blank tile. Sits behind the centre readout. */
537.wall-ring {
538 position: absolute;
539 top: 50%;
540 left: 50%;
541 --ring: min(calc(100vh - 2 * var(--depth) - 16px), calc(100vw - 2 * var(--depth) - 16px), 560px);
542 --ws: calc(var(--ring) / 19.375);
543 --wd: calc(var(--ws) * 1.375);
544 width: var(--ring);
545 height: var(--ring);
546 transform: translate(-50%, -50%);
547 pointer-events: none;
548 z-index: 0;
549}
550.wall-side {
551 position: absolute;
552 display: flex;
553}
554/* Pinwheel: each side starts where the previous one ended. */
555.wall-side.top {
556 top: 0;
557 left: var(--wd);
558 right: 0;
559 height: var(--wd);
560}
561.wall-side.right {
562 top: var(--wd);
563 right: 0;
564 bottom: 0;
565 width: var(--wd);
566 flex-direction: column;
567}
568.wall-side.bottom {
569 bottom: 0;
570 left: 0;
571 right: var(--wd);
572 height: var(--wd);
573 flex-direction: row-reverse;
574}
575.wall-side.left {
576 top: 0;
577 left: 0;
578 bottom: var(--wd);
579 width: var(--wd);
580 flex-direction: column-reverse;
581}
582.wall-stack {
583 position: relative;
584 flex: none;
585 width: var(--ws);
586 height: var(--wd);
587}
588.wall-side.left .wall-stack,
589.wall-side.right .wall-stack {
590 width: var(--wd);
591 height: var(--ws);
592}
593.wall-stack i {
594 position: absolute;
595 top: 50%;
596 left: 50%;
597 width: var(--ws);
598 height: var(--wd);
599 margin: calc(var(--wd) / -2) 0 0 calc(var(--ws) / -2);
600 background-image: url('/tiles/back.png');
601 background-size: 100% 100%;
602 filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.45));
603}
604.wall-side.left .wall-stack i,
605.wall-side.right .wall-stack i {
606 transform: rotate(90deg);
607}
608/* One tile left in the stack. */
609.wall-stack.s1 i {
610 opacity: 0.8;
611 transform: scale(0.86);
612}
613.wall-side.left .wall-stack.s1 i,
614.wall-side.right .wall-stack.s1 i {
615 transform: rotate(90deg) scale(0.86);
616}
617/* Spent stacks stay as ghosts so the square keeps its shape. */
618.wall-stack.s0 i {
619 background: none;
620 filter: none;
621 border: 1px dashed rgba(246, 240, 226, 0.11);
622 border-radius: 2px;
623}
624.wall-stack.dead i {
625 opacity: 0.4;
626 filter: grayscale(0.6);
627}
628.wall-stack.next::after {
629 content: '';
630 position: absolute;
631 inset: -2px;
632 border: 2px solid var(--gold);
633 border-radius: 3px;
634 box-shadow: 0 0 12px rgba(217, 180, 92, 0.7);
635}
636
637.facing {
638 position: relative;
639 z-index: 1;
640 display: flex;
641 flex-direction: column;
642 align-items: center;
643 gap: 8px;
644 transition: transform 0.35s ease;
645}
646
647.last-discard {
648 display: flex;
649 flex-direction: column;
650 align-items: center;
651 gap: 6px;
652 --tile-w: 64px;
653}
654.ld-label {
655 font-size: 12px;
656 opacity: 0.6;
657}
658.prompt {
659 font-size: 15px;
660 letter-spacing: 0.1em;
661 opacity: 0.8;
662}
663.prompt.warn {
664 color: #ffb4a2;
665 font-weight: 600;
666}
667.result {
668 background: rgba(10, 30, 24, 0.94);
669 border: 1px solid rgba(217, 180, 92, 0.45);
670 border-radius: 14px;
671 padding: 18px 26px;
672 display: flex;
673 flex-direction: column;
674 align-items: center;
675 gap: 10px;
676 max-height: 90%;
677 overflow: auto;
678}
679.result h2 {
680 margin: 0;
681 font-size: 24px;
682 color: var(--gold);
683}
684.result .wt {
685 color: var(--ivory);
686 opacity: 0.8;
687}
688.tai-list {
689 display: grid;
690 grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
691 gap: 2px 18px;
692 font-size: 14px;
693 width: 100%;
694}
695.tai-item {
696 display: flex;
697 align-items: baseline;
698 justify-content: space-between;
699 gap: 12px;
700 padding: 2px 0;
701 border-bottom: 1px dotted rgba(246, 240, 226, 0.2);
702}
703.tai-name {
704 display: flex;
705 flex-direction: column;
706 line-height: 1.15;
707}
708.tai-name em {
709 font-style: normal;
710 font-size: 10px;
711 letter-spacing: 0.08em;
712 text-transform: uppercase;
713 opacity: 0.55;
714}
715.tai-val {
716 font-weight: 700;
717 color: var(--gold);
718}
719/* 胡牌 — the arrow that lands on the winner's edge of the table. Sits over the
720 strip rather than in it, so the hand underneath keeps the height it had and
721 nothing shifts when it appears. */
722.win-arrow {
723 position: absolute;
724 top: 0;
725 left: 50%;
726 font-size: 52px;
727 line-height: 0.9;
728 color: var(--gold);
729 text-shadow: 0 0 6px #0a3126, 0 0 20px rgba(217, 180, 92, 0.9);
730 pointer-events: none;
731 z-index: 4;
732 animation: arrow-nudge 0.9s ease-in-out infinite;
733}
734@keyframes arrow-nudge {
735 0%,
736 100% {
737 transform: translate(-50%, 0);
738 }
739 50% {
740 transform: translate(-50%, 9px);
741 }
742}
743
744/* 流局 — who was there and what they were sitting on. */
745.ready-list {
746 display: flex;
747 flex-direction: column;
748 gap: 6px;
749 margin-top: 2px;
750}
751.ready-row {
752 display: flex;
753 align-items: center;
754 gap: 8px;
755 font-size: 14px;
756}
757.ready-row.none {
758 opacity: 0.45;
759}
760.ready-name {
761 min-width: 6.5em;
762 text-align: right;
763}
764.ready-row .tag.ting {
765 font-size: 11px;
766 padding: 1px 6px;
767 border-radius: 999px;
768 background: rgba(46, 170, 120, 0.2);
769 border: 1px solid rgba(46, 170, 120, 0.6);
770 white-space: nowrap;
771}
772.ready-tiles {
773 display: flex;
774 flex-wrap: wrap;
775 gap: 2px;
776 /* Tiles size themselves off their strip's --tile-w, and the centre is not in
777 one — without a size of its own here they come out 0 x 0 and vanish. */
778 --tile-w: 46px;
779}
780.ready-no {
781 font-size: 12px;
782 letter-spacing: 0.04em;
783}
784
785.deltas {
786 display: flex;
787 gap: 16px;
788 font-size: 14px;
789 opacity: 0.9;
790}
791.deltas .up {
792 color: #5fd39a;
793}
794.deltas .down {
795 color: #ff8a80;
796}
797
798/* ---------- help panel ---------- */
799.helpbtn {
800 margin-left: 2px;
801 width: 22px;
802 height: 22px;
803 border-radius: 50%;
804 border: 1px solid rgba(246, 240, 226, 0.35);
805 background: transparent;
806 color: rgba(246, 240, 226, 0.75);
807 font-family: inherit;
808 font-size: 12px;
809 line-height: 1;
810 cursor: pointer;
811}
812/* The rules panel gets its own deeper slot so it is comfortable to read. */
813.help-slot {
814 position: absolute;
815 inset: 0;
816 z-index: 30;
817 background: rgba(4, 18, 14, 0.55);
818}
819.help-slot.slot-bottom,
820.help-slot.slot-top,
821.help-slot.slot-left,
822.help-slot.slot-right {
823 inset: 0;
824 width: auto;
825 height: auto;
826}
827.help {
828 position: absolute;
829 top: 50%;
830 left: 50%;
831 height: var(--hd);
832 z-index: 31;
833 display: flex;
834 flex-direction: column;
835 background: rgba(8, 32, 25, 0.985);
836 border: 1px solid rgba(217, 180, 92, 0.4);
837 border-radius: 12px;
838 padding: 10px 18px 14px;
839 box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
840}
841/* Anchored to the asking player's own edge, and rotated to face them. The
842 leading translate is applied last, so it shifts the box in screen space. */
843.help-slot.slot-bottom .help,
844.help-slot.slot-top .help {
845 width: calc(100vw - 60px);
846 --hd: min(52vh, 560px);
847 --off: calc(50vh - var(--hd) / 2 - 14px);
848}
849.help-slot.slot-left .help,
850.help-slot.slot-right .help {
851 width: calc(100vh - 60px);
852 --hd: min(52vw, 560px);
853 --off: calc(50vw - var(--hd) / 2 - 14px);
854}
855.help-slot.slot-bottom .help {
856 translate: 0 var(--off);
857}
858.help-slot.slot-top .help {
859 translate: 0 calc(var(--off) * -1);
860}
861.help-slot.slot-left .help {
862 translate: calc(var(--off) * -1) 0;
863}
864.help-slot.slot-right .help {
865 translate: var(--off) 0;
866}
867.help-head {
868 display: flex;
869 align-items: center;
870 justify-content: space-between;
871 gap: 16px;
872 flex: none;
873}
874.help-head h3 {
875 margin: 0;
876 font-size: 15px;
877 font-weight: 400;
878 letter-spacing: 0.08em;
879 color: var(--gold);
880}
881.help-head .btn {
882 min-height: 30px;
883 padding: 2px 12px;
884 font-size: 13px;
885}
886.help-body {
887 flex: 1 1 0;
888 min-height: 0;
889 overflow-y: auto;
890 columns: 4;
891 column-gap: 26px;
892 column-fill: auto;
893 padding-top: 8px;
894 overflow-x: auto;
895 scrollbar-width: thin;
896}
897.help-body section {
898 break-inside: avoid;
899 margin-bottom: 10px;
900}
901.help-body h4 {
902 margin: 0 0 2px;
903 font-size: 13px;
904 font-weight: 400;
905 color: var(--gold);
906 letter-spacing: 0.06em;
907}
908.help-body h4 em {
909 font-style: normal;
910 font-size: 9px;
911 letter-spacing: 0.12em;
912 text-transform: uppercase;
913 opacity: 0.55;
914 margin-left: 4px;
915}
916.help-body p {
917 margin: 0 0 4px;
918 display: flex;
919 flex-direction: column;
920 line-height: 1.35;
921 font-size: 11.5px;
922}
923.help-body p em {
924 font-style: normal;
925 font-size: 10.5px;
926 opacity: 0.6;
927}
928.help-body .credit {
929 opacity: 0.6;
930}
931
932/* ---------- lobby resume ---------- */
933.lobby .sub {
934 font-size: 0.95rem;
935}
936.resume {
937 margin-top: 1.4rem;
938 padding: 12px 26px;
939 border: 1px solid rgba(217, 180, 92, 0.35);
940 border-radius: 12px;
941 background: rgba(0, 0, 0, 0.2);
942 text-align: center;
943 display: flex;
944 flex-direction: column;
945 gap: 6px;
946}
947.resume-line {
948 font-size: 14px;
949 color: var(--gold);
950 letter-spacing: 0.06em;
951}
952.resume-scores {
953 display: flex;
954 gap: 18px;
955 justify-content: center;
956 font-size: 13px;
957 opacity: 0.8;
958}
959.resume-scores b {
960 color: var(--gold);
961 font-weight: 600;
962}
963.resume-when {
964 font-size: 11px;
965 opacity: 0.45;
966 letter-spacing: 0.08em;
967}
968.lobby-buttons {
969 display: flex;
970 flex-direction: column;
971 gap: 12px;
972 margin-top: 1.6rem;
973 align-items: stretch;
974}
975/* The two ways to play carry a line of explanation under the name. */
976.lobby-buttons .big-btn {
977 display: flex;
978 flex-direction: column;
979 gap: 3px;
980 min-width: 360px;
981 padding: 12px 28px;
982}
983.lobby-buttons .big-btn em {
984 font-style: normal;
985 font-size: 12px;
986 font-weight: 400;
987 letter-spacing: 0.03em;
988 opacity: 0.72;
989}
990
991/* ---------- sound ---------- */
992.lobby-extras {
993 margin-top: 1.4rem;
994 display: flex;
995 gap: 12px;
996 align-items: center;
997}
998/* Small rounded button for the things that sit under the main choices. */
999.btn.pill {
1000 min-height: 34px;
1001 padding: 2px 14px;
1002 font-size: 13px;
1003 letter-spacing: 0.06em;
1004 border-radius: 999px;
1005 gap: 8px;
1006}
1007.sound-toggle.on {
1008 border-color: rgba(217, 180, 92, 0.7);
1009 color: var(--gold);
1010}
1011.sound-toggle.compact {
1012 min-height: 28px;
1013 padding: 2px 9px;
1014 font-size: 15px;
1015}
1016.sound-toggle .spk {
1017 font-size: 15px;
1018 line-height: 1;
1019}
1020
1021/* ---------- shared table controls ---------- */
1022/* Bottom-right of the centre square, opposite the log. Unrotated on purpose:
1023 it belongs to the table, not to a seat. */
1024.table-controls {
1025 position: absolute;
1026 right: 10px;
1027 bottom: 8px;
1028 display: flex;
1029 align-items: center;
1030 gap: 8px;
1031}
1032.btn.undo {
1033 min-height: 34px;
1034 padding: 3px 14px;
1035 border-radius: 999px;
1036 gap: 9px;
1037 max-width: 40vh;
1038}
1039.undo-arrow {
1040 font-size: 17px;
1041 line-height: 1;
1042 color: var(--gold);
1043}
1044.undo-what {
1045 display: flex;
1046 flex-direction: column;
1047 align-items: flex-start;
1048 line-height: 1.15;
1049 min-width: 0;
1050}
1051.undo-what .zh {
1052 font-size: 13px;
1053 letter-spacing: 0.05em;
1054}
1055.undo-what .en {
1056 font-size: 9px;
1057 letter-spacing: 0.09em;
1058 text-transform: uppercase;
1059 opacity: 0.55;
1060 white-space: nowrap;
1061 overflow: hidden;
1062 text-overflow: ellipsis;
1063 max-width: 100%;
1064}
1065
1066/* ---------- result: one block per winner ---------- */
1067.result .win {
1068 display: flex;
1069 flex-direction: column;
1070 align-items: center;
1071 gap: 8px;
1072 width: 100%;
1073}
1074.result .win + .win {
1075 padding-top: 10px;
1076 border-top: 1px solid rgba(217, 180, 92, 0.3);
1077}
1078.result .liable {
1079 font-size: 12px;
1080 letter-spacing: 0.08em;
1081 color: #ffb4a2;
1082}
1083.result .multi {
1084 font-size: 12px;
1085 letter-spacing: 0.1em;
1086 color: var(--gold);
1087 opacity: 0.85;
1088}
1089
1090/* ---------- settings ---------- */
1091.over-buttons {
1092 display: flex;
1093 gap: 12px;
1094 align-items: center;
1095}
1096.settings-scrim {
1097 position: absolute;
1098 inset: 0;
1099 z-index: 40;
1100 background: rgba(4, 18, 14, 0.72);
1101 display: flex;
1102 align-items: center;
1103 justify-content: center;
1104 padding: 20px;
1105}
1106.settings {
1107 width: min(1180px, 100%);
1108 max-height: 100%;
1109 display: flex;
1110 flex-direction: column;
1111 background: rgba(8, 32, 25, 0.99);
1112 border: 1px solid rgba(217, 180, 92, 0.4);
1113 border-radius: 14px;
1114 box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
1115 padding: 16px 28px 22px;
1116}
1117.settings-head {
1118 display: flex;
1119 align-items: center;
1120 justify-content: space-between;
1121 gap: 16px;
1122 flex: none;
1123 padding-bottom: 12px;
1124 border-bottom: 1px solid rgba(246, 240, 226, 0.12);
1125}
1126.settings-head h3 {
1127 margin: 0;
1128 font-size: 22px;
1129 font-weight: 400;
1130 letter-spacing: 0.08em;
1131 color: var(--gold);
1132}
1133.settings-head-btns {
1134 display: flex;
1135 gap: 10px;
1136}
1137.settings-head .btn {
1138 min-height: 46px;
1139 padding: 2px 22px;
1140 font-size: 17px;
1141}
1142.settings-body {
1143 /* `1 1 auto`, not `1 1 0`: the panel's own height comes from this content,
1144 so a zero basis collapses the pair of them to nothing. `max-height` on the
1145 panel is what brings the scrollbar back at the other end. */
1146 flex: 1 1 auto;
1147 min-height: 0;
1148 overflow-y: auto;
1149 scrollbar-width: thin;
1150 padding-top: 14px;
1151 /* Columns rather than a grid: grid rows would size to the tallest section
1152 and leave the shorter one padded with air, which is what pushed the last
1153 house rule off the bottom. */
1154 columns: 2;
1155 column-gap: 44px;
1156}
1157.settings-body section {
1158 break-inside: avoid;
1159 margin-bottom: 22px;
1160}
1161.settings-body h4 {
1162 margin: 0 0 10px;
1163 font-size: 16px;
1164 font-weight: 400;
1165 color: var(--gold);
1166 letter-spacing: 0.06em;
1167}
1168.settings-body h4 em {
1169 font-style: normal;
1170 font-size: 11px;
1171 letter-spacing: 0.12em;
1172 text-transform: uppercase;
1173 opacity: 0.55;
1174 margin-left: 5px;
1175}
1176.settings .field {
1177 display: flex;
1178 align-items: center;
1179 gap: 14px;
1180 padding: 5px 0;
1181}
1182.settings .f-label {
1183 display: flex;
1184 align-items: baseline;
1185 gap: 6px;
1186 font-size: 16px;
1187 /* Wide enough for 起始籌碼 STARTING CHIPS, so every input in a section
1188 starts at the same place. */
1189 min-width: 196px;
1190 opacity: 0.85;
1191}
1192/* ...except the player rows, which are labelled 1–4 and need no such room. */
1193.settings .names .f-label {
1194 min-width: 26px;
1195}
1196.settings .f-label em {
1197 font-style: normal;
1198 font-size: 11px;
1199 letter-spacing: 0.1em;
1200 text-transform: uppercase;
1201 opacity: 0.55;
1202}
1203.settings input[type='text'],
1204.settings input:not([type]),
1205.settings input[type='number'] {
1206 flex: 1 1 0;
1207 min-width: 0;
1208 font-family: inherit;
1209 font-size: 18px;
1210 color: var(--ivory);
1211 background: rgba(0, 0, 0, 0.28);
1212 border: 1px solid rgba(246, 240, 226, 0.25);
1213 border-radius: 8px;
1214 padding: 11px 14px;
1215 min-height: 48px;
1216 user-select: text;
1217}
1218.settings input:focus {
1219 outline: none;
1220 border-color: rgba(217, 180, 92, 0.8);
1221}
1222.settings input[type='number'] {
1223 max-width: 150px;
1224}
1225.settings input[type='range'] {
1226 flex: 1 1 0;
1227 height: 34px;
1228 accent-color: var(--gold);
1229}
1230.settings input:disabled {
1231 opacity: 0.4;
1232}
1233.settings .switch {
1234 display: grid;
1235 grid-template-columns: auto 1fr;
1236 gap: 3px 14px;
1237 align-items: center;
1238 padding: 9px 0;
1239 cursor: pointer;
1240}
1241.settings .switch input {
1242 width: 26px;
1243 height: 26px;
1244 accent-color: var(--gold);
1245 cursor: pointer;
1246}
1247.settings .sw-name {
1248 display: flex;
1249 align-items: baseline;
1250 gap: 8px;
1251 font-size: 17px;
1252}
1253.settings .sw-name em {
1254 font-style: normal;
1255 font-size: 11px;
1256 letter-spacing: 0.1em;
1257 text-transform: uppercase;
1258 opacity: 0.55;
1259}
1260.settings .note {
1261 grid-column: 2;
1262 font-size: 13px;
1263 line-height: 1.4;
1264 opacity: 0.55;
1265}
1266.settings .switch.dead {
1267 opacity: 0.4;
1268 cursor: default;
1269}
1270.settings .note.lock {
1271 grid-column: auto;
1272 margin: 4px 0 0;
1273 color: #ffb4a2;
1274 opacity: 0.75;
1275}