﻿/* game.css — game board, betting panel, sidebar (Cépage ID / Régions), 50/50, host panel, timer */
.bw{position:relative;width:100%;border-radius:50%;overflow:hidden}
/* Grape↔region atypicality warning for guessers — amber strip between the wheel and the panel. */
.atypical-warn{
  max-width:520px;margin:10px auto 0;padding:8px 14px;
  background:#fff7e0;border:1.5px solid #e0a72c;border-radius:10px;
  color:#8a4b00;font-size:12.5px;line-height:1.4;font-weight:600;
  text-align:center;box-shadow:0 2px 8px rgba(0,0,0,0.18);
}
.atypical-warn::before{content:"\26A0";margin-right:6px;font-weight:700}
/* Millésime hint — glowing, left-aligned button between the wheel and the panel. Shown only when the
   wine's year is off the wheel (updateMillesimeHint); click reveals the decade (showMillesimeHint). */
/* margin-top is NEGATIVE on purpose: the board art carries 3–4.5 % of its own width as empty
   margin inside its square canvas, so .bw ends well below the drawn wheel. The pull eats that
   dead space instead of the wheel — and it is a PERCENTAGE (of the wrap's width, like the art's
   own margin) so the result holds on every screen size instead of drifting with it.
   -3.5 % lands the total wheel→card distance on the 44px asked for (2026-08-31, third pass):
   ~1px of air above the button, its own 42px, 1px below. The button sits at the far left, where
   the wheel's arc has already curved well away, so even on the boards whose margin is thinner
   than 3.5 % nothing overlaps the drawing. */
/* Lifted 10px (requested 2026-08-31) with top, NOT with margin: the row is already
   position:relative (see the z-index:2 rule further down), so an offset moves the button on
   screen and leaves its layout box exactly where it was. The wheel-to-panel distance is therefore
   untouched by construction — which is the whole point, since the -4px bottom margin below
   COLLAPSES with the panel margin and any margin arithmetic here would have moved the panel too.
   Clearance: the board art keeps a 12.2% margin outside its outer ring (r 1070.88 of a 2834.65
   viewBox), so at the button's far-left x the arc is ~56px above the image edge — the lift eats
   10 of the ~45px that were free there. */
.mil-hint-row{max-width:520px;margin:-3.5% auto 0;padding:0 2px;display:flex;justify-content:flex-start;top:-10px}
/* The wheel↔panel gap was tightened to 5px (.panel margin-top), but a row standing between them
   must keep the 12px it always had underneath — otherwise the panel creeps up under the INDICE
   button. Only the LAST visible row carries it (wmSyncRowGaps in bets.js tags it), so when both
   rows show, the 10px between them is untouched. */
.mil-hint-row.gap-keep,.atypical-warn.gap-keep{margin-bottom:12px}
/* …except around the INDICE button, where that spacing still read as a hole (2026-08-31): the
   empty space above + below it went 8+12 → 4+6 → -4+4. The button's own height is what remains.
   Written after the shared rule above so it wins on equal specificity. */
/* -4px, not 1px: this margin COLLAPSES with the panel's own +5px top margin, and a collapsed pair
   is max(positives) + min(negatives) — so 5 + (-4) leaves the 1px of air the 44px total needs. */
