/* ============================================================
   DUPLICABBLE v2 — Design System
   ============================================================ */

/* Tile letter face. "Fashion Fetish Heavy" is a custom display font (also used
   server-side by TileGenerator for the PNG tiles); it is NOT a browser-standard
   font, so it must be shipped as a file here. Drop the font file(s) in
   /v2/fonts/ — the browser falls back to the system stack until then. */
@font-face {
  font-family: 'Fashion Fetish Heavy';
  src: url('/v2/fonts/FashionFetishHeavy.woff2') format('woff2'),
       url('/v2/fonts/FashionFetishHeavy.woff')  format('woff'),
       url('/v2/fonts/FashionFetishHeavy.ttf')   format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}
:root {
  /* Veil the shell fades through when it switches theme (reloadWithTheme in theme.js) */
  --theme-veil: #000;
  --tile-font: 'Fashion Fetish Heavy', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --tile-font-weight: 800;
  /* Vertical nudge that optically centres a tile letter in its tile.
     Fashion Fetish Heavy declares ascent 0.600em / descent 0.100em, so its normal
     line box is 0.700em with the baseline 0.600em down; its capitals are 0.825em
     tall, i.e. the ink runs from -0.225em to 0.600em and its centre sits 0.1625em
     ABOVE the centre of the line box. A flex tile centres the line box, not the
     ink, so the letter reads high. padding-top shifts the centred line box by half
     itself, hence 2 x 0.1625em. Every tile face has to use this one value, or the
     same letter lands at two different heights on the rack and on the grid.
     The tile's line-height must also be large enough for the line box to contain
     the ink (see "Tile faces" in play.css): ink outside the line box is what iOS
     Safari crops on a partial repaint. */
  --tile-letter-nudge: 0.325em;

  /* Tailles / Espacement — couleurs dans v2/themes/<theme>.css */
  --r-sm:  8px;
  --r:     12px;
  --r-lg:  18px;
  --r-xl:  24px;
  --r-f:   9999px;

  --sh-sm: 0 2px 8px rgba(0,0,0,.35);
  --sh:    0 4px 20px rgba(0,0,0,.45);
  --sh-lg: 0 8px 40px rgba(0,0,0,.55);
  /* behind a popup of the page (promo_code_popup.css) */
  --popup-overlay: rgba(0,0,0,.72);
  --sh-p:  0 4px 20px var(--primary-glow);
  /* favorite heart badge, same in every theme */
  --fav-badge: #ff3b4e;

  /* Stripe embedded checkout renders a fixed light form, so its container is always
     white regardless of the app theme (with a dark foreground for controls over it). */
  --stripe-surface: #ffffff;
  --stripe-fg:      #30313d;

  /* Social network buttons (follow_us_popup.css): brand colours, same in every theme. */
  --facebook-blue: #1877f2;
  --instagram-gradient: linear-gradient(45deg, #feda75 0%, #fa7e1e 25%, #d62976 50%, #962fbf 75%, #4f5bd5 100%);
  --social-fg: #ffffff;
  --social-logo-bg: rgba(255,255,255,.18);

  /* Avatar colour picker: hue slider track stops, and the slider thumb. */
  --av-hue-stops: #ef4444, #eab308, #22c55e, #06b6d4, #3b82f6, #a855f7, #ef4444;
  --av-thumb: #ffffff;

  --nav-h: 68px;
  --side-w: 250px;
  --page-max: 520px;

  /* Safe-area insets, scaled in ONE place. Change the *-scale factors to tune how
     much of the device inset the whole app uses (e.g. 0.8 = 80%). Every rule below
     references --sab / --sat instead of env(...) directly. */
  --sab-scale: 0.3;
  --sat-scale: 1;
  --sab: calc(env(safe-area-inset-bottom) * var(--sab-scale));
  --sat: calc(env(safe-area-inset-top) * var(--sat-scale));
}

/* "Thin tile letters" profile option (Player.regularTileFont): the class is set on
   <html> by theme.js (from the tileFont cookie, refreshed from the server value), so
   every tile face of every page — game grid and rack, drag / fly clones, the mini
   grids, the history board — switches to the tile font of the V1 grey theme:
   Verdana regular (see TileGenerator), with no synthetic bold on top of it. Verdana
   is not shipped on Android, where the system sans (Roboto) stands in. Its metrics
   are nothing like Fashion Fetish's: ascent 1.005em / descent 0.210em / capitals
   0.727em, so the ink centre of a capital already sits 0.034em BELOW the centre of
   its line box — no upward nudge (a negative padding is not possible, and that
   offset is below a pixel). */
html.tile-font-regular {
  --tile-font: Verdana, 'DejaVu Sans', Roboto, sans-serif;
  --tile-font-weight: normal;
  --tile-letter-nudge: 0;
}

/* Reset */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
/* Disable text/element selection app-wide (inputs kept editable/selectable below) */
*{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}
input,textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}
/* Global type scale. All font sizes across v2 are expressed in rem, so this single
   value scales the whole app's typography. Bump it to make everything a bit larger
   (e.g. 18px), lower it to shrink. Board tiles use container/px units and are not
   affected. */
