﻿/* main.css — reset, root variables, fonts */
@font-face {
  font-family: 'BritannicBold';
  src: url('../assets/fonts/BritannicBold.ttf') format('truetype');
  font-weight: bold;
  font-style: normal;
}
/* Cyrillic-capable display face for the Russian UI (Britannic Bold has no Cyrillic).
   WMSerifDisplay = Playfair Display ExtraBold (SIL OFL, self-hosted — no Google CDN: keeps user
   IPs away from US servers, CNIL-friendly; replaced the TT Ramillas TRIAL 2026-08-11) with the
   arrow glyphs (U+2190–21FF) REMOVED and the internal name changed per OFL's Reserved-Font-Name
   rule for modified builds. Why removed: Playfair's own → is a swashy display arrow, and pinning
   arrows to a sans via src:local() silently fails on iOS Safari. With no arrows in any face of
   the family, every browser falls through to the system font for them — the exact mechanism that
   gives FR/EN (Britannic, which never had arrows) their clean「← Выйти」-style arrows.
   The filename also serves as the cache-buster: the arrow-ful predecessor sat under a 30-day TTF
   cache, so a same-name replacement would not have reached phones for a month. */
@font-face {
  font-family: 'WMSerifDisplay';
  src: url('../assets/fonts/WMSerifDisplay-ExtraBold.ttf') format('truetype');
  font-weight: bold;
  font-style: normal;
}
/* DIGITS: Playfair's default figures are oldstyle (ascenders/descenders — the room code read as
   "jumping"). Britannic's lining digits instead, so codes/scores/vintages look identical to every
   other language. Later same-family rule wins for its unicode-range. */
@font-face {
  font-family: 'WMSerifDisplay';
  src: url('../assets/fonts/BritannicBold.ttf') format('truetype');
  font-weight: bold;
  font-style: normal;
  unicode-range: U+0030-0039;
}

:root {
  --color-bordeaux: #5e0c23;
  --color-gold: #c9a550;
  --color-beige: #fdf8f0;
  --color-gray-bg: #6b6b6e;
  --font-display: 'BritannicBold', serif;
  --font-body: 'Helvetica Neue', sans-serif;
}
/* Every display-font usage goes through var(--font-display) — wmSetLang() keeps <html lang>
   in sync, so switching to RU swaps the display face app-wide (FR/EN keep Britannic). */
html[lang="ru"] {
  --font-display: 'WMSerifDisplay', 'BritannicBold', serif;
}

*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Helvetica Neue',Arial,sans-serif;background:#5e0c23;display:flex;justify-content:center;padding:14px;min-height:100vh}
/* Sparkling (Bubbles) game board: page background matches the board art's light-gold field so the
   board blends in instead of a gold disc cut off by the bordeaux page. Toggled in applySparklingBoardUI. */