.mil-hint-row.gap-keep{margin-bottom:-4px}
.mil-hint-btn{
  display:inline-flex;align-items:center;gap:8px;
  background:linear-gradient(135deg,#f5e6b8,#e8d5a0);color:#6B1E2E;
  border:2px solid #c9a550;border-radius:12px;padding:9px 15px;cursor:pointer;
  font-family:var(--font-display,'Britannic Bold',serif);font-size:13px;
  letter-spacing:.05em;text-transform:uppercase;
  animation:milHintGlow 1.4s ease-in-out infinite;
}
.mil-hint-btn:active{transform:translateY(1px)}
.mil-hint-bang{
  display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:20px;height:20px;border-radius:50%;background:#6B1E2E;color:#f5e6b8;
  font-size:13px;font-weight:700;line-height:1;
}
@keyframes milHintGlow{
  0%,100%{box-shadow:0 0 0 0 rgba(201,165,80,.25),0 2px 8px rgba(0,0,0,.3)}
  50%{box-shadow:0 0 8px 2px rgba(245,230,184,.5),0 2px 8px rgba(0,0,0,.3)}
}
/* Hint reveal — white card, bordeaux text, dismissed by its OK button (no auto-hide). */
#milHintModal{position:fixed;inset:0;z-index:400;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.35);}
.mil-hint-card{
  background:#fff;color:#6B1E2E;border:2px solid #c9a550;border-radius:14px;
  padding:20px 22px 16px;max-width:78vw;width:340px;text-align:center;
  box-shadow:0 8px 32px rgba(0,0,0,.4);
}
/* Hint header band — same dress as the centre hint card (cream INDICE on the bordeaux gradient). */
.mil-hint-head{margin:-20px -22px 14px;background:linear-gradient(135deg,#5e0c23,#8a1538);color:#e8d5a0;font-family:var(--font-display);font-size:15px;letter-spacing:3px;text-transform:uppercase;padding:9px 14px;border-bottom:2px solid #c9a550;border-radius:12px 12px 0 0}
.mil-hint-msg{font-size:14px;line-height:1.5;}
.mil-hint-ok{
  margin-top:14px;padding:8px 32px;cursor:pointer;
  background:#6B1E2E;color:#f5e6b8;border:none;border-radius:10px;
  font-family:var(--font-display,'Britannic Bold',serif);font-size:13px;
  letter-spacing:.08em;text-transform:uppercase;
}
.mil-hint-ok:active{transform:translateY(1px)}
/* Wheel «Un autre millésime» zone: when the year is on the wheel the zone is click-blocked
   (handleZoneClick + toast) but keeps its normal look — no dimming (user request 2026-08-06). */
/* Some board-art files drift a hair inside their canvas, leaving thin white slivers of the art's
   own background at the rim. Clip the IMG a fraction tighter than the .bw crop circle so the
   slivers fall outside; the click zones and tokens keep their full geometry (no realignment). */
#gameboard{clip-path:circle(49.3% at 50% 50%)}
.overlay{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}
.overlay svg{position:absolute;top:0;left:0;width:100%;height:100%}
.zone{fill:transparent;stroke:transparent;cursor:pointer;pointer-events:all;transition:fill 0.12s}
@media (hover: hover){.zone:hover{fill:rgba(201,165,80,0.18);stroke:rgba(201,165,80,0.4);stroke-width:8}}
.zone.active{fill:rgba(201,165,80,0.35);stroke:#c9a550;stroke-width:10}
.ch-hit{fill:rgba(255,255,255,0.01);stroke:rgba(201,165,80,0.25);stroke-width:3;stroke-dasharray:8,4;cursor:pointer;pointer-events:all;transition:all 0.12s}
@media (hover: hover){.ch-hit:hover{fill:rgba(201,165,80,0.2);stroke:rgba(201,165,80,0.7)}}
.ch-hit.active-ch{fill:rgba(201,165,80,0.15);stroke:#c9a550;stroke-dasharray:none}
.ch-hl{fill:rgba(201,165,80,0.28);stroke:#c9a550;stroke-width:9;pointer-events:none}
.tokens-layer{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}
/* Pinch-zoom reset pill (wm-board-zoom.js): appears only while the wheel is zoomed. A SIBLING of
   .bw inside .wrap (the whole wheel transforms — anything inside would scale with it); the zoom
   module pins its `top` over the wheel's foot from layout metrics. z-index above the panel (2). */
.bw-zoom-reset{position:absolute;left:50%;transform:translateX(-50%);z-index:20;display:none;padding:7px 16px;background:rgba(255,255,255,0.94);border:1.5px solid #c9a550;border-radius:20px;color:#5e0c23;font-family:var(--font-display);font-size:12.5px;letter-spacing:1.2px;text-transform:uppercase;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,0.35);cursor:pointer}
.bw.bw-zoomed + .bw-zoom-reset{display:block}
.bw-zoom-reset:active{transform:translateX(-50%) scale(0.92)}
/* The zoomed wheel spills over its layout slot; a transform lifts .bw into the positioned paint
   layer, which would put the spill ON TOP of the in-flow blocks below. Everything under the
   wheel answers with its own layer, so the spill slides UNDER the panel and the hint rows. */
.panel,.mil-hint-row,.atypical-warn{position:relative;z-index:2}
.token{position:absolute;width:6%;transform:translate(-50%,-50%);pointer-events:none;filter:drop-shadow(0 2px 5px rgba(0,0,0,0.6));animation:td 0.32s cubic-bezier(.3,.7,.4,1);background:transparent!important;border:none!important;outline:none!important}   /* 0.2→0.32s: the drop reads as a drop now (2026-08-30, keyframes in animations.css) */
/* margin-top 12→5px (requested 2026-08-31, "−30 %"): the visible gap is this margin PLUS the
   board art's own bordeaux margin inside its square canvas (~3–4 % of the wheel's width, i.e.
   11–14px on a phone), so the whole 23–26px gap shrinks by roughly a third. */
.panel{background:#fff;border-radius:14px;padding:14px;margin-top:5px;border:2.5px solid #c9a550;box-shadow:0 0 0 1px rgba(201,165,80,0.15),0 4px 20px rgba(0,0,0,0.3)}
/* «Comment jouer ?» — the rules button standing where the edition title used to (2026-08-30). */
.ptitle-howto{display:inline-flex;align-items:center;gap:8px;padding:7px 14px 7px 8px;background:#fdf8f0;border:1.5px solid #c9a550;color:#8a6a20;font-family:'Helvetica Neue',Arial,sans-serif;font-size:11px;font-weight:700;letter-spacing:1.2px;text-transform:uppercase;cursor:pointer;box-shadow:none!important}
.ptitle-howto:active{background:#f7eed9}
.ptitle-howto-q{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:#5e0c23;color:#e8d5a0;font-size:12px;font-weight:700;flex:none}
/* The rules panel: backdrop + a cream sheet sliding in from the LEFT (vintage-panel pattern). */
#howtoPanel{position:fixed;inset:0;z-index:340;pointer-events:none}
#howtoPanel .howto-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.45);opacity:0;transition:opacity .25s}
#howtoPanel .howto-sheet{position:absolute;top:0;bottom:0;left:0;width:min(330px,88vw);background:#fdf8f0;box-shadow:4px 0 24px rgba(0,0,0,.5);transform:translateX(-105%);transition:transform .28s cubic-bezier(.3,1,.4,1);display:flex;flex-direction:column;padding:calc(14px + env(safe-area-inset-top,0px)) 16px calc(14px + env(safe-area-inset-bottom,0px))}
#howtoPanel.open{pointer-events:auto}
#howtoPanel.open .howto-backdrop{opacity:1}
#howtoPanel.open .howto-sheet{transform:translateX(0)}
.howto-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;flex:0 0 auto}
.howto-title{font-family:var(--font-display);font-size:17px;letter-spacing:1.5px;text-transform:uppercase;color:#5e0c23}
.howto-close{background:none;border:1.5px solid #c9a550;color:#8a6a20;width:32px;height:32px;font-size:16px;line-height:1;cursor:pointer;flex:0 0 auto;box-shadow:none!important;padding:0}
.howto-body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;font-size:13.5px;line-height:1.6;color:#3a2a12;font-family:'Helvetica Neue',Arial,sans-serif}
.howto-body p{margin:0 0 10px}
.howto-body ol{margin:0 0 10px;padding-left:20px}
.howto-body li{margin-bottom:9px}
.howto-body strong{color:#5e0c23}
.ptop{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;padding-bottom:9px;border-bottom:1px solid rgba(201,165,80,0.25)}
/* Title + token count each break at the \n baked into their i18n strings ("Wine Me Casino\nVersion
   France" / "Monocépage\n4 jetons"); the token side is right-aligned as a block. */
.ptitle{font-size:11px;letter-spacing:2.5px;text-transform:uppercase;color:#888;font-weight:700;font-family:var(--font-display);white-space:pre-line;line-height:1.5}   /* air between the WINE ME line and ÉDITION … — 1.8 read too loose, 1.5 (user-tuned 2026-08-25) */
.pjt{font-size:11px;color:#c9a550;font-weight:700;letter-spacing:1px;white-space:pre-line;text-align:right;flex-shrink:0}
.toggle{display:flex;gap:6px;margin-bottom:11px}
.tbtn{flex:1;padding:7px 4px;border:1px solid #e8e8e8;border-radius:8px;font-size:10.5px;letter-spacing:1px;text-transform:uppercase;cursor:pointer;text-align:center;color:#bbb;background:#fff;transition:all .12s;font-family:var(--font-display)}
.tbtn.on{background:#6B1E2E;border-color:#6B1E2E;color:#fff}
.slots{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-bottom:10px}
.slot{position:relative;padding:6px 9px;border:1px solid #f0f0f0;border-radius:8px;min-height:40px;transition:all .15s}
.slot.filled{border-color:#c9a550;background:rgba(201,165,80,.04)}
.slot.cheval{border-color:#c9a550;border-style:dashed;background:rgba(201,165,80,.04)}
/* VdF round: the region slot is a fixed, non-editable "Vin de France" plate — no region bet.
   pointer-events:none also disables the GB info chip (region isn't scored this round). */
.slot.vdf-locked{border-style:dashed;border-color:#c9a550;background:rgba(201,165,80,.07);pointer-events:none}
.slot.vdf-locked .sval{color:#a3893f;font-style:italic}
.slot.missing{border-color:#ae182b;border-width:1.5px;background:rgba(174,24,43,.06);animation:slotPulse .55s ease-in-out 2}
@keyframes slotPulse{0%,100%{box-shadow:0 0 0 0 rgba(174,24,43,0)}50%{box-shadow:0 0 0 5px rgba(174,24,43,.22)}}
.slot-inner{display:flex;justify-content:space-between;align-items:center}
.slbl{font-size:9.5px;letter-spacing:1.2px;text-transform:uppercase;color:#999;font-weight:600;margin-bottom:3px;padding-right:30px}
.gb-info-btn{position:absolute;top:5px;right:7px;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background:transparent;color:#5e0c23;font-size:10px;font-weight:700;letter-spacing:0.3px;cursor:pointer;font-family:var(--font-display);border:1.5px solid #e8d5a0;transition:transform .15s,border-color .15s,background .15s;line-height:1;z-index:2}
@media (hover: hover){.gb-info-btn:hover{border-color:#c9a550;background:rgba(232,213,160,0.18)}}
.gb-info-btn:active{transform:scale(0.9)}
/* GB info modal */
.gb-info-overlay{position:fixed;inset:0;background:rgba(40,5,15,0.78);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:340;display:none;align-items:center;justify-content:center;padding:20px}
.gb-info-overlay.open{display:flex}
.gb-info-card{position:relative;background:#fff;border-radius:16px;padding:24px 22px 18px;max-width:340px;width:100%;border:2px solid #c9a550;box-shadow:0 12px 40px rgba(0,0,0,0.45);text-align:center}
.gb-info-close{position:absolute;top:6px;right:14px;font-size:24px;color:#999;cursor:pointer;line-height:1;padding:4px}
@media (hover: hover){.gb-info-close:hover{color:#5e0c23}}
.gb-info-bills{position:relative;height:80px;margin:18px 0 32px;display:flex;justify-content:center;align-items:center}
.gb-info-bills img{position:absolute;height:54px;width:auto;filter:drop-shadow(0 3px 8px rgba(0,0,0,0.22));transition:transform .25s}
.gb-info-bills img:nth-child(1){transform:rotate(-14deg) translate(-40px,6px);z-index:1}
.gb-info-bills img:nth-child(2){transform:rotate(0deg) translateY(-2px);height:62px;z-index:3}
.gb-info-bills img:nth-child(3){transform:rotate(14deg) translate(40px,6px);z-index:2}
.gb-info-title{font-family:var(--font-display);font-size:17px;color:#5e0c23;letter-spacing:1.5px;margin-bottom:8px;text-transform:uppercase}
.gb-info-body{font-size:12.5px;color:#444;line-height:1.5;text-align:left;margin-bottom:14px}
.gb-info-body .row{display:flex;justify-content:space-between;align-items:baseline;padding:8px 0;border-bottom:1px dotted #eadcb8;gap:10px}
.gb-info-body .row:last-of-type{border-bottom:none}
.gb-info-body .row .label{font-size:10.5px;letter-spacing:1.5px;text-transform:uppercase;color:#5e0c23;font-weight:700;flex:1;font-family:inherit}
.gb-info-body .row .val{color:#3B6D11;font-weight:700;font-family:var(--font-display);letter-spacing:0.8px;white-space:nowrap;font-size:16px}
.gb-info-body .note{font-size:11px;color:#888;margin-top:10px;line-height:1.45;padding:8px 10px;background:#fdf8f0;border-left:2px solid #c9a550;border-radius:4px}
.gb-info-ok{display:block;margin:0 auto;padding:10px 36px;background:linear-gradient(135deg,#5e0c23,#8a1538);color:#e8d5a0;border:2px solid #e8d5a0;border-radius:10px;font-size:13px;font-family:var(--font-display);letter-spacing:1.5px;cursor:pointer;text-align:center;transition:transform .15s}
.gb-info-ok:active{transform:scale(0.96)}
.sval{font-size:12px;color:#6B1E2E;font-weight:600;line-height:1.3;letter-spacing:0.8px}
.cbadge{font-size:9px;color:#c9a550;background:rgba(201,165,80,0.12);padding:1px 4px;border-radius:3px;margin-left:3px;letter-spacing:0.5px}
.sx{font-size:16px;color:#ddd;cursor:pointer;line-height:1;margin-left:4px;flex-shrink:0}
@media (hover: hover){.sx:hover{color:#c9a550}}
.divider{height:1px;background:rgba(201,165,80,0.2);margin:0 0 10px}
.btns{display:flex;gap:7px}
.btn{flex:1;padding:10px;border-radius:9px;font-size:10.5px;letter-spacing:2px;text-transform:uppercase;cursor:pointer;border:1px solid #e5e5e5;background:#fff;color:#bbb;transition:all .15s;font-family:inherit;display:flex;align-items:center;justify-content:center;line-height:1;text-align:center}
@media (hover: hover){.btn:hover{border-color:#c9a550;color:#6B1E2E}}
.btn:active{transform:scale(0.93);box-shadow:0 1px 6px rgba(0,0,0,0.2)}
.btngo{background:#6B1E2E;border:2px solid #c9a550;color:#fff;font-weight:600;font-family:var(--font-display)}
/* All required bets placed → golden waves (like the mystery-bottle pulse) telling the player this
   button closes the round. Toggled by refresh() in bets.js; removed once bets lock. */
.btngo.ready{position:relative;z-index:2;animation:btngoReadyPulse 1.4s ease-in-out infinite}
@keyframes btngoReadyPulse{0%,100%{box-shadow:0 0 0 0 rgba(201,165,80,0.65)}50%{box-shadow:0 0 0 12px rgba(201,165,80,0)}}
@media (hover: hover){.btngo:hover{background:#5a1828;color:#e8d5a0}}
.btngo:active{transform:scale(0.93);box-shadow:0 2px 8px rgba(0,0,0,0.3)}
.st{font-size:10.5px;letter-spacing:2px;color:#c9a550;text-align:center;margin-top:8px;min-height:13px;text-transform:uppercase}
.st.err{color:#ae182b;font-weight:700;font-size:11.5px}
.hint{font-size:10px;color:#6B1E2E;text-align:center;margin-top:5px;letter-spacing:0.5px}
/* ===== Table board (2026-08-31) — replaces the hint line in a multiplayer round =====
   The roster of the table: the croupier first, then the players, each with a presence dot and,
   once they tap "Rien ne va plus", a MISES FAITES chip. Fed by the /players listener room.js
   already keeps open for the lobby (renderTableBoard). Solo rounds keep the hint instead. */
.table-board{margin-top:8px;border-top:1px solid #f0e6d2;padding-top:7px}
.tb-title{font-size:9.5px;letter-spacing:2px;text-transform:uppercase;color:#b09060;text-align:center;margin-bottom:5px}
.tb-row{display:flex;align-items:center;gap:7px;padding:3px 2px;font-size:12.5px;color:#5e0c23;min-height:22px}
.tb-row + .tb-row{border-top:1px solid #faf3e6}
.tb-row.tb-off{opacity:0.45}
.tb-dot{width:8px;height:8px;border-radius:50%;background:#3B6D11;flex:none;box-shadow:0 0 0 2px rgba(59,109,17,0.16)}
.tb-row.tb-off .tb-dot{background:#c2c2c2;box-shadow:none}
.tb-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.tb-me{color:#8b5e1a}
.tb-tag{font-size:8.5px;letter-spacing:1px;text-transform:uppercase;padding:2px 7px;border-radius:999px;flex:none;line-height:1.4}
.tb-tag-host{background:#5e0c23;color:#e8d5a0}
.tb-tag-off{background:#ececec;color:#8a8a8a}
/* The "bets are in" chip — pushed to the right edge so the eye reads the column at a glance. */
.tb-tag-bets{margin-left:auto;background:linear-gradient(135deg,#f5e6b8,#e8d5a0);color:#6B1E2E;border:1px solid #c9a550;font-weight:700}
/* Sidebar Drawer */
.sb-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:90;touch-action:none}   /* dead overlay: a tap closes, a drag must not scroll the board behind */
.sb-backdrop.open{display:block}
/* touch-action:pan-y — the drawer has no horizontal scrolling of its own, so iOS chained a
   one-finger horizontal swipe THROUGH it into the page scroller underneath and the board slid
   behind the card (video 2026-08-26). pan-y keeps vertical scrolling inside the drawer and hands
   horizontal travel to nothing; the JS tab-swipe still works — touch-action only disables native
   scrolling, not the touch events. overscroll-behavior:contain stops the vertical chain at the
   drawer's ends the same way. */
/* The background is split bordeaux-over-cream instead of plain cream (video 2026-08-31): the
   header scrolls WITH the content, so iOS' rubber-band at the top slid it down and flashed the
   drawer's own cream through the status-bar strip — an ugly white band above the dark header.
   A scroller's background does not scroll, so the top half now paints the top overscroll in the
   header's own bordeaux (and the bottom half keeps the bottom overscroll cream). The bordeaux is
   a LEFT-TO-RIGHT ramp because that is what the header's 135deg gradient looks like along its top
   edge — the revealed strip continues it seamlessly. Every child that sits over the split must be
   opaque — .sb-header, .sb-tabs and .sb-panel all are. */
.sb-drawer{position:fixed;top:0;right:0;height:100%;width:min(320px,88vw);background:linear-gradient(90deg,#5d1519 0%,#431012 100%) top/100% 50% no-repeat,#fdf8f0;border-left:2.5px solid #c9a550;z-index:100;transform:translateX(100%);transition:transform 0.32s cubic-bezier(.4,0,.2,1);overflow-y:auto;touch-action:pan-y;overscroll-behavior:contain;display:flex;flex-direction:column;box-shadow:-6px 0 32px rgba(0,0,0,0.25)}
.sb-drawer.open{transform:translateX(0)}
.sb-header{background:linear-gradient(135deg,#5d1519 0%,#3a0d11 100%);padding:14px 16px 12px;display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-shrink:0}
.sb-title-wrap{flex:1}
.sb-name{font-size:16px;letter-spacing:2px;text-transform:uppercase;color:#f5e8c8;line-height:1.2;font-family:var(--font-display)}
/* RU: Cyrillic transliteration of the grape under the Latin name (see setSbGrapeName). */
.sb-name-ru{display:block;font-size:12px;letter-spacing:1.5px;color:#d9c290;margin-top:2px}
.sb-subtitle{font-size:8.5px;letter-spacing:1.5px;color:#c9a550;text-transform:uppercase;margin-top:3px}
.sb-dot{width:16px;height:16px;border-radius:50%;flex-shrink:0;margin-top:2px}
.sb-dot.red{background:#ae182b;border:2px solid rgba(201,165,80,0.5)}
.sb-dot.white{background:#e9dc81;border:2px solid rgba(201,165,80,0.5)}
.sb-dot.pink{background:#e8a0b4;border:2px solid rgba(201,165,80,0.5)}
.sb-close{font-size:24px;color:#c9a550;cursor:pointer;line-height:1;flex-shrink:0;padding:0 0 4px 8px}
/* Tabs */
.sb-tabs{display:flex;border-bottom:2px solid #e0c878;flex-shrink:0;background:#faf3e0}
.sb-tab{flex:1;padding:10px 6px;font-size:12px;letter-spacing:1.5px;text-transform:uppercase;color:#b09060;cursor:pointer;text-align:center;border-bottom:3px solid transparent;transition:all 0.2s;margin-bottom:-2px}
.sb-tab.active{color:#8b5e1a;border-bottom-color:#c9a550;font-weight:bold;background:#fdf8f0}
/* Tab content */
/* The ⇄ swipe hint — a big arrow at the drawer's bottom centre (user-placed 2026-08-25). Last
   flex child: margin-top:auto parks it at the foot when content is short, position:sticky rides
   it above long content while scrolling. pointer-events:none — it's a hint, not a control.
   Hidden on the sparkling / regional cards, whose tab bar (and swipe) doesn't exist. */
.sb-swipe-hint{position:sticky;bottom:72px;align-self:center;margin-top:auto;padding:2px 0 0;color:#5e0c23;font-size:40px;line-height:1;opacity:.5;pointer-events:none;text-shadow:0 1px 3px rgba(255,255,255,0.8)}   /* bordeaux, bigger; bottom 26→72px — clear of the home-indicator zone (user-tuned 2026-08-25, raised 2026-08-30) */
.sb-drawer.sb-sparkling .sb-swipe-hint,.sb-drawer.sb-regional-card .sb-swipe-hint{display:none}
/* Opaque on purpose — it covers the drawer's bordeaux/cream split (see .sb-drawer). */
.sb-panel{display:none;padding:14px 16px 20px;flex:1;background:#fdf8f0}
.sb-panel.active{display:block;animation:sbPanelIn .22s ease}
@keyframes sbPanelIn{from{opacity:.35;transform:translateX(10px)}to{opacity:1;transform:none}}
/* Cépage image */
.sb-cepage-img{width:90px;height:auto;display:block;margin:0 auto 12px}
/* Cépage ID styles - beige/gold theme */
.mc-section{margin-bottom:13px}
.mc-slbl{font-size:11px;letter-spacing:2px;text-transform:uppercase;color:#8b5e1a;margin-bottom:6px;font-weight:bold}
.mc-text{font-size:13px;line-height:1.5;color:#3d2b10;font-family:'Helvetica Neue',Arial,sans-serif}
.mc-bar-row{display:flex;align-items:center;margin-bottom:7px;gap:8px}
.mc-bar-name{font-size:11.5px;color:#7a5c2a;letter-spacing:0.5px;width:60px;flex-shrink:0;font-family:'Helvetica Neue',Arial,sans-serif;font-style:italic}
.mc-bar-track{position:relative;flex:1 1 auto;height:7px;background:rgba(180,140,60,0.15);border-radius:3px;overflow:hidden;min-width:60px}
.mc-bar-fill{position:absolute;left:0;top:0;height:100%;border-radius:3px;transition:width 0.5s ease}
.mc-bar-fill-light{position:absolute;left:0;top:0;height:100%;border-radius:3px;opacity:0.38;transition:width 0.5s ease}
.mc-bar-fill.red{background:linear-gradient(90deg,#ae182b,#d42035)}
.mc-bar-fill.teal{background:linear-gradient(90deg,#c9a550,#e8c870)}
/* Intensity text next to each bar. Long phrases ("От низких до средних", "Medium to full-bodied",
   "Mittel bis kräftig") wrap to two lines instead of being clipped with an ellipsis. */
.mc-bar-label{font-size:10px;color:#1a1a1a;font-style:italic;letter-spacing:0.2px;flex:0 0 92px;text-align:left;line-height:1.2;overflow-wrap:break-word}
/* Russian grape-profile labels ("Кислотность") are longer than FR/EN/etc — widen the name column
   for RU only so it shows in full and the bars + intensity words shift right accordingly. */
html[lang="ru"] .mc-bar-name{width:88px}
.mc-colors{display:flex;gap:5px;flex-wrap:wrap}
.mc-color-chip{padding:3px 10px;border-radius:10px;font-size:8px;letter-spacing:0.5px;background:#f0e6c8;color:#7a5c2a;font-family:'Helvetica Neue',Arial,sans-serif;border:1px solid #d4b06a}
.mc-divider{height:1px;background:linear-gradient(90deg,transparent,#c9a550,transparent);margin:10px 0;opacity:0.4}
/* Région styles - beige/gold theme */
.rg-card{background:#fffdf7;border:1px solid #e0c878;border-radius:10px;padding:11px 13px;margin-bottom:10px;box-shadow:0 1px 6px rgba(180,140,60,0.1)}
.rg-name{font-size:13px;letter-spacing:1.5px;text-transform:uppercase;color:#8b5e1a;margin-bottom:6px;font-weight:bold}
.rg-section-title{font-size:12px;letter-spacing:1.5px;text-transform:uppercase;color:#8b5e1a;font-weight:bold;margin:0 0 10px}
.rg-terroir-note{font-style:italic;font-size:11px;color:#b09060;line-height:1.4;margin:2px 2px 8px}
/* Atypical grape↔region/country note atop the Regions tab (echoes the on-board banner). */
.rg-atypical-note{
  background:#fff7e0;border:1.5px solid #e0a72c;border-radius:10px;
  color:#8a4b00;font-size:12px;line-height:1.4;font-weight:600;
  padding:8px 12px;margin:0 2px 12px;text-align:center;
}
.rg-atypical-note::before{content:"\26A0";margin-right:6px;font-weight:700}
.rg-row{display:flex;gap:6px;margin-bottom:4px;align-items:flex-start}
/* Rose region cards split mono-cépage / assemblage / style / particularités into labeled blocks. */
.rg-block{margin-top:9px}
.rg-block:first-of-type{margin-top:0}
.rg-sublabel{font-size:11px;letter-spacing:1.4px;text-transform:uppercase;color:#8b5e1a;font-weight:700;margin-bottom:3px;opacity:0.95}
/* Bold italic prefix in Assemblage — black, separates partners from appellations. */
.rg-assemblage-prefix{color:#3d2b10;font-style:italic;font-weight:700}
/* Particularités: each appellation on its own line for easier scanning. */
.rg-particularite-item{margin-bottom:4px;font-size:12px;color:#3d2b10;line-height:1.4}
.rg-particularite-item:last-child{margin-bottom:0}
/* Assemblage partners (sidebar Cépage tab): one cépage per line, frequency notes in italic. */
.rg-partner-item{font-size:12px;color:#3d2b10;line-height:1.5;margin-bottom:2px}
.rg-partner-item em{color:#8b6e3a;font-style:italic;font-weight:400}
/* Cépage Rosé: hide jeune/évolué scaffolding, show the rose-only assemblage section. */
.mc-rose-only{display:none}
.sb-drawer.cepage-rose .mc-evol-row{display:none}
.sb-drawer.cepage-rose .mc-evol-prefix{display:none}
.sb-drawer.cepage-rose .mc-rose-only{display:block}
/* Sparkling sector cards: hide the cépage tabs/panels, show the dynamic sparkling panel. */
.sb-drawer.sb-sparkling .sb-tabs,
.sb-drawer.sb-sparkling #panelCepage,
.sb-drawer.sb-sparkling #panelRegion{display:none}
.sb-drawer.sb-sparkling #panelSparkling{display:block}
/* Régional custom cards (AOC-level hints / other grapes): hide tabs + standard panels. */
.sb-drawer.sb-regional-card .sb-tabs,
.sb-drawer.sb-regional-card #panelCepage,
.sb-drawer.sb-regional-card #panelRegion,
.sb-drawer.sb-regional-card #panelSparkling{display:none}
.sb-drawer.sb-regional-card #panelRegionalCard{display:block;padding:16px 15px}
.sb-dot.sparkling{background:linear-gradient(180deg,#e8d5a0,#c9a550);border:2px solid rgba(201,165,80,0.5)}
/* Country / dosage overview: the tapped sector's card highlighted among the full ring list. */
.rg-card.spark-active{border:2px solid #c9a550;background:#fbf3dd;box-shadow:0 2px 10px rgba(201,165,80,0.28)}
.rg-emoji{font-size:11px;flex-shrink:0;line-height:1.4}
.rg-val{font-size:12px;color:#3d2b10;line-height:1.4;font-family:'Helvetica Neue',Arial,sans-serif}
/* Espagne region cards: the "blind tasting clue" is lifted out of the paragraph into a burgundy
   callout box so it stands out at a glance; .bt-clue keeps its label emphatic inside the box. */
.rg-val .bt-clue{color:#5e0c23}
.bt-clue-box{margin-top:9px;padding:8px 11px;background:#f7e8eb;border-left:3px solid #5e0c23;border-radius:0 7px 7px 0;font-size:12px;line-height:1.5;color:#4a1522;font-family:'Helvetica Neue',Arial,sans-serif}
.bt-clue-box .bt-clue{color:#5e0c23;letter-spacing:0.3px}
/* Régional (Bourgogne) — per-AOC-level tasting notes on the Cépage tab */
.aoc-lv{background:#fffdf7;border:1px solid #e0c878;border-radius:8px;padding:9px 11px;margin-top:8px}
.aoc-lv-name{font-size:12px;letter-spacing:1px;text-transform:uppercase;color:#8b5e1a;font-weight:bold;margin-bottom:3px}
.aoc-lv-impr{font-size:11.5px;font-style:italic;color:#6b4e1a;margin-bottom:5px}
.aoc-lv-row{font-size:12px;line-height:1.45;color:#3d2b10;margin-top:3px;font-family:'Helvetica Neue',Arial,sans-serif}
.aoc-lv-k{color:#8b5e1a;font-weight:600}
.aoc-remarque{font-size:11.5px;font-style:italic;line-height:1.5;color:#6b4e1a}
/* Framed "profile varies with AOC level" note on the grape card */
.aoc-vary-note{font-size:11.5px;font-style:italic;line-height:1.5;color:#6b4e1a;background:#fbf3dc;border:1px solid #dcc079;border-radius:8px;padding:8px 11px}
/* Standard-profile disclaimer at the foot of the AOC-level card */
.aoc-profile-note{font-size:11px;font-style:italic;line-height:1.5;color:#8b6e3a;margin-top:10px;padding-top:8px;border-top:1px solid #e0c878;opacity:0.85}
/* Bordeaux zone cards: the grape's role in the zone — a prominent lead-in above the Flagship AOC box */
.appel-role{font-size:14.5px;line-height:1.45;color:#4a3210;margin:2px 0 8px}
.appel-list{margin:4px 0 0;padding-left:17px;list-style:disc}
.appel-list li{font-size:12px;line-height:1.5;color:#3d2b10;font-family:'Helvetica Neue',Arial,sans-serif}
/* Régional: the region-wide "Bourgogne Régional" box, set apart from the sous-régions above it. */
.rg-card-regional{background:#f7edd4;border:1.5px solid #c9a550}
.rg-chip-row{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.rg-chip{padding:2px 7px;border-radius:8px;font-size:8px;background:#f5e8b8;color:#7a5218;font-family:'Helvetica Neue',Arial,sans-serif;letter-spacing:0.5px;border:1px solid #d4b06a}
/* 50/50 — the two candidates keep their normal look (plain zones: full board colour, normal hover
   and the .active bet highlight); every OTHER grape in the ring is darkened so the choice reads by
   contrast. Deliberately NO rule for .highlighted-5050 — an !important fill there would suppress the
   .active highlight when a token is placed on a candidate. */
.zone.dimmed-5050{fill:rgba(6,3,7,0.66)!important;stroke:transparent!important;cursor:not-allowed!important}
@media (hover: hover){.zone.dimmed-5050:hover{fill:rgba(6,3,7,0.66)!important;stroke:transparent!important;stroke-width:0!important}}
/* Timer expired — gray out the board + bet slots; only Rien ne va plus stays clickable & vivid. */
body.timer-expired-mode .bw{filter:grayscale(1) brightness(0.65);pointer-events:none;transition:filter .3s}
body.timer-expired-mode .panel .slots,
body.timer-expired-mode .panel .toggle,
body.timer-expired-mode .panel .ptop,
body.timer-expired-mode .panel .hint,
body.timer-expired-mode .panel .divider,
body.timer-expired-mode .panel #st,
body.timer-expired-mode .btn:not(.btngo){filter:grayscale(1);opacity:0.45;pointer-events:none;transition:filter .3s,opacity .3s}
body.timer-expired-mode .btngo{position:relative;z-index:2;animation:btngoPulse 1.4s ease-in-out infinite;box-shadow:0 0 0 0 rgba(232,213,160,0.6)}
@keyframes btngoPulse{0%,100%{box-shadow:0 0 0 0 rgba(232,213,160,0.55)}50%{box-shadow:0 0 0 6px rgba(232,213,160,0)}}
/* Host Observation Panel */
.host-overlay{position:fixed;inset:0;background:#5e0c23;z-index:200;display:none;flex-direction:column;overflow-y:auto}
.host-overlay.open{display:flex}
.host-top{padding:24px 16px 8px;text-align:center}   /* nothing is pinned above any more — the code plate moved into .host-ctrl-row */
.host-wine-title{font-family:var(--font-display);font-size:20px;color:#e8d5a0;letter-spacing:2px;margin-bottom:4px}
/* The characteristics always break onto TWO lines (renderHostWineDetail inserts the <br>), so the
   block reserves both — masking the wine collapses it to one row of dots and the panel below
   would otherwise jump. */
.host-wine-detail{font-size:12px;line-height:1.45;min-height:2.9em;color:#fff;margin-bottom:10px;font-family:'Helvetica Neue',Arial,sans-serif}
/* «Masquer le vin» — a quiet ghost pill under the answer line (2026-08-31). The croupier's screen
   carries the solution, and a neighbour's glance is all it takes to spoil the round. */
.host-wine-hide{background:transparent;border:1px solid rgba(232,213,160,0.45);color:#e8d5a0;border-radius:999px;padding:3px 12px;font-size:10px;letter-spacing:1.2px;text-transform:uppercase;font-family:'Helvetica Neue',Arial,sans-serif;cursor:pointer;margin-bottom:10px}
.host-wine-hide:active{background:rgba(232,213,160,0.12)}
/* Masked state: the dots ARE the text (renderHostWineDetail swaps it), so nothing readable is
   left in the DOM to un-blur or screenshot. */
.host-wine-detail.host-wine-masked{letter-spacing:3px;color:rgba(255,255,255,0.5)}
/* Timer + table miniature share one row as two columns (2026-08-31). Stacked, they ate the whole
   first screen and pushed the players cards under the fold — the one thing the croupier watches. */
/* Three fixed-ish columns on a phone: the gap and the INVITER label give way before anything is
   clipped. Measured at 320px, the widest label (RU ПРИГЛАСИТЬ) overflowed the header padding and
   the code plate ran off the left edge; flex-wrap is the last resort, dropping the timer to its
   own line rather than cutting a column in half. */
.host-ctrl-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:clamp(8px,3.5vw,14px);margin-bottom:8px}
/* Code plate in the row: the role screen dock, minus the standalone spacing it carries there,
   and it must not shrink — the 4 digits are the whole point of the plate. Scoped to the row so it
   OUTRANKS .room-code-dock, which is defined further down the file: its margin-bottom:22px was
   winning on source order and pushing the plate 11px above the other two columns. */
.host-ctrl-row .host-code-dock{flex:0 0 auto;margin-bottom:0;padding:8px 12px;min-width:0;align-self:stretch}
.host-code-col{display:flex;flex-direction:column;align-items:stretch;gap:9px;flex:0 0 auto;align-self:flex-end}
/* INVITER wears the timer buttons' pill so the row reads as one set of controls; uppercase comes
   from CSS, not the dictionary, so Пригласить / Einladen keep their natural case in the data. */
/* Scoped to the row so it OUTRANKS .host-timer-btn, whose pill it borrows: that rule is defined
   further down the file and was silently winning font-size and padding on source order (verified
   with getComputedStyle — the shrink below simply never applied). The label gives way before the
   row does: uppercase from CSS, not the dictionary, so Пригласить / Einladen keep natural case. */
.host-ctrl-row .host-invite-btn{text-transform:uppercase;white-space:nowrap;padding:6px clamp(6px,2.6vw,12px);font-size:clamp(9px,2.9vw,11px);letter-spacing:clamp(0px,0.25vw,1px)}
/* Both side columns hang from the BOTTOM of the row (requested 2026-08-31), so INVITER and RESET
   sit on one line however tall either column grows. Pinning BOTH rather than just the code column
   is what makes that hold: with only one pinned, the pair would align to whichever item is tallest
   — today the timer, but a bigger miniature would silently break it. The miniature stays centred. */
.host-timer-col{display:flex;flex-direction:column;align-items:center;gap:9px;align-self:flex-end}
/* PAUSE over RESET, stacked (user request 2026-08-31). Same min-width on both so the two pills
   line up as one block instead of sizing to their own labels — RESET is the shorter word in every
   language, and ragged edges read as a mistake next to the round table miniature. */
.host-timer-btns{display:flex;flex-direction:column;align-items:stretch;gap:8px}
.host-timer-btns .host-timer-btn{min-width:96px;text-align:center}
/* Table miniature + its blown-up view. The croupier plays no board, but he needs to SEE the one
   his table is looking at (2026-08-31). */
.host-board-thumb{display:block;width:101px;height:101px;flex:0 0 auto;margin:0;align-self:center;border-radius:50%;border:1.5px solid rgba(201,165,80,0.7);box-shadow:0 2px 10px rgba(0,0,0,0.35);cursor:pointer;background:#5d1519}
.host-board-thumb:active{transform:scale(0.94)}
/* touch-action:none — the pinch belongs to wm-board-zoom.js, not to iOS's own scroll/rubber-band
   underneath. overflow:hidden keeps a panned board from widening the page. */
.host-board-zoom{display:none;position:fixed;inset:0;z-index:260;background:rgba(40,6,16,0.94);align-items:center;justify-content:center;padding:16px;cursor:pointer;touch-action:none;overflow:hidden}
.host-board-zoom.open{display:flex}
.host-board-zoom img{width:100%;max-width:560px;height:auto;border-radius:50%;box-shadow:0 8px 40px rgba(0,0,0,0.5);transform-origin:0 0}
/* The way out at any zoom level: while zoomed a tap means "look here", so it must not close. */
.host-zoom-close{position:absolute;top:calc(12px + env(safe-area-inset-top,0px));right:14px;z-index:2;width:38px;height:38px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.94);border:1.5px solid #c9a550;color:#5e0c23;font-size:22px;line-height:1;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.35);touch-action:manipulation}
.host-zoom-close:active{transform:scale(0.92)}
.host-timer-display{font-family:var(--font-display);font-size:28px;color:#fff;letter-spacing:2px}
.host-timer-btn{padding:6px 14px;border-radius:8px;font-size:11px;font-family:var(--font-display);letter-spacing:1px;cursor:pointer;border:1.5px solid #e8d5a0;background:transparent;color:#e8d5a0;transition:all .15s}
.host-timer-btn:active{transform:scale(0.94)}
.host-timer-btn.running{background:#e8d5a0;color:#5e0c23}
.host-players-grid{flex:1;padding:8px 12px 20px;display:flex;flex-direction:column;gap:8px}
.host-player-card{background:#fff;border:1.5px solid #c9a550;border-radius:12px;padding:12px 14px;transition:border-color .3s}
.host-player-card.has-bets{border-color:#c9a550}
.host-player-card.complete{border-color:#3B6D11;background:#f4fbf0}
.host-player-name{font-family:var(--font-display);font-size:15px;color:#5e0c23;margin-bottom:6px;display:flex;align-items:center;gap:8px}
.host-player-status{font-size:9px;padding:2px 8px;border-radius:10px;letter-spacing:1px;font-family:'Helvetica Neue',Arial,sans-serif}
.host-status-waiting{background:#f0ebe3;color:#999}
.host-status-betting{background:#fdf3d7;color:#a67c00}
.host-status-done{background:#3B6D11;color:#fff;font-weight:700;border:1px solid #2e5a0d;box-shadow:0 1px 4px rgba(59,109,17,0.35)}   /* solid win-green: the croupier spots a locked player at a glance (was pale #e8f5e0) */
.host-bets-row{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
/* Filled and empty chips share the same boxed look so the row stays visually flat. The
   label is small grey; the value is bold bordeaux. An empty chip is told apart by its em dash
   in place of that bold value — not by a fainter label (see the grey note below). */
.host-bet-chip{font-size:10px;padding:3px 8px;border-radius:6px;background:#f0ebe3;border:1px solid #ddd;font-family:'Helvetica Neue',Arial,sans-serif;color:#5e0c23;font-weight:400}
/* One grey for every chip label, filled or not (2026-08-31). #888 measured 2.99:1 on the chip's
   #f0ebe3 and #bbb a hopeless 1.62:1 — at 10px that is not quiet, it is unreadable. #666 is
   4.84:1, WCAG AA. Both states share it on purpose: darkening only the empty chips would have
   made the player who has bet NOTHING read louder than the one who has bet. */
.host-bet-chip .hb-label{text-transform:none;font-weight:400;color:#666;letter-spacing:0.3px}
.host-bet-chip .hb-val{font-weight:700;color:#5e0c23;text-transform:uppercase;letter-spacing:0.5px}
.host-bet-chip.empty{color:#666}
.host-bet-chip.empty .hb-label{color:#666}
.host-reveal-btn{display:block;width:calc(100% - 32px);margin:0 16px 10px;padding:16px;background:linear-gradient(135deg,#fdf8f0,#f5e6b8);color:#5e0c23;border:2px solid #c9a550;border-radius:12px;font-size:16px;font-family:var(--font-display);letter-spacing:2px;cursor:pointer;text-align:center;transition:transform .15s,box-shadow .15s}
.host-reveal-btn:active{transform:scale(0.94);box-shadow:0 2px 8px rgba(0,0,0,0.3)}
.host-reveal-btn:disabled{opacity:0.4;cursor:default}
/* All players locked their bets → the reveal button glows with golden waves (set by renderHostPlayers)
   AND a gold arrow bobs above it, pointing down at the button (user request 2026-08-24). */
.host-reveal-btn.host-reveal-ready{position:relative;z-index:2;border-color:#c9a550;animation:btngoReadyPulse 1.4s ease-in-out infinite}
/* The "everyone has confirmed" arrow: 28→36px and lifted from -40 to -52px, so it reads as a
   sign and no longer crowds the button it points at (requested 2026-08-31). The bob keeps a
   9px travel, which still leaves air at the bottom of its swing. */
.host-reveal-btn.host-reveal-ready::before{content:'↓';position:absolute;top:-52px;left:50%;font-family:'Helvetica Neue',Arial,sans-serif;font-size:36px;font-weight:700;line-height:1;color:#e8d5a0;text-shadow:0 2px 6px rgba(0,0,0,0.45);pointer-events:none;animation:hostArrowBob 1s ease-in-out infinite}
@keyframes hostArrowBob{0%,100%{transform:translate(-50%,0)}50%{transform:translate(-50%,9px)}}
/* Timer */
.game-exit-btn{display:none;padding:10px 24px;border-radius:8px;background:transparent;border:none;color:#999;font-size:12px;font-family:inherit;cursor:pointer;letter-spacing:0.5px}
/* "Terminer la partie" on the results screen — reads as a real (but muted) button: grey caps in
   a grey frame. Applied on top of .game-exit-btn (see resetResultsBottomBar). */
.res-end-btn{text-transform:uppercase;letter-spacing:1.5px;font-size:11px;font-weight:600;color:#999;border:1.5px solid #c6c6c6;border-radius:10px;padding:11px 20px}
.game-exit-btn:active{opacity:0.6}
/* height 42px = the code badge's height (below): the two pills share the top line of the board
   page and must read as ONE row (requested 2026-08-25). */
.timer-widget{position:fixed;left:10px;top:10px;height:42px;box-sizing:border-box;display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;z-index:50;background:#ffffff;border:1.5px solid #c9a550;border-radius:10px;padding:4px 10px 4px 8px;box-shadow:0 2px 8px rgba(0,0,0,0.15)}
/* Multiplayer guests can't control the timer (only the host) — show it as a read-only display. */
.timer-widget.timer-readonly{cursor:default}
/* z-index 260 keeps the badge above .host-overlay (200) and .results-overlay (250) so
   the host (and players) can still read the partie code from any in-game screen. */
.room-code-badge{position:fixed;right:10px;top:10px;height:42px;box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;z-index:260;background:#ffffff;border:1.5px solid #c9a550;border-radius:10px;padding:3px 10px;box-shadow:0 2px 8px rgba(0,0,0,0.15);cursor:pointer;user-select:none;text-align:center;line-height:1.05;min-width:62px}
.room-code-badge:active{transform:scale(.95)}
/* The croupier screen used to pull the badge to the horizontal centre, where it sat on the axis of
   the wine title and read as part of the header. It now keeps the same top-right corner it holds
   everywhere else (2026-08-31) — one fixed place for the partie code on every screen. .host-top
   still reserves the height so VIN MYSTÈRE clears it. */
/* Croupier screen: the floating badge stands down — the code has its own plate inside
   .host-ctrl-row there (2026-08-31). Relies on the badge markup sitting AFTER .host-overlay. */
.host-overlay.open ~ .room-code-badge{display:none}
/* Cépage ID drawer open → the badge yields: it used to cover the Régions tab and the × close.
   Relies on the badge markup sitting AFTER .sb-drawer. */
.sb-drawer.open ~ .room-code-badge{display:none}
.room-code-label{font-size:8px;color:#999;letter-spacing:2px;font-weight:600}
.room-code-val{font-family:var(--font-display);font-size:17px;color:#6B1E2E;letter-spacing:3px}
/* Docked variant of the badge: a FLOW element on the between-rounds role screen, centered right
   above the white card (the fixed badge is covered by those overlays and used to leak into the
   iPhone status-bar strip). Same look, same tap-to-copy. */
/* Taller plate (requested 2026-08-31): 4→8px of vertical padding and a touch more leading — the
   label and the number sat squeezed against the frame. margin-bottom 12→22px so it no longer sits
   on the white card's shoulder; the card is flex-centred, so the plate rises with the gap.
   Only the role screen carries this dock. */
.room-code-dock{background:#fff;border:1.5px solid #c9a550;border-radius:10px;padding:8px 16px;box-shadow:0 2px 8px rgba(0,0,0,0.15);cursor:pointer;user-select:none;text-align:center;line-height:1.2;min-width:76px;margin-bottom:22px}
.room-code-dock:active{transform:scale(.95)}

.timer-text{font-size:16px;color:#6B1E2E;font-family:var(--font-display);letter-spacing:2px;line-height:1}


.timer-ring{display:none}
.timer-widget.running .timer-text{animation:tpulse 1s ease-in-out infinite}
.timer-widget.expired{border-color:#ae182b;animation:tshake 0.5s ease-in-out}
.timer-widget.expired .timer-text{color:#ae182b;animation:tblink 0.6s ease-in-out infinite}