html{font-size:17px;-webkit-text-size-adjust:100%;scroll-behavior:smooth;overscroll-behavior-y:none}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  background:var(--bg);color:var(--t1);min-height:100vh;line-height:1.5;overflow-x:hidden;overscroll-behavior-y:none}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
button{cursor:pointer;border:none;background:none;font-family:inherit;color:inherit}
input,select,textarea{font-family:inherit;outline:none}

/* ============ App Shell ============ */
.app{display:flex;min-height:100vh;min-height:100dvh}
.main{flex:1;padding-top:var(--sat);padding-bottom:calc(var(--nav-h) + var(--sab));min-width:0;display:flex;flex-direction:column;transition:padding-bottom .35s cubic-bezier(.4,0,.2,1)}
.app.game-view .main{padding-bottom:0}
.page{max-width:var(--page-max);margin:0 auto;padding:5px 16px 32px}
/* Credit footer, appended to every iframe page by page.js */
.page-credit{display:block;flex:none;text-align:center;margin:24px 0 0;font-size:0.75rem;
  color:var(--t3);text-decoration:none}

/* ============ Sidebar (desktop) ============ */
.sidebar{
  display:none;width:var(--side-w);background:var(--surface);
  border-right:1px solid var(--border);height:100vh;height:100dvh;position:sticky;top:0;
  flex-direction:column;padding:0 0 16px;overflow-y:auto;flex-shrink:0;z-index:50
}
.sidebar-logo{padding:28px 20px 24px;border-bottom:1px solid var(--border);margin-bottom:8px;position:sticky;top:0;z-index:1;background:var(--surface)}
.s-item{
  display:flex;align-items:center;gap:12px;padding:11px 20px;
  color:var(--t2);font-size: 0.9375rem;font-weight:500;transition:all .2s;position:relative;
  cursor:pointer;border:none;background:none;width:100%;text-align:left
}
.s-item:hover{background:var(--card);color:var(--t1)}
.s-item.active{background:var(--card);color:var(--primary)}
.s-item.active::before{content:'';position:absolute;left:0;top:6px;bottom:6px;
  width:3px;background:var(--primary);border-radius:0 3px 3px 0}
.s-badge{
  margin-left:auto;min-width:20px;height:20px;
  background:var(--err);border-radius:10px;font-size: 0.625rem;font-weight:800;
  color:#fff;display:flex;align-items:center;justify-content:center;padding:0 5px
}
.s-sep{margin:8px 20px;height:1px;background:var(--border);flex-shrink:0} /* never squashed to nothing by a short sidebar */
.s-section-label{padding:12px 20px 4px;font-size: 0.6875rem;font-weight:700;
  color:var(--t3);text-transform:uppercase;letter-spacing:.1em}

/* ============ Bottom Nav (mobile) ============ */
.bottom-nav{
  position:fixed;bottom:var(--sab);left:0;right:0;
  height:var(--nav-h);
  background:var(--nav-bg);border-top:1px solid var(--border);
  display:flex;align-items:stretch;z-index:100;
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  transition:transform .35s cubic-bezier(.4,0,.2,1)
}
/* Solid strip filling the home-indicator safe area below the bar, same colour as the
   bar. The bar itself sits above the inset (buttons stay clear of the home indicator)
   and this fills the gap so the nav reads as continuous down to the screen bottom. */