body.sparkling-bg{background:#d0c082}
.wrap{width:100%;max-width:560px;position:relative}   /* anchors the pinch-zoom 1× pill (game.css .bw-zoom-reset) */

/* Capacitor iOS shell (html.wm-native, set in index.html <head>): the document must NOT be the
   scroller. WKWebView rubber-bands the document and drags every position:fixed layer along with
   it (screens, overlays, the nav pill), exposing the game board underneath when a short overlay
   screen is swiped. Make <body> an inner scroll container with no overscroll instead — inner
   scrollers never move fixed layers. Web (Safari/Chrome) is untouched. */
html.wm-native{height:100%;overflow:hidden;overscroll-behavior:none}
html.wm-native body{height:100%;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:none;-webkit-overflow-scrolling:touch}

/* Safe areas in the native shell (status bar / notch / home indicator). With the WebView scroll
   view frozen (ios.scrollEnabled=false) iOS no longer insets the content for us, so the layout
   reserves the top inset itself — requires viewport-fit=cover on the viewport meta. Every
   full-screen layer starts below the status bar; the strip above it shows the page background,
   which reads like a native status bar, and scrolling content stops at that line instead of
   running under the clock. Modal backdrops (dimmed layers) deliberately stay full-bleed. */
html.wm-native body{box-sizing:border-box;padding-top:calc(14px + env(safe-area-inset-top,0px))}
/* …and room at the FOOT of the game page (2026-08-31): body is the scroller in the native shell,
   and its scrollable area used to end at the betting panel's last pixel — so the card's bottom
   rows (the table board, "Quitter la partie") stayed under the home indicator with nowhere left
   to scroll. It has to be a real BOX at the end of the page: the body is a flex container whose
   own bottom padding is swallowed by the stretched item, .wrap is that stretched item, and the
   panel spills out of it — padding on the body, padding on .wrap and a margin on the panel were
   all measured and none of them extended the scrollable area. A block with a height does.
   Overlays are position:fixed and ignore this either way. */
.wm-page-foot{height:0}
html.wm-native .wm-page-foot{height:calc(24px + env(safe-area-inset-bottom,0px))}
html.wm-native .entry-overlay,html.wm-native .lobby-overlay,html.wm-native .setup-overlay,
html.wm-native .auth-overlay,html.wm-native .age-gate-overlay,html.wm-native .onb-overlay,
html.wm-native .dash-overlay,html.wm-native .community-overlay,html.wm-native .mystere-info-overlay,
html.wm-native .results-overlay,html.wm-native .host-overlay,html.wm-native .quiz-overlay,
html.wm-native .settings-overlay,html.wm-native .legal-overlay,
html.wm-native .wm-report-overlay,html.wm-native #wmPhotoViewer,html.wm-native #vintagePanel{
  top:env(safe-area-inset-top,0px);
}
/* …EXCEPT the screens that count the notch in their OWN padding-top (added 2026-08-29/30).
   For those the group rule above insets TWICE — a wasted ~60px band on an iPhone — and, worse,
   the strip it leaves above them shows whatever is behind: the dashboard is grey and starts at
   top:0, so a burgundy screen opened over it wore a GREY CAP (reported on the lives shop, and
   the same on the quiz and the community screens). Let them start at the very top: their own
   burgundy paints the status-bar strip and their padding keeps the content clear of the notch.
   The community HUB is excluded — its padding (screens.css) is a plain 24px with no inset, so
   it still needs the group's offset. Native only; on the web every inset is 0. */
html.wm-native #quizOverlay,
html.wm-native #livesShopOverlay,
html.wm-native #infoDayOverlay,
html.wm-native .community-overlay:not(.community-hub-overlay){top:0}

/* .lvl-overlay deliberately NOT in the inset group (2026-08-26): it is a dimmed-backdrop bottom
   sheet — starting the dim below the status bar left a bare dark strip of the screen underneath
   showing at the very top. A sheet's dim runs under the clock like every iOS sheet; the 92vh
   modal itself still starts well below the inset. */

/* Status-bar curtain (2026-08-25, scroll-guard.js sets body.wm-covered): while any full-screen
   section screen is on show, the game page behind it is taken out of flow. Without this the strip
   above the screens (they start below the status bar) showed the body, and the body kept its
   in-game scroll offset after a community-mystery round, so the wheel's top arc slid through the
   status-bar strip on the casino/quiz screens.
   HOW, and why not the obvious way: the first cut locked the body with overflow-y:hidden — the
   classic body-scroll-lock, which WKWebView answers by also killing touch scrolling INSIDE nested
   scrollers, so the quiz leaderboard and the mystère list (fixed overlays with their own
   overflow-y:auto) could no longer be dragged at all. Hiding .wrap instead removes the only tall
   in-flow content there is — every screen and layer above it is position:fixed — so the body has
   nothing left to scroll, the leak is gone at the source, and the body's own overflow is never
   touched. Inline display from the game flow still wins where it sets 'none'; it only ever
   clears back to '', which lets this rule apply.
   Background forced back to bordeaux too: a sparkling round leaves body.sparkling-bg's gold
   behind, which would otherwise tint the strip on every screen after the game. Native-only — on
   the web the screens are full-bleed (inset:0), there is no strip to leak into. */