.bottom-nav-fill{
  position:fixed;bottom:0;left:0;right:0;
  height:var(--sab);
  background:var(--nav-bg);z-index:100;
  transition:transform .35s cubic-bezier(.4,0,.2,1)
}
/* Slide both fully off-screen: the bar is offset up by the bottom inset, so it must
   travel its own height PLUS that inset to clear the screen edge entirely. */
.app.game-view .bottom-nav,
.app.game-view .bottom-nav-fill{transform:translateY(calc(100% + var(--sab)));pointer-events:none}
.n-item{
  flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;color:var(--t3);font-size: clamp(0.5rem,2.6vw,0.625rem);font-weight:600;text-transform:uppercase;
  letter-spacing:.03em;transition:color .2s;position:relative;padding:8px 4px;
  cursor:pointer;border:none;background:none;width:100%
}
.n-label{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.n-item:hover,.n-item.active{color:var(--primary)}
.n-icon{font-size: 1.375rem;line-height:1}
.n-badge{
  position:absolute;top:4px;right:calc(50% - 22px);min-width:22px;height:22px;padding:0 5px;
  background:var(--err);border-radius:11px;font-size: 0.75rem;font-weight:800;
  display:flex;align-items:center;justify-content:center;
  border:2px solid var(--surface);color:#fff
}

/* ============ Buttons ============ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:12px 20px;border-radius:var(--r-sm);font-size: clamp(0.8125rem,3.75vw,0.9375rem);font-weight:600;
  transition:all .2s;white-space:nowrap;cursor:pointer
}
.btn-primary{background:var(--primary);color:var(--on-primary);/*box-shadow:var(--sh-p)*/}
.btn-primary:hover{background:var(--primary-h);transform:translateY(-1px);
  /*box-shadow:0 6px 24px var(--primary-glow)*/}
.btn-secondary{background:var(--raised);color:var(--t1);border:1px solid var(--border2)}
.btn-secondary:hover{background:var(--card);border-color:var(--t2)}
.btn-ghost{color:var(--t2);padding:10px 16px;background: var(--card);}
.btn-ghost:hover{background:var(--card);color:var(--t1)}
.btn-danger{background:rgba(var(--err-rgb),.12);color:var(--err);border:1px solid rgba(var(--err-rgb),.3)}
.btn-danger:hover{background:rgba(var(--err-rgb),.2)}
.btn-sm{padding:8px 14px;font-size: clamp(0.6875rem, 3.2vw, 0.8125rem);}
.btn-lg{padding:15px 24px;font-size: clamp(0.8125rem,4vw,1rem);border-radius:var(--r)}
.btn-block{width:100%}
.btn-icon{width:44px;height:44px;padding:0;border-radius:var(--r-sm)}
.btn-bld{font-size: clamp(0.6875rem, 3.6vw, 1.25rem);font-weight: 900;}

/* Replay button, shown on finished games (play + game detail). Pages add their
   own sizing class on top of this one. */
.replay-btn{
  font-weight:600;color:var(--ok);
  background:rgba(var(--ok-rgb),.12);
  border:1px solid rgba(var(--ok-rgb),.3);
  border-radius:var(--r-f);cursor:pointer;white-space:nowrap;
  /* Soft pulse so the button catches the eye once the game is over. */
  animation:replayPulse 1.2s ease-in-out infinite
}
/* Stop drawing attention once the user has reached it. */
.replay-btn:hover{background:rgba(var(--ok-rgb),.2);animation:none}
/* Once the game has been replayed the button is spent: no pulse, no click. */
.replay-btn:disabled,.replay-btn:disabled:hover{
  color:var(--t3);background:var(--raised);border-color:var(--border);
  box-shadow:none;animation:none;cursor:default;opacity:.6
}
@keyframes replayPulse{
  0%,100%{background:rgba(var(--ok-rgb),.12);border-color:rgba(var(--ok-rgb),.3);
    box-shadow:0 0 0 0 rgba(var(--ok-rgb),0)}
  50%{background:rgba(var(--ok-rgb),.28);border-color:rgba(var(--ok-rgb),.7);
    box-shadow:0 0 8px 2px rgba(var(--ok-rgb),.35)}
}
@media (prefers-reduced-motion:reduce){.replay-btn{animation:none}}

/* ============ Cards ============ */
.card{
  background:var(--card);border:1px solid var(--border);
  border-radius:var(--r);padding:16px;transition:all .2s
}

/* ============ Inputs ============ */
.field{margin-bottom:16px}
.label{display:block;font-size: 0.75rem;font-weight:700;color:var(--t2);margin-bottom:6px;
  text-transform:uppercase;letter-spacing:.06em}
.input{
  width:100%;background:var(--raised);border:1.5px solid var(--border);
  border-radius:var(--r-sm);padding:12px 16px;color:var(--t1);font-size: 0.9375rem;
  transition:border-color .2s
}
.input::placeholder{color:var(--t3)}
.input:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-glow)}
.input-wrap{position:relative}
.input-wrap .input{padding-left:44px}
.input-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);
  color:var(--t3);font-size: 1.125rem}

/* Password "eye": a .eye-btn placed right after a password .input inside an .input-wrap.
   Wired up by lib/form.js, which also adds .has-eye to the input to keep the text clear
   of the button. Dimmed while the password is masked, full color once revealed. */
.eye-btn{
  position:absolute;right:12px;top:50%;transform:translateY(-50%);
  background:none;border:none;cursor:pointer;padding:4px;line-height:1;
  font-size:1rem;color:var(--t3);opacity:.5;transition:color .2s,opacity .2s
}
.eye-btn:hover{color:var(--t1)}
.eye-btn.revealed{opacity:1}
.input-wrap .input.has-eye{padding-right:44px}

/* Search "clear" cross: a .clear-btn placed right after a type="search" .input, added by
   lib/form.js (initSearchClears) to every filter field. The native WebKit cancel button is
   hidden: desktop Chrome shows it on hover only and the iOS / Android WebViews not at all,
   so this one is drawn by hand and stays visible as long as the field holds text (the
   placeholder, which every filter sets, is what tells an empty field apart). */
.input[type=search]::-webkit-search-cancel-button,
.input[type=search]::-webkit-search-decoration{-webkit-appearance:none;display:none}
.input.has-clear{padding-right:40px}
.clear-btn{
  position:absolute;right:8px;top:50%;transform:translateY(-50%);
  width:32px;height:32px;display:flex;align-items:center;justify-content:center;
  background:none;border:none;border-radius:50%;cursor:pointer;padding:0;line-height:1;
  font-size:1rem;color:var(--t3);transition:color .2s,background .2s
}
.clear-btn:hover{color:var(--t1);background:var(--raised)}
.input:placeholder-shown+.clear-btn{display:none}

/* ============ Dividers ============ */
.or-divider{
  display:flex;align-items:center;gap:12px;color:var(--t3);font-size: 0.8125rem;margin:16px 0
}
.or-divider::before,.or-divider::after{content:'';flex:1;height:1px;background:var(--border)}

/* ============ Scrabble Tile ============ */
.tile{
  display:inline-flex;flex-direction:column;align-items:center;justify-content:center;
  background:var(--tile-grad);border-radius:4px;color:var(--tile-text);
  font-weight:800;box-shadow:0 2px 4px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.2);
  position:relative;flex-shrink:0;letter-spacing:0
}
.tile-xs{width:20px;height:20px;font-size: 0.75rem}
.tile-sm{width:28px;height:28px;font-size: 1.0625rem}
.tile-md{width:40px;height:40px;font-size: 1.5rem}
.tile-val{
  position:absolute;bottom:1px;right:2px;
  font-size:8px;font-weight:600;opacity:.8
}
.tile-md .tile-val{font-size:9px;bottom:2px;right:3px}

/* Social login */
.social-btn{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;padding:12px;border-radius:var(--r-sm);font-size: 0.9375rem;font-weight:600;
  border:1.5px solid var(--border);background:var(--raised);color:var(--t1);
  cursor:pointer;transition:all .2s;margin-bottom:10px
}
.social-btn:hover{background:var(--card);border-color:var(--border2)}