html.wm-native body.wm-covered{background:#5e0c23}
html.wm-native body.wm-covered .wrap{display:none}

/* Round timer pill: fixed at the top of the board page. Below the status bar in the native shell,
   so the full-screen layers (which start there too) cover it instead of leaking it into the
   status-bar strip above them. */
html.wm-native .timer-widget{top:calc(10px + env(safe-area-inset-top,0px))}
html.wm-native .room-code-badge{top:calc(10px + env(safe-area-inset-top,0px))}

/* Cépage ID / Régions drawer: it runs full-height from the very top, so its dark header used to
   sit under the clock and got chewed by the status bar. The gradient keeps painting the strip
   (reads native); the name / subtitle / × start below it. */
html.wm-native .sb-header{padding-top:calc(14px + env(safe-area-inset-top,0px))}

/* Dashboard: unlike the burgundy screens it extends UNDER the status bar, so the strip is
   painted by the overlay itself (dark grey — one bar with the pinned header). The status-bar
   text stays light (app default), no per-screen switching needed. */
html.wm-native .dash-overlay{top:0;padding-top:env(safe-area-inset-top,0px)}
/* Settings opens OVER the dashboard and its strip showed the dashboard's grey — extend it under
   the status bar too. The safe-area inset lives on the HEADER, not the overlay: the header's own
   darkened background then paints the status-bar strip, so the strip and the RÉGLAGES row are one
   colour (requested 2026-08-24 — with the inset on the overlay the strip took the plain burgundy
   and read as a separate band). Safe here: the overlay never scrolls itself (pinned
   .settings-header + inner .settings-body scroller). */
html.wm-native .settings-overlay{top:0}
html.wm-native .settings-header{padding-top:calc(16px + env(safe-area-inset-top,0px))}

/* ===== Native feel (2026-08-24) ===== */
/* In the native shell the UI chrome is not selectable text: no long-press selection loupe, no
   "Save image" callout, no grey tap flash — the classic webview tells. Real content the player
   may want to copy stays selectable (inputs, textareas, the player-ID / code values). Web is
   untouched — desktop users still select and copy freely. */
/* Native text feel: no automatic text inflation in wide blocks (a webview tell on orientation
   change), and the fields players type into carry the brand — bordeaux caret, gold selection. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
input,textarea{caret-color:#8a1538}
input::selection,textarea::selection{background:rgba(201,165,80,0.35)}

/* ===== Global button shadow (2026-08-24, user request) =====
   Every real <button> rests on the same soft bordeaux shadow the quiz done-screen introduced.
   Controls that only LOOK like text — tab bars, × closes, inline comment icons, text links,
   the nav-pill icons, the tiny in-slot GB chip, the jeton swatches — opt out below: a shadow
   under a borderless control reads as dirt. Buttons whose own classes set a box-shadow keep
   theirs (class rules outrank this element-level default). */
button,.btn{box-shadow:0 2px 6px rgba(94,12,35,0.16)}   /* .btn: the board panel's action row (Effacer / 50-50 / Rien ne va plus) is <div>s */
.appnav-btn,.lvl-tab,.info-tab,.mystere-list-tab,
.lu-close-btn,.wine-modal-close,.mystere-info-close,.gb-info-close,
.mystere-comment-like,.mystere-comment-delete,.mystere-comment-report,
.quiz-link,.game-exit-btn,.auth-email-back,.age-gate-cancel,.wm-report-cancel,
.gb-info-btn,.jeton-swatch{box-shadow:none}

/* ===== Global pill buttons (2026-08-25, user request) =====
   Every button in the app is fully rounded — a capsule, like the bottom nav pill. One rule with
   !important: dozens of button classes set their own small radius (and the setup-card big-scale
   rule in screens.css is itself !important), so listing the few exceptions beats editing every
   class. Square icon buttons (×-closes, GB chips, jeton swatches, nav icons) simply render as
   circles — 999px clamps to half the side. .btn/.tbtn cover the board panel's <div> buttons
   (Effacer / 50-50 / Rien ne va plus, mono/blend). Opt-out: the underline tabs — a pill radius
   would bend their gold border-bottom indicator up the sides. Joined segmented controls
   (.setup-toggle) keep flat inner segments: the CONTAINER is the pill (its overflow:hidden clips
   the <div> segments, which this button rule never matches anyway). */
button,.btn,.tbtn{border-radius:999px!important}
/* Floating shadow on EVERY button app-wide (2026-08-27, softened 20%). Flat/utility controls opt
   out below: underline/segment tabs, quiet text links, the nav-pill icons, tiny round icon
   buttons and grid cells — a drop shadow there reads as grime, not lift. */
button,.btn{box-shadow:0 9px 22px rgba(0,0,0,0.234), 0 3px 7px rgba(0,0,0,0.117)}
/* Same soft float on every data-entry field app-wide (2026-08-27). Checkboxes/radios/ranges
   are excluded — a drop shadow on a tick box looks wrong. */
input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{box-shadow:0 5px 14px rgba(0,0,0,0.15), 0 2px 5px rgba(0,0,0,0.08)}   /* lighter float for fields (2026-08-27) */
.info-tab,.know-tab,.lvl-tab,.dash-tab,.vint-tab,.vint-cell,.community-btn-plain,
.appnav-btn,.mystere-authored-help,.vint-close,.jeton-swatch,.mystere-see-all-btn,
.dash-settings-btn,.settings-back,.mystere-info-close,.wm-report-close{box-shadow:none!important}
.jeton-swatch{box-shadow:0 5px 14px rgba(0,0,0,0.15), 0 2px 5px rgba(0,0,0,0.08)!important}   /* chips float too (requested 2026-08-28) */
/* …but NOT a bare input that only exists inside an already-styled shell: the dashboard search
   field is transparent and borderless inside its own pill, so a drop shadow drew a grey bar
   across it (2026-08-28). */
.dash-history-search input{box-shadow:none!important}
/* Same story in the vin-mystère manual editor (2026-08-30): each section field is a transparent,
   borderless textarea with only a dashed underline, sitting inside the cream editor card — the
   global field shadow drew a grey rectangle around every one of them, which read as a stray cell. */
.mystere-manual-ta{box-shadow:none!important}
.lvl-tab,.info-tab{border-radius:0!important}
.know-tile{border-radius:14px!important}   /* Savoir home icon cards (2026-08-30): rounded rectangles, not capsules — an oval crops the artwork */
/* Vintage side panel opt-out (2026-08-26): its year grid mimics the wheel's flat roulette cells —
   pills broke the table look. Cells go back to square, the range tabs and the × keep their
   original 8px. */
.vint-cell{border-radius:0!important}
.vint-tab,.vint-close{border-radius:8px!important}
.agb-acc-head{border-radius:10px!important}   /* earn/spend accordion heads on the GB journey keep their original rounded-rect look (2026-08-27) */

/* ===== Earned-avatar ring (2026-08-25, user request) =====
   The level artwork carries its own bordeaux rim, and its outer edge is uneven — pale specks show
   at some levels. A real ring drawn over that edge both fixes it and says something: bordeaux for
   everyone, metallic gold for a Club member. It is a transparent border with the gradient clipped
   to the border box, so it follows whatever radius each site already uses (circles everywhere, a
   26px rounded square in the level-up unlock) and needs no wrapper element.
   The border sits INSIDE the declared size (global box-sizing), so no avatar changes footprint.
   Two ways to earn the gold. wm-avatar-own marks avatars we know are the viewer's, and reads their
   LIVE tier off <html>. wm-avatar-club is for other people, and is set from the tier they published
   to the public board — entitlements/<uid> is owner-only, so a snapshot is the only way anyone
   else's tier can be known at all. Everything else keeps the bordeaux ring. */
.wm-avatar{
  border:2px solid transparent;
  background:linear-gradient(135deg,#8a1538 0%,#5e0c23 40%,#7d1129 68%,#5e0c23 100%) border-box;
}
html.wm-club .wm-avatar-own,
.wm-avatar.wm-avatar-club{
  background:linear-gradient(135deg,#8a6614 0%,#f6e3a0 22%,#a87f1c 52%,#fdf3cd 74%,#8a6614 100%) border-box;
}
.mystere-comment-avatar.wm-avatar{border-width:1.5px}   /* 20px avatar — 2px would read as a blob */
.lu-hero-avatar.wm-avatar{border-width:3px}

html.wm-native{-webkit-tap-highlight-color:transparent}
html.wm-native body{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
html.wm-native input,html.wm-native textarea,html.wm-native [contenteditable="true"],
html.wm-native code{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}

/* swipe-back.js: the card is briefly "tossed" to the right before the back action runs. */
.wm-swipe-back-anim{transition:transform .15s ease-out,opacity .15s ease-out!important;transform:translateX(64px)!important;opacity:.35!important}