/* ============ Logo ============ */
.logo{display:flex;align-items:center;gap:8px}
.logo-tiles{display:flex;gap:2px;align-items:center}
/* The logo as a link (misc.js linkEntryLogoToLanding): looks exactly like the plain logo */
.logo-link{display:inline-block;text-decoration:none}
/* Read by screen readers, not shown */
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.tile-i{background:linear-gradient(145deg,#5A3A9A,#3A1A7A)}
/* Logo "I" tiles (sidebar + login page) use the same primary green as the new-game button (.btn-primary) */
.sidebar-logo .tile-i,
.login-logo-wrap .tile-i{background:linear-gradient(145deg,var(--primary),var(--primary-h))}
.s-icon{font-size: 1.125rem}
.s-sep-push{margin-top:auto}

/* ============ Auth pages ============ */
.auth-page{
  min-height:100vh;display:flex;flex-direction:column;align-items:center;
  justify-content:center;
  /* Top/bottom insets keep the content (the DUPLICS logo first of all) clear of the
     iOS status bar / front camera and of the home indicator. */
  padding:calc(var(--sat) + 24px) 20px calc(var(--sab) + 24px);
  background:var(--bg)
}
.auth-card{
  width:100%;max-width:400px;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-xl);padding:30px 20px
}

/* ============ Loading overlay ============ */
#v2-mire{
  display:none;position:fixed;inset:0;z-index:9999;
  align-items:center;justify-content:center
}
#v2-mire.visible{display:flex}
#v2-mire-img{display:none;width:48px;height:48px}

/* ============ Logo header (mobile, inside shell) ============ */
.header-logo{
  font-size: 0.8125rem;font-weight:900;color:var(--gold);
  letter-spacing:.1em;text-decoration:none;flex-shrink:0
}

/* Back arrow — only visible on mobile pushed views (see page.js) */
.header-back{
  font-size: 1.25rem;color:var(--t2);padding:2px 8px 2px 0;
  cursor:pointer;border:none;background:none;font-family:inherit;
  transition:color .15s;flex-shrink:0;line-height:1
}
.header-back:hover{color:var(--primary)}

/* ============ Back arrows on Android ============ */
/* The &#8592; glyph of the back buttons (.header-back built by page.js, .back-to-list of
   message_detail, #back-from-play of play) comes, on Android, from a fallback font: it is
   drawn small and a few px too low (rounded font metrics, a px nudge is not reliable). The
   glyph is made invisible (text-fill only: the line box, so the button size, and currentColor
   are untouched) and the same arrow is drawn over it with a currentColor mask, centred in
   the button (stroke thick enough to match the 900-weight glyph of web/iOS). :hover keeps
   working; web and iOS render the glyph correctly and are left untouched. */
html.android .header-back,
html.android .back-to-list,
html.android #back-from-play{
  --back-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 10' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 5H2.5M6.5 1.5 2.5 5 6.5 8.5'/%3E%3C/svg%3E");
  position:relative;
  -webkit-text-fill-color:transparent;
}
html.android .header-back::before,
html.android .back-to-list::before,
html.android #back-from-play::before{
  content:"";position:absolute;inset:0;margin:auto;width:16px;height:10px;
  background:currentColor;
  -webkit-mask:var(--back-arrow) center / contain no-repeat;
  mask:var(--back-arrow) center / contain no-repeat;
}
/* .header-back has its padding on the right only: centre the arrow on the glyph's box */
html.android .header-back::before{right:8px}

/* ============ Page header ============ */
.page-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}
.page-title{font-size: clamp(1.0625rem,5.5vw,1.375rem);font-weight:800;color:var(--t1)}
.page-sub{font-size: 0.8125rem;color:var(--t3);margin-top:2px}

/* ============ Avatar ============ */
.av{border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-weight:800;flex-shrink:0;color:#fff;overflow:hidden}
/* Avatar picture: fits inside the circle, anything past the round edge is clipped */
.av-img{width:100%;height:100%;object-fit:contain;display:block}
.av-sm{width:32px;height:32px;font-size: 0.75rem}
.av-md{width:40px;height:40px;font-size: 0.875rem}
.av-xl{width:72px;height:72px;font-size: 1.625rem;flex-shrink:0}
.av-wrap{position:relative;display:inline-block;flex-shrink:0}
.online-dot{position:absolute;bottom:1px;right:1px;width:11px;height:11px;
  background:var(--ok);border-radius:50%;border:2.5px solid var(--card)}
.offline-dot{background:var(--t3)}
/* Favorite heart on the avatar, mirroring the online dot (bottom right). Same outline as the
   online dot: the card colour, 2.5px thick; the stroke is centred on the path, so 5px gives
   2.5px outside the filled heart. */
.fav-badge{position:absolute;bottom:-3px;left:-3px;width:13px;height:13px;overflow:visible;
  fill:var(--fav-badge);stroke:var(--card);stroke-width:5px;stroke-linejoin:round;paint-order:stroke fill}
.fav-badge path{vector-effect:non-scaling-stroke}

/* ============ Toggle switch ============ */
.switch{display:inline-flex;align-items:center;flex-shrink:0;cursor:pointer}
.switch input[type="checkbox"]{position:absolute;opacity:0;width:0;height:0}
.sw-track{
  position:relative;width:46px;height:26px;background:var(--raised);
  border:1.5px solid var(--border);border-radius:var(--r-f);
  transition:background .2s,border-color .2s;flex-shrink:0
}
.sw-track::after{
  content:'';position:absolute;top:3px;left:3px;width:18px;height:18px;
  border-radius:50%;background:var(--t3);transition:transform .2s,background .2s
}
.switch input:checked + .sw-track{background:var(--primary);border-color:var(--primary)}
.switch input:checked + .sw-track::after{transform:translateX(20px);background:#fff}
.switch input:disabled + .sw-track{opacity:.4;cursor:not-allowed}

/* ============ Segmented tabs (statistics view, games/tournaments switch) ============ */
.stats-tabs{
  display:flex;background:var(--surface);border-radius:var(--r-sm);
  padding:4px;margin-bottom:20px;flex-shrink:0
}
.stats-tab{
  flex:1;text-align:center;padding:9px 8px;font-size: 0.8125rem;font-weight:600;
  color:var(--t3);cursor:pointer;border-radius:6px;transition:all .2s;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis
}
.stats-tab:hover{color:var(--t1)}
.stats-tab.active{background:var(--raised);color:var(--t1);box-shadow:var(--sh-sm)}

/* ============ Month tabs (12 last months selector) ============ */
.month-tabs{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding:12px 0;margin-bottom:8px}
.month-tabs::-webkit-scrollbar{display:none}
.month-tab{
  padding:6px 14px;border-radius:var(--r-f);font-size: 0.8125rem;font-weight:600;
  border:1.5px solid var(--border);background:var(--card);color:var(--t2);
  cursor:pointer;white-space:nowrap;transition:all .2s;flex-shrink:0
}
.month-tab.active{border-color:var(--gold);color:var(--gold);background:rgba(var(--gold-rgb),.1)}

/* ============ Utility ============ */
.mb4{margin-bottom:16px}

/* ============ Mobile layout (bottom nav visible) ============ */
/* Triggered by .mobile-layout class set in page.js, which checks the parent
   window's #bottom-nav visibility — more reliable than a media query inside
   an iframe where the viewport is narrower than the outer browser window. */
body.mobile-layout .page-header{display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
body.mobile-layout .header-logo{grid-column:1;justify-self:start}
body.mobile-layout .page-header > .page-title{grid-column:2;text-align:center}
body.mobile-layout .page-title-wrap{grid-column:2;text-align:center}
body.mobile-layout .page-header > .btn,
body.mobile-layout .page-header > .replay-btn{grid-column:3;justify-self:end}

/* Pushed-view header: DUPLICS logo and title share row 1, back arrow below it */
body.mobile-layout.pushed-view .page-header{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  grid-template-rows:auto auto;
  row-gap:2px;
  align-items:center
}
body.mobile-layout.pushed-view .header-logo{grid-column:1;grid-row:1;justify-self:start;align-self:end}
body.mobile-layout.pushed-view .header-back{grid-column:1;grid-row:2;justify-self:start;align-self:start;font-weight: 900;}
body.mobile-layout.pushed-view .page-header > .page-title{grid-column:2;grid-row:1/3;text-align:center}
body.mobile-layout.pushed-view .page-title-wrap{grid-column:2;grid-row:1/3;text-align:center}
body.mobile-layout.pushed-view .page-header > .btn,
body.mobile-layout.pushed-view .page-header > .replay-btn{grid-column:3;grid-row:2;justify-self:end}

/* Pushed-view header on wide screen: same 3-col grid as mobile so title stays centered */
body.pushed-view:not(.mobile-layout) .page-header{display:grid;grid-template-columns:auto 1fr auto;align-items:center}
body.pushed-view:not(.mobile-layout) .header-back{grid-column:1}
body.pushed-view:not(.mobile-layout) .page-header > .page-title{grid-column:2;text-align:center}
body.pushed-view:not(.mobile-layout) .page-title-wrap{grid-column:2;text-align:center}
body.pushed-view:not(.mobile-layout) .page-header > .btn,
body.pushed-view:not(.mobile-layout) .page-header > .replay-btn{grid-column:3;justify-self:end}

/* ============ Responsive ============ */
/* The shell (home.jsp, a top-level window) picks the phone or sidebar layout from
   the window width. That is the ONLY media query the layout hangs on. */
@media(min-width:768px){
  .sidebar{display:flex}
  .bottom-nav,.bottom-nav-fill{display:none}
  .main{padding-bottom:0}
}
/* The pages follow the shell's choice through body.mobile-layout, set by page.js
   from the shell's bottom bar (see _isMobileLayout). A media query here would
   measure the frame — the window minus the sidebar — and snap the page to its
   phone layout while the sidebar is still up. Wrapped in :where() so the rule
   keeps the specificity of a bare .page and the per-page overrides
   (.page-games .page ...) still win, as they did over the media query. */
:where(body:not(.mobile-layout)) .page{padding:32px 40px;max-width:840px}
:where(body:not(.mobile-layout)) .g2-l{display:grid;grid-template-columns:1fr 1fr;gap:20px}

/* ============ Likes of a profile message (own and friend profile) ============ */
.like-pill{display:inline-flex;align-items:center;gap:6px;padding:5px 12px;flex-shrink:0;
  border:1px solid var(--border);border-radius:var(--r-f);background:var(--raised);color:var(--t3);
  font:inherit;font-size:0.8125rem;font-weight:700;line-height:1;
  transition:color .15s,border-color .15s,background .15s}
button.like-pill{cursor:pointer}
button.like-pill:active:not(:disabled){opacity:.7}
button.like-pill:disabled{cursor:default}
.like-pill.liked{color:var(--primary);border-color:rgba(var(--primary-rgb),.4);background:rgba(var(--primary-rgb),.12)}
.like-pill-icon{width:15px;height:15px;fill:currentColor}

/* ============ Mini board (shared across pages) ============ */
.gc-tile{width:66px;height:66px;border-radius:5px;overflow:hidden;flex-shrink:0;border:1px solid var(--border)}
.board{display:grid;grid-template-columns:repeat(15,1fr);grid-template-rows:repeat(15,1fr);
  width:100%;height:100%;background:var(--tile-grad)}
.cell{display:block}
.c-n {background:var(--cell-n); color:var(--cell-n-fg)}
.c-dl{background:var(--cell-dl);color:var(--cell-dl-fg)}
.c-tw{background:var(--cell-tw);color:var(--cell-tw-fg)}
.c-dw{background:var(--cell-dw);color:var(--cell-dw-fg)}
.c-tl{background:var(--cell-tl);color:var(--cell-tl-fg)}
.c-st{background:var(--cell-st);color:var(--cell-st-fg)}
.c-t {background:var(--tile-grad);display:flex;align-items:center;justify-content:center;font-size:3.5px;font-weight:700;color:var(--tile-text);line-height:0.5;width:4.26px;height:4.26px}
/* Thin tile letters option: the mini grids follow the tile font too. The default
   keeps the system bold above (tuned at this 3.5px size); the regular cut needs the
   optical nudge every tile face uses (see --tile-letter-nudge). */
html.tile-font-regular .c-t {font-family:var(--tile-font);font-weight:var(--tile-font-weight);padding-top:var(--tile-letter-nudge)}
html.android .c-t {transform:scale(0.5)}

/* ============ Animations ============ */
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
@keyframes spin{to{transform:rotate(360deg)}}
.anim-in{animation:fadeUp .3s ease}

/* ============ Badges: small coloured pills (game options, tournament states...) ============ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: var(--r-f);
  font-size: 0.6875rem;
  font-weight: 700;
  white-space: nowrap;
}
.badge-p { background: rgba(var(--primary-rgb),.15); color: var(--primary); }
.badge-g { background: rgba(var(--gold-rgb),.15); color: var(--gold); }
.badge-ok { background: rgba(var(--ok-rgb),.15); color: var(--ok); }
.badge-n { background: var(--badge-n-bg, var(--raised)); color: var(--badge-n-text, var(--t2)); }
.badge-warn { background: rgba(var(--warn-rgb),.15); color: var(--warn); }
.badge-err { background: rgba(var(--err-rgb),.15); color: var(--err); }
