/* The desk, in Sapien's language.
 *
 * Everything OUTSIDE the match — sign-in, home, the lobby, profile, standings,
 * settings — restated in the UI system the owner built for Sapien and asked for
 * here: pills, glass, hairlines, eyebrows, one elastic column, segmented tabs
 * whose selection slides, a carousel that swipes its contents inside a still
 * card, a bottom drawer that drags to dismiss, and a bottom bar. The match
 * screen is untouched: the owner likes it, and styles.css still owns it.
 *
 * THE BRAND IS LUDOO'S, NOT SAPIEN'S. Sapien's rule is that the default accent
 * is not a colour — ink on background — and colour appears only where it means
 * something. Translated: cream on wood by default, BRASS for the one thing you
 * are meant to press and for what is selected, the table's green kept for PLAY
 * alone (it is the game's "go"), and the seat colours only where seats are.
 *
 * Loaded after styles.css on purpose. It restates the desk's classes and adds
 * new ones; nothing in here selects into .match.
 */

/* ------------------------------------------------------------------ type */

@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("vendor/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
    U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("vendor/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------- tokens */

:root {
  --font-sans: "Inter Variable", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --fs-display: clamp(30px, 7.5vw, 48px);
  --fs-num: clamp(36px, 10vw, 56px);
  --r-card: 24px;
  --r-hero: 32px;
  --ease: cubic-bezier(.16, 1, .3, 1);

  /* Sapien's surface set, on Ludoo's wood. The hairline is brass at low
     alpha rather than white: white lines read as a different, colder product. */
  --bg: #140d05;
  --ink: var(--cream-100);
  --dim: #8a7a5e;
  --fill: rgba(255, 236, 200, .045);
  --fill-soft: rgba(255, 236, 200, .03);
  --fill-hover: rgba(255, 236, 200, .07);
  --hair: rgba(228, 194, 118, .13);
  --hair-bright: rgba(228, 194, 118, .26);
  --glass: rgba(52, 36, 18, .58);
  --glass-strong: rgba(36, 24, 11, .86);
  --track: rgba(255, 236, 200, .08);
  /* The chosen tab has to be a different COLOUR from the track it sits in, not
     a slightly lighter shade of it: over the felt's own gradient the old #3a2a16
     thumb and the track read as the same thing, and the only sign of which tab
     was chosen was its brass lettering. Brass, held down to a fill. */
  --seg-fill: #5a4114;
  --shadow-pop: 0 20px 60px rgba(0, 0, 0, .55);

  /* The accent. Cream by default — Sapien's "ink on background" — and brass
     where a thing is chosen or is the thing to press. */
  --accent: var(--cream-100);
  --accent-ink: #1b1108;
  --accent-soft: rgba(242, 231, 206, .07);
  --accent-line: rgba(242, 231, 206, .3);
  --accent-glow: rgba(242, 231, 206, .18);
  --brass: var(--brass-500);
  --brass-soft: rgba(199, 149, 55, .12);
  --brass-line: rgba(199, 149, 55, .5);
  --brass-glow: rgba(199, 149, 55, .32);
  --go: var(--action);
  --go-lit: var(--action-lit);
}

/* Only the desk takes the new face. The match keeps the system stack the
   board was tuned with. */
.screen:not(.match) { font-family: var(--font-sans); }

/* ------------------------------------------------------- the page column */

/* One elastic column, safe-area padded, with the bottom bar's clearance
   built in. Every desk screen is a .page now; the old per-screen bodies are
   restated below to sit inside it. */
/* The fixed logo (#brandHeader) sits at 14px + safe-top, 116px wide and about
   72px tall, so it ends near 86px; the column starts under it, not behind it.
   Written at the specificity styles.css uses for the same rule — a plain
   .screen:not(.match) loses to its :not(.match):not(.auth) and never applied. */
/* A DESK SCREEN IS ONE VIEWPORT TALL, AND ITS CONTENTS SCROLL WITHIN IT. A
   fixed frame — the logo and corners at the top, the deck under them — that
   fills a tall screen and scrolls on a short one, with a mask at the foot
   saying so. (For a week the deck was scaled to the room instead, so that no
   page ever scrolled; the page shifting as the scale settled was worse than
   scrolling, and the scaling is gone.) */
.screen:not(.match):not(.auth), .screen.auth {
  height: 100dvh; min-height: 0;
  display: flex; flex-direction: column;
  /* Room under the last thing, so it can scroll clear of the mask below. */
  padding: calc(env(safe-area-inset-top, 0px) + var(--head-room)) 18px
    calc(var(--foot-room) + 40px + env(safe-area-inset-bottom, 0px));
  /* THE PAGE SCROLLS, as a page does, and the SCREEN is what scrolls: the
     deck inside it stays a plain box so the mode rail can bleed to the glass,
     and the screen clips the bleed at its edges. Clipped here rather than
     hidden on the body: the body must never scroll sideways, and hiding that
     would hide the next bleed too. desk.js pins scrollLeft to zero, since a
     clip beside a scrolling y computes to hidden, and hidden still scrolls
     when the browser wants to reveal something. */
  overflow-y: auto; overflow-x: clip;
  overscroll-behavior: contain; scrollbar-width: none;
}
.screen:not(.match)::-webkit-scrollbar { display: none; }
/* And the fade at the head of the page, under the logo and the corners, so
   what scrolls up behind them dims out rather than colliding with them. The
   colour is the felt's own at the top of the glass (styles.css, body). */
.screen:not(.match)::before {
  content: ""; position: fixed; left: 0; right: 0; top: 0; z-index: 37;
  height: calc(env(safe-area-inset-top, 0px) + 104px);
  background: linear-gradient(180deg, rgb(43, 26, 10) 0%, rgba(38, 23, 8, .92) 45%, rgba(34, 21, 7, 0) 100%);
  pointer-events: none;
}

/* The room above and below, elastic with the viewport: the fixed logo needs
   its 96px on a tall screen, and on a short one it may have less. */
:root {
  --head-room: clamp(74px, 11.5dvh, 96px); --foot-room: clamp(14px, 3dvh, 36px);
  --col-w: 560px; --deck-gap: clamp(8px, 1.5dvh, 14px);
}
/* The old auth hero offset stood the eyebrow 52px further down than the rest. */
#authScreen .auth-brand { padding-top: 0; }
/* The group picture under the tagline: the whole picture, never cropped, its
   feet fading into the felt so it sits on the page rather than on a card. */
.auth-art { display: grid; justify-items: center; margin-top: 6px; }
.auth-art img {
  width: 100%; max-width: 360px; height: auto; max-height: 36dvh; object-fit: contain;
  /* Dissolved into the felt rather than cut off on it: solid through the
     faces, giving out under the table so the chairs and shoes trail away
     instead of ending on a line. */
  -webkit-mask-image: linear-gradient(180deg, #000 46%, rgba(0, 0, 0, .55) 74%, transparent 97%);
  mask-image: linear-gradient(180deg, #000 46%, rgba(0, 0, 0, .55) 74%, transparent 97%);
  filter: drop-shadow(0 14px 22px rgba(0, 0, 0, .45));
}
@media (min-width: 720px) { .auth-art { justify-items: start; } .auth-art img { max-height: 46dvh; } }

/* THE TWO CORNERS RIDE THE LOGO'S LINE. Fixed at the logo's vertical centre
   (14px + 36px, less half a 38px button), at the column's edges, so people and
   profile flank the name. Home and the Lobby carry them; a screen that also
   has a back arrow and a title keeps those in their own row underneath. */
/* Specificity matters here: the desk's column rule (.screen:not(.match) > *)
   gives every screen child width and centring margins, and a bare .corners
   would lose to it — the bar becomes viewport-wide from left:18px and Profile
   lands 18px past the right edge. Selected as a screen child so this wins. */
.screen:not(.match) > .corners {
  position: fixed; left: 18px; right: 18px; z-index: 39;
  top: calc(env(safe-area-inset-top, 0px) + 31px);
  display: flex; align-items: center; justify-content: space-between;
  /* width from left/right, not from the column rule every screen child gets —
     that rule handed the bar 100% + its margins and pushed Profile off the edge */
  width: auto; max-width: none;
  margin: 0; min-height: 0; padding: 0; pointer-events: none;
}
.corners > * { pointer-events: auto; }
.corners .wordmark { display: none; }
@media (min-width: 600px) {
  .screen:not(.match) > .corners {
    left: max(18px, calc(50% - var(--col-w) / 2)); right: max(18px, calc(50% - var(--col-w) / 2));
  }
}
.screen:not(.match) > * { width: min(100%, var(--col-w)); margin-inline: auto; }

/* The page's arrival is animated in desk.js (Desk.fadeInPage), not here: a CSS
   animation plays once, on first paint, and a screen that is shown again is a
   screen that arrives again. Two of them at once — this rule and that one —
   was one fade too many. */

/* THE DECK: the page's contents. It fills a tall screen — the tablet rows
   stretch to the foot of the glass — and outgrows a short one, at which point
   the screen scrolls. It never shrinks: too tall is a page to scroll, never a
   page to fold. NOT A SCROLL CONTAINER, which is the whole trick: the mode
   rail bleeds past this box to the screen's edges on purpose, and a box that
   clipped it would also have to scroll it — that is what once let a tap on a
   mode card drag the whole page 14px sideways. With overflow visible the rail
   simply runs on, and the SCREEN clips it at the glass. */
.home-body, .lobby-body, .profile-body, .settings-body, .leaderboard-body, .auth-body {
  padding: 0; margin-inline: auto; width: min(100%, var(--col-w));
  flex: 1 0 auto;
  display: flex; flex-direction: column; gap: var(--deck-gap);
  overflow: visible;
}

/* THE ACT IS ALWAYS WITHIN REACH. On a phone the page scrolls, and a PLAY button
   that has scrolled off is a page you have to travel back up to use. Both primary
   actions are pinned to the foot of the glass and the page runs underneath them —
   which is why the screens below carry enough bottom padding for the last thing on
   them to clear the button rather than hide behind it.

   Phones only. A tablet lays the page out in columns with room for the action in
   its own, and there is nothing to scroll past. */
@media (max-width: 719px) {
  #playBtn, #startBtn {
    position: fixed; left: 18px; right: 18px; width: auto; max-width: none;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 14px);
    /* Over the foot mask, which is the fade the page scrolls under (z-index 39). */
    z-index: 41;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .55), 0 0 0 1px rgba(0, 0, 0, .25);
  }
  /* The same selector the base padding uses, or it loses to it: three classes
     beat two whatever the order in the file. */
  .screen:not(.match):not(.auth), .screen.auth {
    /* The button is about 68px tall and sits 14px off the glass; the rest is the
       gap between it and the last thing on the page, so nothing ends underneath. */
    padding-bottom: calc(var(--foot-room) + 96px + env(safe-area-inset-bottom, 0px));
  }
}

/* THE MASK, on a page with more below: the felt's own fade at the foot of the
   screen, saying there is more without a scrollbar saying it. Lifted the
   moment the page reaches its end, because a mask over the last item is a
   mask hiding the thing you scrolled down for. desk.js keeps .at-end true. */
.screen:not(.match):not(.at-end)::after {
  content: ""; position: fixed; left: 0; right: 0; bottom: 0; height: 108px;
  background: linear-gradient(180deg, transparent, #051b10f0 82%);
  pointer-events: none; z-index: 39;
}
/* flex-shrink 0, or a page that outruns its frame lets its columns shrink and
   their contents spill into each other: the seats drawn under the character
   grid, the difficulty tabs over a face. Too tall is a page to scroll or to
   scale, never a page to fold. */
.col { display: flex; flex-direction: column; flex: 0 0 auto; gap: var(--deck-gap); min-width: 0; }
/* Inside a column the gap IS the spacing; a label carrying its own margins
   served the same helping twice and cost a phone thirty pixels a page. */
.col > .grouplab, .col > .section-label { margin: 4px 0 0; }
.col > .note, .col > .lede { margin: 0; }
/* A region that may genuinely outrun the page — a long standings table, a
   table of seats — grows the page, and the page scrolls. Not a scroll
   container of its own: one that was would state a minimum height of nothing
   to the tablet's grid rows, and a 1fr row would fold it to nothing. */
.flexy { flex: 1 1 auto; }

/* ------------------------------------------------------------ the tablet
   A tablet is not a big phone. The single column becomes two — the thing you
   are choosing on the left, the thing you have chosen and the way into it on
   the right — and the page widens to use the glass it is given. */
/* THE PAGE FILLS THE GLASS. Every deck carries three groups — what you are
   choosing, what you have chosen, and the way into it — and the only question
   a wider screen asks is how many columns those three groups get. One on a
   phone, two on a tablet, three when there is genuinely room for three. The
   rows stretch, so the page reaches the foot of the screen by default rather
   than floating in the middle of it. */
@media (min-width: 720px) {
  :root {
    /* A modest ceiling on purpose. Growing the page makes the type bigger but
       NOT the columns wider — the layout is computed before the scale — so a
       tall ceiling squeezes a character's name into three lines to win height
       that the growers below already fill. */
    --col-w: 1080px; --head-room: clamp(84px, 10dvh, 116px);
    /* The greeting is sized for a phone's narrow column; on a tablet the
       viewport-width term runs away with it. A flat ceiling keeps the
       display face a heading, not a banner. */
    --fs-display: 34px; --fs-num: 44px;
  }
  .deck {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr);
    gap: var(--deck-gap) 30px;
    align-content: stretch;
  }
  .deck > .col { gap: clamp(12px, 1.6dvh, 18px); }

  /* A BAND RUNS THE WHOLE WIDTH, and the columns begin beneath it. The
     greeting is the page saying hello; it is not a column of anything. */
  .deck > .band { grid-column: 1 / -1; grid-row: 1; }
  .home-body { grid-template-rows: auto 1fr auto; }
  .home-body > .col-lead { grid-row: 2 / span 2 !important; }
  .home-body > .col-main { grid-row: 2 !important; }
  .home-body > .col-act  { grid-row: 3 !important; }

  /* TWO COLUMNS: the first group takes the left, the other two stack on the
     right. The left column spans both rows, so it is a column and not a card
     with a hole under it. */
  .home-body > .col-lead, .lobby-body > .col-lead, .profile-body > .col-lead {
    grid-column: 1; grid-row: 1 / span 2;
  }
  .home-body > .col-main, .lobby-body > .col-main, .profile-body > .col-main {
    grid-column: 2; grid-row: 1;
  }
  .home-body > .col-act, .lobby-body > .col-act, .profile-body > .col-act {
    grid-column: 2; grid-row: 2;
  }

  /* The last group's foot sits at the page's foot. A label that opens a second
     idea takes the slack above it (so "Join a table" and its field stay one
     thing, at the bottom), and a block button that ends a column stands at the
     bottom of it — Start Match at the foot of the rules, where it belongs. */
  .deck > .col-act > .grouplab:not(:first-child) { margin-top: auto; }
  .deck > .col-act > .btn.block:last-child { margin-top: auto; }

  /* A group that is one thing takes its whole column, and holds that thing in
     the middle of it — a join code the size of the column is the lobby's
     point, not a card stranded at the top of an empty stripe. */
  .col > :only-child { flex: 1 1 auto; }
  .col > .card:only-child { display: grid; align-content: center; }

  /* ON A TABLET THE RAIL IS A LIST. A carousel exists because a phone has one
     column and four modes; a tablet column has the height to show all four at
     once, and swiping through what is already on screen is a worse way to
     choose. The rail becomes a stack, the dots stand down, and the column
     fills with cards rather than with one card stretched to look like four. */
  .col > .carousel-card.peek { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; padding-bottom: 0; }
  .col > .carousel-card.peek .carousel-rail {
    display: grid; grid-auto-flow: row; gap: 12px;
    flex: 1 1 auto; min-height: 0; padding: 2px 0;
    overflow-x: hidden; overflow-y: auto; scroll-snap-type: none;
    scrollbar-width: none;
  }
  .col > .carousel-card.peek .carousel-rail::-webkit-scrollbar { display: none; }
  .col > .carousel-card.peek .carousel-slide { flex: none; scroll-snap-align: none; }
  .col > .carousel-card.peek .mode { min-height: 112px; align-content: center; }
  .col > .carousel-card.peek .mode-face {
    top: 0; right: 0; height: 128%; max-width: 50%; object-position: top right;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 45%), linear-gradient(180deg, #000 45%, transparent 68%);
    mask-image: linear-gradient(90deg, transparent, #000 45%), linear-gradient(180deg, #000 45%, transparent 68%);
    -webkit-mask-composite: source-in; mask-composite: intersect;
  }
  .col > .carousel-card.peek .mode-text { max-width: 64%; }
  .col > .carousel-card.peek .mode-face.group {
    left: auto; right: 0; top: 4px; width: 46%; height: calc(100% - 8px); max-width: 46%;
    object-fit: cover; object-position: top center;
    transform: none; transform-origin: right center;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%), linear-gradient(180deg, #000 72%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent, #000 18%), linear-gradient(180deg, #000 72%, transparent 100%);
    -webkit-mask-composite: source-in; mask-composite: intersect;
  }
  .col > .carousel-card.peek .mode[aria-pressed="true"] .mode-face.group { transform: scale(1.04); }
  .col > .carousel-card.peek .mode-name { font-size: 22px; }
  .col > .carousel-card.peek .carousel-dots { display: none; }
  /* The chosen mode reads top to bottom over the height it is given. */
  .col > .mode-detail, .card.hero.mode-detail { align-content: space-between; }

  /* Community keeps one deck: the tabs span, the pane below them splits. */
  .leaderboard-body, .auth-body { grid-template-columns: minmax(0, 1fr); }
  .leaderboard-body > .col, .auth-body > .col { grid-column: 1; }
  .auth-body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .auth-body > .col-lead { grid-column: 1; grid-row: 1; }
  .auth-body > .col-main { grid-column: 2; grid-row: 1; align-content: center; }
  .auth-brand { text-align: left; }
  #authScreen .auth-brand .tagline { margin-right: 0; }
}
@media (min-width: 720px) and (max-width: 899px) {
  .deck { gap: var(--deck-gap) 22px; }
}

/* THREE COLUMNS IN LANDSCAPE, two in portrait. The owner's rule, and the right
   one: a tablet held upright has the height to stack two groups and not the
   width to stand three, and turned on its side it has exactly the reverse. */
@media (min-width: 900px) and (orientation: landscape) {
  :root { --col-w: 1240px; }
  .home-body, .lobby-body, .profile-body {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  /* Three across, all of them under the band. */
  .home-body { grid-template-rows: auto 1fr; }
  .home-body > .col-lead, .home-body > .col-main, .home-body > .col-act {
    grid-row: 2 !important;
  }
  .home-body > .col-lead, .lobby-body > .col-lead, .profile-body > .col-lead {
    grid-column: 1; grid-row: 1;
  }
  .home-body > .col-main, .lobby-body > .col-main, .profile-body > .col-main {
    grid-column: 2; grid-row: 1;
  }
  .home-body > .col-act, .lobby-body > .col-act, .profile-body > .col-act {
    grid-column: 3; grid-row: 1;
  }
  :root { --fs-display: 38px; }
  /* PLAY is the biggest thing in its own column, as it should be. */
  .col-act > .btn.play { min-height: 68px; font-size: 19px; }
}

/* --------------------------------------------------------------- headers */

/* Sapien's page-top: an eyebrow and a title on the left, the avatar on the
   right. The logo lives above all of it, fixed, as it already did. */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 0; min-height: 38px; margin: 0 0 6px;
}
/* THE BACK BUTTON TAKES THE TOP-LEFT CORNER WHEN NOTHING ELSE IS THERE.
   On Profile and Community that corner is empty, so the chevron rides the
   logo's line where every other screen's top-left control sits — the same
   coordinates as `.corners`, so it lands in exactly the same place as the
   Community icon does on Home. On the Lobby, where the corners ARE there, it
   stays in its own row: `:has(> .corners)` is what asks the question. */
.screen:not(.match):not(:has(> .corners)) > .topbar > .back-btn {
  position: fixed; z-index: 39;
  left: 18px;
  top: calc(env(safe-area-inset-top, 0px) + 31px);
}
@media (min-width: 600px) {
  .screen:not(.match):not(:has(> .corners)) > .topbar > .back-btn {
    left: max(18px, calc(50% - var(--col-w) / 2));
  }
}
/* The title takes the room the button left, lining up with the page under it
   rather than hanging off an indent nothing occupies any more. */

.topbar-title {
  flex: 1; text-align: left;
  font-size: 12.5px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink);
}
.topbar .wordmark { display: none; }   /* the real logo sits above every screen */

.eyebrow {
  font-size: 10px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--dim); margin: 0 0 8px; font-weight: 600;
}
.eyebrow.brass { color: var(--brass-300); }
.greet {
  font-size: var(--fs-display); font-weight: 800; letter-spacing: -0.02em; line-height: 1.1;
  margin: 6px 0 10px; color: var(--ink);
}
.greet em { font-style: normal; color: var(--brass-300); }
p.lede, .lede { color: var(--muted); font-size: 14px; line-height: 1.5; margin: 0 0 14px; }
.grouplab {
  font-size: 10px; font-weight: 700; letter-spacing: .19em; text-transform: uppercase;
  color: var(--muted); margin: 18px 0 9px;
}
.grouplab em { font-style: normal; font-weight: 500; font-size: 11px; letter-spacing: 0;
  text-transform: none; color: var(--dim); margin-left: 8px; }
.section-label { /* the old label, restated as a grouplab */
  font-size: 10px; font-weight: 700; letter-spacing: .19em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}
.next-line { margin: 14px 2px 0; font-size: 12.5px; color: var(--dim); text-align: center; line-height: 1.5; }

/* Round glass buttons at the corners of a page: back, settings, the avatar. */
.icon-btn, .avatar:not(.big):not(.drawer-face):not(.corner-avatar) {
  width: 38px; height: 38px; border-radius: 999px; flex: none;
  display: grid; place-items: center;
  /* background-COLOR, not the shorthand: the shorthand resets background-size,
     and an avatar's photo then rendered at its natural size — a picture far too
     big for its circle, showing one corner of itself. */
  background-color: var(--glass); backdrop-filter: blur(22px) saturate(170%);
  -webkit-backdrop-filter: blur(22px) saturate(170%);
  border: 1px solid var(--hair); color: var(--muted);
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
  transition: all .4s var(--ease); overflow: hidden;
}
.icon-btn:hover, .avatar:hover { color: var(--ink); border-color: var(--hair-bright); }
.icon-btn.ghosted { background: none; border-color: transparent; pointer-events: none;
  backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: none; }
.avatar, .avatar.big, .avatar.drawer-face {
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.avatar.big {
  width: 84px; height: 84px; border-radius: 999px; margin: 0 auto 12px;
  border: 1px solid var(--hair-bright); background-color: var(--fill);
  display: grid; place-items: center; font-size: 30px; font-weight: 800; color: var(--ink);
}

/* ------------------------------------------------------------------ cards */

.panel, .card {
  background: var(--fill); border: 1px solid var(--hair); border-radius: var(--r-card);
  padding: 18px; box-shadow: none; margin: 0;
}
.card.hero { border-radius: var(--r-hero); padding: 22px 20px; }
.card-line { margin: 0; font-size: 15px; color: var(--ink); }
.cards-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: stretch; }
.cards-row > * { min-height: 100%; }
.bignum { font-size: var(--fs-num); font-weight: 800; font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em; line-height: 1; color: var(--ink); }
.bignum em { font-style: normal; font-size: .42em; font-weight: 700; color: var(--muted); }

.note {
  border-radius: 16px; padding: 14px 16px; margin: 0;
  background: var(--fill-soft); border: 1px solid var(--hair);
  color: var(--muted); font-size: 12.5px; line-height: 1.5;
}
.note b { color: var(--ink); }
.note.halt { background: rgba(217, 140, 121, .08); border-color: rgba(217, 140, 121, .28); color: #e8b2a4; }

/* ---------------------------------------------------------------- actions */

/* Sapien's cta: a full-width pill, small caps, heavy, tracked. The primary
   one is brass here — it is the one thing on the screen to press. */
.cta, .btn.block {
  width: 100%; margin: 0; border: 1px solid transparent; border-radius: 999px;
  padding: 15px 18px; min-height: 50px;
  font-family: var(--font-sans); font-size: 11.5px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase;
  background: var(--accent); color: var(--accent-ink);
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  cursor: pointer; transition: all .4s var(--ease); box-shadow: none; text-shadow: none;
}
.cta:hover:not(:disabled):not(.ghost):not(.quiet), .btn.block.primary:hover:not(:disabled) {
  box-shadow: 0 0 26px var(--accent-glow); transform: translateY(-1px);
}
.cta:active:not(:disabled), .btn.block:active:not(:disabled) { transform: translateY(0) scale(.99); }
.cta:disabled, .btn.block:disabled { opacity: .32; cursor: not-allowed; background: var(--accent); color: var(--accent-ink); }
.cta.ghost, .btn.block.ghost {
  background: transparent; color: var(--accent); border-color: var(--accent-line); box-shadow: none;
}
.cta.ghost:hover:not(:disabled), .btn.block.ghost:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent-line); }
.cta.quiet, .btn.block.quiet {
  background: transparent; color: var(--muted); border-color: transparent; text-transform: none;
  letter-spacing: 0; font-size: 13px; font-weight: 600; min-height: 44px; padding: 10px;
}
.cta.quiet:hover:not(:disabled) { color: var(--ink); }
.btn.block.primary { background: var(--brass); color: #1b1108; border-color: transparent; }
.btn.block.primary:hover:not(:disabled) { box-shadow: 0 0 26px var(--brass-glow); }

/* PLAY keeps the game's green and the brass edge: it is the door to the table,
   and the one place on the desk the table's own colours are allowed to speak. */
.btn.play {
  width: 100%; border-radius: 999px; padding: 19px; min-height: 64px; margin: 0;
  font-family: var(--font-sans); font-size: 17px; font-weight: 800; letter-spacing: .2em;
  background: linear-gradient(180deg, #2f9a5c 0%, var(--go) 100%);
  color: #fdf6e4; border: 2px solid var(--brass);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35), 0 12px 32px rgba(0, 0, 0, .5),
    0 0 24px var(--brass-glow), 0 1px 0 #ffffff33 inset;
  text-shadow: 0 1px 0 #0b3a20; transition: all .4s var(--ease);
}
.btn.play:hover:not(:disabled) { box-shadow: 0 0 0 1px rgba(0,0,0,.35), 0 14px 34px rgba(0, 0, 0, .55), 0 0 36px var(--brass-glow), 0 1px 0 #ffffff33 inset; transform: translateY(-1px); }
.btn.play .chev { color: var(--brass-300); opacity: .95; font-size: 15px; }

.btn-icon {
  display: inline-grid; place-items: center; width: 18px; height: 18px; margin: 0;
  border-radius: 4px; background: #fff; color: #17140f; font-weight: 800; font-size: 11px;
}
.btn-icon svg { width: 16px; height: 16px; display: block; }

/* GOOGLE'S BUTTON, TO GOOGLE'S RULES: white, a grey hairline, the G at 20px
   with its own clear space, "Sign in with Google" in Roboto Medium at 14px
   where Roboto exists and the system face where it does not. The brass pill
   it replaced was ours, and a sign-in button that is not recognisably
   Google's is one people hesitate over. */
.btn.block.google {
  background: #fff; color: #1f1f1f; border: 1px solid #747775;
  font-family: Roboto, var(--font-sans); font-weight: 500; font-size: 14px; letter-spacing: 0.01em;
  text-transform: none; gap: 10px;
}
.btn.block.google:hover:not(:disabled) { background: #f2f2f2; box-shadow: 0 1px 2px rgba(60, 64, 67, .3), 0 1px 3px 1px rgba(60, 64, 67, .15); }
.btn.block.google:disabled { background: #ffffff1f; color: #1f1f1f61; border-color: #1f1f1f1f; }
.btn.block.google .btn-icon { width: 20px; height: 20px; background: none; border-radius: 0; }
.btn.block.google .btn-icon svg { width: 20px; height: 20px; }

.mini {
  border-radius: 999px; padding: 7px 13px; font: inherit; font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  background: var(--fill); border: 1px solid var(--hair); cursor: pointer;
  transition: all .4s var(--ease);
}
.mini:hover { color: var(--ink); border-color: var(--hair-bright); }
.mini.brass { color: var(--brass-300); border-color: var(--brass-line); background: var(--brass-soft); }

/* THE DEAL, SEEN. A seat mid-riffle is lifted and lit; the one that has just
   landed takes a beat to settle. The dice on the Random tile tumbles while it
   runs, so the tile that was tapped is visibly the thing doing the work. */
.seat-tile.dealing .seat-face {
  animation: deal-riffle .28s ease-in-out infinite alternate;
  box-shadow: 0 0 0 2px var(--brass-line), 0 6px 18px rgba(0, 0, 0, .45);
}
.seat-tile.landed .seat-face { animation: deal-land .42s var(--ease) both; }
@keyframes deal-riffle { from { transform: translateY(0) scale(1); } to { transform: translateY(-2px) scale(1.045); } }
@keyframes deal-land {
  0% { transform: scale(1.16); box-shadow: 0 0 0 3px var(--brass-line); }
  60% { transform: scale(.98); }
  100% { transform: scale(1); box-shadow: none; }
}
.cast-tile.random.rolling .cast-dice { animation: dice-tumble .5s linear infinite; }
/* Carries the die's resting angle through the spin, or it snaps upright the
   moment a deal starts. */
@keyframes dice-tumble {
  from { transform: rotate(-12deg); }
  to { transform: rotate(348deg); }
}
@media (prefers-reduced-motion: reduce) {
  .seat-tile.dealing .seat-face, .seat-tile.landed .seat-face,
  .cast-tile.random.rolling .cast-dice { animation: none; }
}

/* THE HIDDEN ATTRIBUTE MEANS HIDDEN. The browser's own `[hidden] { display:
   none }` is a UA rule, so ANY author rule that sets `display` beats it — which
   is why a hidden form with `display: grid` kept showing, and why half a dozen
   one-off `.thing[hidden] { display: none }` rules had accumulated below.
   Stated once, here.

   `.stop-throwing` is the deliberate exception: it stays laid out and invisible
   so the toolbar does not jump when it comes and goes (styles.css). */
[hidden]:not(.stop-throwing) { display: none !important; }

/* The email form, revealed under the two buttons. Its own stack rather than
   the actions' gap, so the three fields read as one thing to fill in. */
.email-form { display: grid; gap: 10px; }
.email-form .field { width: 100%; }
.email-alt { display: flex; gap: 8px; justify-content: space-between; flex-wrap: wrap; }
.email-alt .btn { padding-inline: 4px; font-size: 12.5px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.rule { display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: center; margin: 4px 0; }
.rule::before, .rule::after { content: ""; height: 1px; background: var(--hair); }
.rule span { color: var(--dim); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; }

/* ----------------------------------------------------------------- fields */

.field, input[type="text"], .select {
  width: 100%; border-radius: 16px; padding: 14px 16px; min-height: 50px;
  background: var(--fill); border: 1px solid var(--hair); color: var(--ink);
  font: inherit; font-family: var(--font-sans); font-size: 15px;
  transition: border-color .4s var(--ease);
}
.field::placeholder, input[type="text"]::placeholder { color: var(--dim); }
.field:focus, input[type="text"]:focus, .select:focus { outline: none; border-color: var(--brass-line); }
.select { appearance: none; -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 22px) 55%, calc(100% - 17px) 55%; background-size: 5px 5px; background-repeat: no-repeat; }
.join-row { display: flex; gap: 8px; }
.join-row input { text-transform: uppercase; letter-spacing: .22em; font-weight: 700; }
.join-row .btn { flex: none; width: auto; padding-inline: 20px; }

/* ------------------------------------------------- settings rows and chips */

.set-group {
  border-radius: var(--r-card); background: var(--fill); border: 1px solid var(--hair);
  overflow: hidden; margin: 0;
}
.set-row, .row-toggle {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 15px 16px; border-bottom: 1px solid var(--hair); margin: 0;
  color: var(--ink); font: inherit; font-family: var(--font-sans); background: none; border-inline: 0; border-top: 0;
  min-height: clamp(48px, 6.6dvh, 56px); cursor: default;
}
.set-row:last-child, .row-toggle:last-child, .row-toggle:last-of-type { border-bottom: none; }
button.set-row { cursor: pointer; transition: background .4s var(--ease); }
button.set-row:hover { background: var(--fill-hover); }
.set-row > b, .row-title { font-weight: 650; font-size: 15px; display: block; }
.set-row small, .row-sub { display: block; font-size: 12px; line-height: 1.45; color: var(--dim); margin-top: 3px; font-weight: 400; }
.set-row .spacer { flex: 1; }
.set-row .value { color: var(--muted); font-size: 13px; margin-left: auto; }
.set-row .go { color: var(--dim); margin-left: auto; }
.set-stack { flex-direction: column; align-items: stretch; gap: 0; }
.set-stack .chips { margin: 10px 0 0; }
.set-stack small { margin-top: 10px; }
.row-toggle > span:first-child { flex: 1; }
.row-range { padding: 15px 16px; border-bottom: 1px solid var(--hair); display: grid; grid-template-columns: 1fr auto; gap: 8px 12px; }
.row-range:last-child { border-bottom: none; }
.row-range input[type="range"] { grid-column: 1 / -1; accent-color: var(--brass); }
.row-value { color: var(--brass-300); font-size: 13px; font-weight: 600; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
.chip {
  border-radius: 999px; padding: 9px 15px; font: inherit; font-family: var(--font-sans); font-size: 12.5px;
  color: var(--muted); background: var(--fill); border: 1px solid var(--hair); cursor: pointer;
  transition: all .4s var(--ease);
}
.chip:hover { color: var(--ink); border-color: var(--hair-bright); }
.chip[data-on="1"], .chip.on { color: var(--brass-300); border-color: var(--brass-line); background: var(--brass-soft); }

/* The switch. Sapien uses chips for two-state settings; the toggles here are
   real and already wired, so they stay — restated as a pill in the brand. */
.row-toggle input[type="checkbox"] {
  appearance: none; flex: none; width: 46px; height: 27px; border-radius: 999px;
  background: var(--track); border: 1px solid var(--hair); position: relative; cursor: pointer;
  transition: background .3s var(--ease), border-color .3s var(--ease); margin: 0;
}
.row-toggle input[type="checkbox"]::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 21px; height: 21px; border-radius: 50%;
  background: var(--muted); transition: transform .3s var(--ease), background .3s var(--ease);
}
.row-toggle input[type="checkbox"]:checked { background: var(--brass-soft); border-color: var(--brass-line); }
.row-toggle input[type="checkbox"]:checked::after { transform: translateX(19px); background: var(--brass-300); }

/* ---------------------------------------------------------- segmented tabs */

/* A grey track with one raised pill that SLIDES to the selected tab. The
   thumb is one element translated by its own width per index, so the
   movement reads as the selection travelling; the labels only change colour. */
.seg {
  position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  width: fit-content; max-width: 100%; align-self: flex-start;
  background: var(--track); border-radius: 999px; padding: 4px;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .35), inset 0 0 1px rgba(0, 0, 0, .2);
}
.seg.block { display: grid; width: 100%; }
.seg-thumb {
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  border: 1px solid var(--brass-line);
  width: calc((100% - 8px) / var(--seg-n, 2));
  transform: translateX(calc(var(--seg-i, 0) * 100%));
  transition: transform .32s var(--ease);
  background: var(--seg-fill); border-radius: 999px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 3px 10px rgba(0, 0, 0, .25);
}
.seg-tab {
  position: relative; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 16px; border-radius: 999px; border: 0; background: none; cursor: pointer;
  font: inherit; font-family: var(--font-sans); font-size: 12.5px; font-weight: 600; color: var(--muted);
  white-space: nowrap; transition: color .32s var(--ease);
}
.seg-tab:hover { color: var(--ink); }
.seg-tab[aria-selected="true"] { color: var(--brass-300); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .seg-thumb { transition: none; } }

/* The standings' mode tabs are five labels, which is more than a phone's
   width shares out; equal columns put them in one another's laps. A rail
   instead: each tab its own width, the row scrolling, the chosen one filled
   rather than pointed at by a thumb that cannot know where it is. */
#boardModeTabs .seg {
  display: flex; width: 100%; gap: 2px; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain;
  /* Its five labels must not be its intrinsic width, or the pane — and the
     page — grows to fit them and the whole screen runs off the right edge. */
  contain: inline-size;
}
.community-pane { min-width: 0; max-width: 100%; }
#boardModeTabs .seg::-webkit-scrollbar { display: none; }
#boardModeTabs .seg-thumb { display: none; }
/* Sticky pseudo-elements rather than fixed overlays: they ride the scroller,
   so they sit at the visible edge whatever the rail has been dragged to, and
   they take no room (the negative margin gives back what the width takes). */
/* THE WAIT, EVERYWHERE: the table's own die, turning. One rule, so a loading
   state anybody adds later looks like every other one without having to know
   what the others did. */
/* CENTRED ON THE SCREEN, not at the top of a box. A wait is the only thing
   happening, so it takes the room and sits in the middle of it — the die, and
   under it the word for what is being waited for. */
.waiting {
  display: grid; place-content: center; justify-items: center; gap: 16px;
  /* Deep enough that the pair lands on the middle of the GLASS rather than the
     middle of the box: the header takes the top ~140px, so the box has to run
     past the halfway line for its centre to sit on it. */
  min-height: min(66dvh, 560px);
  color: var(--dim); font-size: 12px;
  letter-spacing: 0.18em; text-transform: uppercase;
}
.waiting-word { text-align: center; }
/* Nothing but the die while it turns: no card, no hairline, no caption. */
.waiting-host {
  background: none !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
.waiting-die {
  width: 68px; height: 68px; display: block;
  animation: die-wait 1.1s cubic-bezier(.5, 0, .5, 1) infinite;
  filter: drop-shadow(0 8px 12px rgba(0, 0, 0, .5));
}
/* Turned in quarters with a pause at each, which is a die being rolled rather
   than a wheel spinning: a constant rotation reads as machinery. */
@keyframes die-wait {
  0%   { transform: rotate(0deg) scale(1); }
  55%  { transform: rotate(180deg) scale(1.06); }
  100% { transform: rotate(360deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .waiting-die { animation: none; opacity: .8; }
}

/* A button doing the work it was pressed for. */
.btn.busy { pointer-events: none; }
.busy-die {
  width: 24px; height: 24px; display: block; margin-inline: auto;
  animation: die-wait 1.1s cubic-bezier(.5, 0, .5, 1) infinite;
}
@media (prefers-reduced-motion: reduce) { .busy-die { animation: none; } }

/* THE SEARCH FIELD: the desk's own input with the glass in it. The icon is
   inside the box rather than beside it, so the whole thing reads as one control
   and the tap target is the field. */
.search-field { position: relative; display: block; }
.search-field .search-mark {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--dim); pointer-events: none;
}
.search-field input[type="search"] {
  width: 100%; border-radius: 999px; padding: 13px 16px 13px 42px; min-height: 48px;
  background: var(--fill); border: 1px solid var(--hair); color: var(--ink);
  font: inherit; font-family: var(--font-sans); font-size: 15px;
  transition: border-color .4s var(--ease), background .4s var(--ease);
  -webkit-appearance: none; appearance: none;
}
.search-field input[type="search"]::placeholder { color: var(--dim); }
.search-field input[type="search"]:focus {
  outline: none; border-color: var(--brass-line); background: var(--fill-hover);
}
/* The browser's own clear button is a grey X on a dark field. Ours, or none. */
.search-field input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
.search-field:focus-within .search-mark { color: var(--brass-300); }

/* A found player: their face, their name, and how they have done — the same
   three things a standings row shows, because that is all a search is allowed
   to know about somebody. */
.friend-results { display: grid; gap: 8px; margin-top: 12px; }
.friend-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: 999px;
  background: var(--fill); border: 1px solid var(--hair);
  transition: border-color .4s var(--ease), background .4s var(--ease);
}
.friend-row:hover { border-color: var(--hair-bright); background: var(--fill-hover); }
.friend-row .face { width: 34px; height: 34px; font-size: 13px; }
.friend-who {
  font-weight: 700; font-size: 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.friend-record {
  color: var(--dim); font-size: 11px; white-space: nowrap;
  letter-spacing: 0.04em;
}
/* Where the two of you already stand, when there is nothing left to press. */
.friend-mark {
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--brass-300); white-space: nowrap;
}
.friend-row .btn.mini { padding: 7px 12px; font-size: 12px; min-height: 0; }
/* THE ADDRESS BOOK. One card, hairlines between the names, a letter above each
   run of them — the shape a phone's contacts have, because that is the shape
   people can already read without being taught it. */
.contact-book {
  border-radius: var(--r-card, 18px);
  background: var(--fill); border: 1px solid var(--hair);
  overflow: hidden;
}
.contact-letter {
  padding: 7px 16px 6px;
  background: var(--track);
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.16em;
  color: var(--brass-300);
}
.contact-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--hair);
}
.contact-row:last-child { border-bottom: 0; }
.contact-row .face { width: 34px; height: 34px; font-size: 13px; }
.contact-who {
  font-size: 14px; font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.contact-won { color: var(--dim); font-size: 11px; white-space: nowrap; letter-spacing: 0.04em; }
.contact-won b {
  color: var(--ink); font-size: 15px; font-weight: 800; margin-right: 4px;
  font-variant-numeric: tabular-nums;
}

.friend-lists { display: grid; gap: 8px; margin-top: 18px; }
.friend-lists > .grouplab:not(:first-child) { margin-top: 10px; }

/* ONLY on the rail. The other tab strips are `display: grid`, where a
   pseudo-element is a CELL — two invisible fades there took two columns and
   squashed the labels into the left of the pill. */
#boardModeTabs .seg::before, #boardModeTabs .seg::after {
  content: ""; position: sticky; flex: none; align-self: stretch;
  width: 26px; z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity .25s var(--ease);
}
#boardModeTabs .seg::before { left: 0; margin-right: -26px; background: linear-gradient(90deg, var(--track), transparent); }
#boardModeTabs .seg::after { right: 0; margin-left: -26px; background: linear-gradient(270deg, var(--track), transparent); }
#boardModeTabs .seg[data-edge="both"]::before, #boardModeTabs .seg[data-edge="start"]::before { opacity: 1; }
#boardModeTabs .seg[data-edge="both"]::after, #boardModeTabs .seg[data-edge="end"]::after { opacity: 1; }
#boardModeTabs .seg-tab { flex: 0 0 auto; padding: 9px 14px; }
#boardModeTabs .seg-tab[aria-selected="true"] { background: var(--seg-fill); }

/* ----------------------------------------------------------------- carousel */

/* THE CARD DOES NOT MOVE. What swipes is its contents. Scroll-snap does the
   work: the browser already knows how to swipe a horizontal list with the
   platform's own physics, and all this adds is the dot row. */
.carousel-card { position: relative; overflow: hidden; padding: 0 0 26px; }
.carousel-rail {
  display: flex; align-items: stretch; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.carousel-rail::-webkit-scrollbar { display: none; }
.carousel-slide { flex: 0 0 100%; min-width: 0; scroll-snap-align: center; display: flex; align-items: stretch; }
.carousel-dots {
  position: absolute; right: 18px; bottom: 14px; display: flex; gap: 6px;
}
.carousel-dot {
  width: 6px; height: 6px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  background: var(--hair-bright); transition: all .32s var(--ease);
}
.carousel-dot[data-on="1"] { background: var(--brass-300); width: 16px; }

/* THE PEEK RAIL. Not one face at a time: cards a little under half the width,
   so two sit in view and the third shows its edge — the edge is what says
   "there is more", which is why there are no dots. The rail bleeds to the
   screen's edges and scroll-padding brings each card back in line with the
   column when it snaps. Choosing is a tap, and the chosen card wears brass. */
@media (min-width: 720px) {
  /* A tablet's rail is a list inside a column, and a list that ran off the
     glass would be a list with its right-hand side missing. */
  /* Selected through .col so it outranks the phone's bleed, which is written
     later in the file and would otherwise win on source order alone — as it did,
     leaving a tablet's list hanging off the left edge of the glass. */
  .col > .carousel-card.peek { margin-inline: 0; width: 100%; padding-bottom: 0; }
  .col > .carousel-card.peek .carousel-rail { padding-inline: 0; scroll-padding-inline: 0; }
  .col > .carousel-card.peek .carousel-dots { margin-inline: 0; }
  .carousel-card.peek .carousel-slide { flex: 0 0 min(46%, 210px); }
}
/* THE RAIL RUNS OFF THE GLASS. The next card is cut by the edge of the screen,
   not by the edge of the text column, because that is what says there is more
   to the right — a card that stops neatly at the margin looks like the last one.
   Safe now that the deck is not a scroll container (see .deck above): the rail
   overflows into the screen's padding and the screen clips it. */
.carousel-card.peek {
  background: none; border: 0; border-radius: 0; padding: 0 0 26px;
  /* Both halves of the bleed. The negative margins alone only move the box:
     a box with a definite width does not grow to fill a negative right margin,
     so the rail hung off the left edge and stopped short of the right one. The
     width says how much wider than its column it is; the margins say where that
     extra goes. */
  margin-inline: -18px; width: calc(100% + 36px);
  overflow: visible;
}
.carousel-card.peek .carousel-rail {
  gap: 10px; padding: 4px 18px 6px; scroll-padding-inline: 18px;
  scroll-snap-type: x mandatory;
}
/* 42%: two cards, two gaps and the column's inset leave about 23px of the
   third card showing on a 375px phone — the edge that says there is more. */
.carousel-card.peek .carousel-slide { flex: 0 0 min(42%, 175px); scroll-snap-align: start; }
/* Dots under the peek rail, centred, in the flow: they say where you are
   along the rail, and nothing about which card is chosen — brass says that. */
.carousel-card.peek .carousel-dots {
  position: static; display: flex; justify-content: center; gap: 6px;
  padding: 12px 0 0; margin-inline: 18px;
}

/* A MODE IS A POSTER: a face in the top half, the name in the display face
   at the foot, and a line under it. The portrait fades into the card before
   it reaches the type, so the two never fight. */
.mode {
  position: relative; overflow: hidden; isolation: isolate;
  display: grid; grid-template-columns: 1fr; gap: 4px; align-content: end; text-align: left; width: 100%;
  background: var(--fill); border: 1px solid var(--hair); border-radius: 22px;
  padding: 16px 15px 17px; color: var(--ink); font: inherit; font-family: var(--font-sans);
  cursor: pointer; min-height: 178px;
  transition: border-color .4s var(--ease), background .4s var(--ease), transform .4s var(--ease), opacity .4s var(--ease);
  box-shadow: none;
}
.mode:hover { transform: translateY(-1px); border-color: var(--hair-bright); }
.mode.selected, .mode[aria-pressed="true"] {
  border-color: var(--brass-line); background: var(--brass-soft);
  box-shadow: 0 0 0 1px var(--brass-line), 0 10px 26px rgba(0, 0, 0, .35);
}
.mode-face {
  position: absolute; top: 4px; right: -4%; z-index: -1;
  /* A full-length figure, as tall as the card and cropped by it: the head
     and the gesture in the top half, the legs lost under the type. */
  height: 100%; width: auto; max-width: none;
  object-fit: contain; object-position: top right;
  pointer-events: none; user-select: none;
  opacity: .88;
  /* THE COLOUR IS THE CHOICE. Every card but the chosen one is muted — held
     back rather than drained, so a pink hoodie is still a pink hoodie and the
     rail still reads as one lit poster among several waiting ones. */
  filter: grayscale(.7) saturate(.68);
  -webkit-mask-image: linear-gradient(180deg, #000 42%, transparent 74%);
  mask-image: linear-gradient(180deg, #000 42%, transparent 74%);
  transform-origin: top right;
  transition: transform .5s var(--ease), opacity .4s var(--ease), filter .4s var(--ease);
}
.mode[aria-pressed="true"] .mode-face { opacity: 1; filter: none; transform: scale(1.05); }
.mode:not([aria-pressed="true"]):hover .mode-face { filter: grayscale(.45) saturate(.85); }
/* A GROUP OF THREE, CROPPED AT THE LEGS AND NEVER AT THE FACES. The picture
   fills the card's width and is cut off at the bottom by its own box, which
   is what keeps the card short and the heads big — fitting all three whole
   would mean either a much taller card or three faces the size of a thumbnail.
   Anchored to the top, so what the box takes is always the legs, and faded
   out over the last third so the cut reads as a fade rather than a chop.
   (The version before this one centred a picture WIDER than the card and lost
   35px off each side, which took the outer two of the three faces.) */
.mode-face.group {
  left: 0; right: 0; top: 6px; width: 100%; max-width: 100%; height: 68%;
  object-fit: cover; object-position: top center;
  transform: none; transform-origin: top center;
  -webkit-mask-image: linear-gradient(180deg, #000 64%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 64%, transparent 100%);
}
.mode[aria-pressed="true"] .mode-face.group { transform: scale(1.04); }

/* THE CHOSEN CARD IS THE LIT ONE. The rest of the rail sits back, so the
   choice reads at a glance rather than from the brass hairline alone. */
.mode:not([aria-pressed="true"]) { opacity: .58; }
/* A locked card is a door, not a wall: it says what it wants and opens the
   sign-in screen. Dimmer than a card merely not chosen, and its eyebrow is
   the reason rather than the mode's own line. */
.mode.locked { opacity: .42; }
.mode.locked .mode-eyebrow { color: var(--dim); }
.mode.locked .mode-face { filter: grayscale(1) saturate(.5); }
.mode:not([aria-pressed="true"]):hover { opacity: .78; }
@media (prefers-reduced-motion: reduce) { .mode { transition: none; } }
.mode-emblem { display: none; }
.mode-text { display: grid; gap: 3px; }
.mode-eyebrow {
  font-size: 10px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--brass-300); line-height: 1.2;
}
.mode-name {
  font-family: "Georgia", "Iowan Old Style", serif; font-weight: 700;
  /* 19px: the widest name, "Private online", on one line in a phone's card. */
  font-size: 19px; letter-spacing: -0.01em; line-height: 1.05; color: var(--cream-100, var(--ink));
}
.mode-go { display: none; }

/* The chosen mode, in full, with the player's own record in it. */
.mode-detail { display: grid; gap: 16px; position: relative; overflow: hidden; isolation: isolate; }
.mode-detail > * { position: relative; }
/* The body is static so the face positions against the card, not the body. */
.mode-detail > .detail-body { position: static; display: grid; gap: 14px; }

/* The same face, larger, over the shoulder of the title. */
.mode-detail .detail-face {
  position: absolute; right: -4%; top: -10px; z-index: -1;
  height: 250px; width: auto; max-width: 56%;
  object-fit: contain; object-position: top right;
  pointer-events: none; user-select: none; opacity: .92;
  -webkit-mask-image: linear-gradient(180deg, #000 40%, transparent 72%);
  mask-image: linear-gradient(180deg, #000 40%, transparent 72%);
}
/* Wholly inside the card — a box hung 10px above its top edge cost the group
   the tops of their heads, which the card's own overflow then hid. */
.mode-detail .detail-face.group {
  /* Cropped at the legs like the posters, and no taller than the title and
     the line under it: past that the group walks across the record below,
     which is text to read rather than a background to decorate. */
  height: 152px; top: 4px; right: 0; width: 46%; max-width: 46%;
  object-fit: cover; object-position: top center;
  /* Faded on its left as well as its foot: the type stops before the picture
     starts (the paddings below), and a hard vertical edge where the two meet
     would draw the line the fade is there to soften. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 20%), linear-gradient(180deg, #000 62%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent, #000 20%), linear-gradient(180deg, #000 62%, transparent 100%);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
/* On a tablet the card is tall and its middle is empty, so the group stands
   in that room instead — on the felt above the PLAY button, whole and
   unmasked, rather than squeezed into the corner beside two lines of type. */
@media (min-width: 720px) {
  .mode-detail .detail-face.group {
    top: auto; bottom: 96px; right: 0; left: 0; margin-inline: auto;
    width: 100%; height: min(300px, 34dvh); max-width: 100%;
    /* CONTAIN here, against the crop the phone's cards use: this one stands
       in open room, so there is nothing to gain by cutting it — and a `cover`
       box this much wider than it is tall crops from the top, which takes the
       three faces and leaves three pairs of shoes. */
    object-fit: contain; object-position: bottom center;
    -webkit-mask-image: none; mask-image: none;
    filter: drop-shadow(0 16px 26px rgba(0, 0, 0, .45));
  }
}
/* THE TYPE STOPS WHERE THE PICTURE BEGINS. Both are the picture's own width
   plus a little air; a smaller number here is words running under a face. */
.mode-detail .detail-head { display: grid; gap: 4px; padding-right: 50%; }
.mode-detail .detail-head .eyebrow { margin: 0; }
.mode-detail .detail-name {
  font-family: "Georgia", "Iowan Old Style", serif; font-weight: 700;
  font-size: 32px; letter-spacing: -0.01em; line-height: 1.05; color: var(--cream-100, var(--ink));
}
.mode-detail .detail-blurb { color: var(--muted); font-size: 14px; line-height: 1.5; margin: 0; padding-right: 50%; }
/* On a tablet the picture stands BELOW the type (see the block above), so the
   type may have its width back. Stated here rather than up there because both
   rules carry the same weight and the later one wins. */
@media (min-width: 720px) {
  .mode-detail .detail-head, .mode-detail .detail-blurb { padding-right: 0; }
}
.mode-detail .stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.mode-detail .stat { display: grid; gap: 2px; padding: 12px 12px 11px; border-radius: 16px; background: var(--fill); border: 1px solid var(--hair); }
.mode-detail .stat .eyebrow { margin: 0; }
.mode-detail .stat .n { font-size: 24px; font-weight: 800; letter-spacing: -0.02em; line-height: 1; font-variant-numeric: tabular-nums; }
.mode-detail .stat .n em { font-style: normal; font-size: .5em; color: var(--muted); font-weight: 700; margin-left: 2px; }
.mode-detail .leader { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 13px; }
.mode-detail .leader b { color: var(--ink); }
.mode-detail .leader .crown { color: var(--brass-300); }
.mode-detail .note { margin: 0; }

/* ---------------------------------------------------------------- the auth */

.auth-brand { text-align: center; }
.auth-brand .wordmark { display: none; }
/* THE TABLE'S OWN VOICE, the one the board already speaks in: the gold leaf
   of YOUR TURN (styles.css, .turn-label) — Georgia, uppercase, letterspaced,
   lit at the top and bronze at the foot, with a shadow under it so it sits on
   the felt rather than floating over it. Said here in the same numbers rather
   than by borrowing the class, because a match label and a page's headline
   want different sizes and one of them must not drag the other about. */
.tagline {
  font-family: Georgia, "Iowan Old Style", serif;
  font-size: clamp(26px, 7.6vw, 34px); font-weight: 700;
  letter-spacing: 0.06em; line-height: 1.18; text-transform: uppercase;
  background: linear-gradient(180deg, #f9e2a4 8%, #e2b563 55%, #b98033 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 2px 3px #00000088);
  /* PULLED UP INTO THE PICTURE'S DISSOLVE. The headline reads over the felt
     where the image has already given out, which is why the mask above ends
     transparent well before the box does — the overlap is the point, and the
     type never crosses a face. `relative` so it stands over the image rather
     than under it, whatever order the two are painted in. */
  position: relative; z-index: 1;
  margin: -52px 0 16px;
}
/* On a tablet the lead column is narrow, and 40px put the headline on three
   lines that then reached a third of the way up the picture. Smaller, and
   pulled up by a fixed amount rather than a share of a bigger image. */
@media (min-width: 720px) { .tagline { font-size: 32px; margin-top: -54px; } }
.auth-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; text-align: left; max-width: none; }
.auth-points li { position: relative; padding: 0 0 0 22px; color: var(--muted); font-size: 14px; line-height: 1.5; }
.auth-points li::before { content: ""; position: absolute; left: 0; top: 9px; width: 8px; height: 8px;
  border-radius: 999px; background: var(--brass); box-shadow: 0 0 10px var(--brass-glow); }
.auth-card {
  width: 100%; max-width: none; background: var(--fill); border: 1px solid var(--hair);
  border-radius: var(--r-hero); padding: 22px 20px; box-shadow: none;
}
.auth-title { margin: 0; font-size: 20px; font-weight: 800; letter-spacing: -0.01em; }
.auth-sub { color: var(--muted); font-size: 13.5px; line-height: 1.5; margin: 6px 0 16px; }
.auth-actions { display: grid; gap: 10px; }
.auth-note { color: var(--dim); font-size: 12.5px; line-height: 1.5; margin: 14px 0 0; text-align: center; }
.error { color: #e8b2a4; font-size: 13px; min-height: 1.2em; margin-top: 10px; text-align: center; }

/* ---------------------------------------------------------------- the home */

/* Two lines: the greeting, then the name — and a breath of space between the
   corners on the logo line and the first words on the page. */
.identity { padding: 0; background: none; border: 0; display: block; margin-top: 26px; }
.identity-label { display: block; font-size: var(--fs-display); font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; color: var(--muted); }
.identity-name { font-size: var(--fs-display); font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); }
.identity-meta { color: var(--muted); font-size: 14px; margin-top: 10px; line-height: 1.5; }

/* --------------------------------------------------------------- the lobby */

.code-panel { text-align: center; }
.code {
  font-family: var(--font-sans); font-size: var(--fs-num); font-weight: 800; letter-spacing: .18em;
  color: var(--brass-300); text-indent: .18em; line-height: 1; margin: 6px 0 10px;
}
.code-share { color: var(--muted); font-size: 13px; }
.url { color: var(--ink); font-family: var(--font-mono, ui-monospace, monospace); }
#lobbyShare { margin-top: 14px; }

/* align-content: start because a seat list that is given more height than it
   has seats must keep its rows the size of a seat. Stretched rows put the
   name and the character on opposite ends of a tall empty box. */
/* It may shrink and scroll, but it never grows: a seat list stretched to a
   column's height is a bordered box with an empty row painted at the bottom. */
.seat-list.flexy { flex: 0 1 auto; }
.seat-list {
  display: grid; gap: 0; align-content: start;
  border-radius: 18px; overflow: hidden; border: 1px solid var(--hair);
}
/* A seat is a Sapien set-row: who is in it over what they are, the actions on
   the right. Two columns, so a character's name never wraps three deep because
   the chips wanted the width. */
.seat-row {
  display: grid; grid-template-columns: auto 1fr auto; grid-template-rows: auto auto;
  column-gap: 10px; row-gap: 2px; align-items: center;
  background: var(--fill-soft); border: 0; border-bottom: 1px solid var(--hair);
  border-radius: 0; padding: 12px 14px; font-size: 14px;
}
.seat-row:last-child { border-bottom: 0; }
.seat-row.you { background: var(--brass-soft); }
.seat-row .seat-glyph { grid-row: 1 / 3; font-size: 11px; width: 1em; align-self: center; }
.seat-row .seat-name { grid-column: 2; grid-row: 1; text-transform: capitalize; min-width: 0; font-weight: 700; }
.seat-row .seat-who { grid-column: 2; grid-row: 2; color: var(--muted); font-size: 12.5px; line-height: 1.35; min-width: 0; }
.seat-row .seat-actions { grid-column: 3; grid-row: 1 / 3; display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; align-self: center; }
.seat-row .seat-actions .chip { padding: 7px 12px; font-size: 11.5px; }
.mini-select {
  background: var(--fill); border: 1px solid var(--hair); color: var(--ink);
  border-radius: 999px; padding: 7px 10px; font: inherit; font-family: var(--font-sans); font-size: 11.5px;
}

/* ------------------------------------------------------------- the profile */

.profile-card { text-align: center; }
.profile-name { font-size: 22px; font-weight: 800; letter-spacing: -0.01em; }
.profile-kind { color: var(--muted); font-size: 13px; margin-top: 4px; }
.btn-stack { display: grid; gap: 10px; }

/* ----------------------------------------------------------- the community */

#communityTabs { margin-bottom: 4px; }
.community-pane { display: grid; gap: 12px; }
.community-pane[hidden] { display: none; }
.mode-tabs { display: block; }
.board-table { border-radius: var(--r-card); background: var(--fill); border: 1px solid var(--hair); overflow: hidden; }
.board-table:empty { display: none; }
.board-empty { border-radius: var(--r-card); }
.board-row {
  display: grid; grid-template-columns: 1.8rem 1fr auto auto; gap: 10px; align-items: center;
  padding: 14px 16px; border-bottom: 1px solid var(--hair); font-size: 14px;
}
.board-row:last-child { border-bottom: 0; }
.board-rank { color: var(--dim); font-size: 12px; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.board-name .who { font-weight: 650; }
.board-kind { font-size: 9.5px; letter-spacing: .1em; color: var(--dim); border-color: var(--hair); }
.board-played { color: var(--dim); font-size: 12px; }
.board-won { font-weight: 800; font-size: 16px; font-variant-numeric: tabular-nums; }
.board-row.leader { background: var(--brass-soft); }
.board-note { color: var(--dim); font-size: 12.5px; padding: 14px 16px; }

/* ---------------------------------------------------------- bottom sheet */

/* A card that rises from the bottom and floats clear of the edge. Any part of
   it drags down to dismiss; the handle stays as the sign that it can.
   NAMED .sheet, NOT .sheet: the match already owns a .sheet — the chat and
   rules panels — which styles.css parks off-screen with translateY(100%) until
   it is opened. Sharing the name put this one 633px below the fold on arrival,
   which read as the sheet never opening. */
.sheet-veil {
  position: fixed; inset: 0; z-index: 19; background: rgba(4, 3, 1, .55);
  animation: veil-in .22s ease-out;
}
.sheet-veil[data-out="1"] { animation: veil-out .22s ease-in forwards; }
@keyframes veil-in { from { opacity: 0; } }
@keyframes veil-out { to { opacity: 0; } }
.sheet {
  position: fixed; left: 14px; right: 14px; z-index: 20; margin: 0 auto; max-width: 560px;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  max-height: min(86dvh, 720px); display: flex; flex-direction: column;
  border-radius: 28px; background: var(--glass-strong);
  backdrop-filter: blur(22px) saturate(170%); -webkit-backdrop-filter: blur(22px) saturate(170%);
  border: 1px solid var(--hair-bright); box-shadow: var(--shadow-pop);
  touch-action: none; animation: sheet-rise .36s var(--ease);
  transition: transform .26s var(--ease);
  font-family: var(--font-sans); color: var(--ink);
}
.sheet[data-out="1"] { animation: sheet-fall .22s cubic-bezier(.32, .72, 0, 1) forwards; }
@keyframes sheet-rise { from { transform: translateY(calc(100% + 60px)); } }
@keyframes sheet-fall { to { transform: translateY(calc(100% + 60px)); } }
.sheet-handle { display: flex; justify-content: center; padding: 10px 0 2px; flex: none; }
.sheet-handle span { width: 38px; height: 5px; border-radius: 999px; background: var(--hair-bright); }
.sheet-body { overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; padding: 8px 18px 22px; scrollbar-width: none; }
.sheet-body::-webkit-scrollbar { display: none; }
.rail-head { display: flex; align-items: center; justify-content: space-between; margin: 0 0 8px; }
.rail-head .grouplab { margin: 0; }
@media (prefers-reduced-motion: reduce) { .sheet, .sheet-veil { animation: none; } }


/* ===================================================== THE MATCH'S FURNITURE
   The owner's second ruling: the match's SUPPLEMENTARY chrome — the drawer,
   its tabs, table talk, the leave question, the winner's card — may borrow
   the desk's language. The board, the die and the turn panel do not; they
   keep the dress styles.css tuned for them. Everything below lives outside
   .match in the DOM (drawer and dialogs are body-level), so the promise at
   the top of this file — nothing selects into .match — still holds. */

.drawer, .ask, .win { font-family: var(--font-sans); color: var(--ink); }

/* The drawer as the desk's sheet: floating clear of the edge, glass, one
   hairline, a small handle. From the top it is the same card upside down. */
.drawer-scrim { background: rgba(4, 3, 1, .55); }
@media (max-width: 999px) {
  .drawer {
    left: 10px; right: 10px; margin: 0 auto; max-width: 560px;
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    border-radius: var(--r-hero); border: 1px solid var(--hair-bright);
    background: var(--glass-strong);
    backdrop-filter: blur(22px) saturate(170%); -webkit-backdrop-filter: blur(22px) saturate(170%);
    box-shadow: var(--shadow-pop);
    padding-bottom: 0;
    transform: translateY(calc(100% + 60px));
  }
  .drawer.open { transform: translateY(0); }
}
@media (min-width: 1000px) {
  .drawer { background: var(--glass); border: 1px solid var(--hair); border-radius: var(--r-card); }
}
.drawer-handle { width: 38px; height: 5px; background: var(--hair-bright); margin: 10px auto 0; }
.drawer-head { padding: 8px 18px 6px; }
.drawer-head h2 {
  font-size: 17px; font-weight: 700; letter-spacing: -0.01em; text-transform: none;
  color: var(--ink);
}
.drawer-pane { padding: 0 18px 18px; }

/* The tab strip is the desk's segmented control, thumb-less: the on tab is
   raised on the track and takes brass, the others only change colour. */
.panel-tabs { background: var(--track); border: 0; border-radius: 999px; padding: 3px; }
.tab {
  font-size: 13px; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--muted); min-height: 34px; padding: 6px 8px;
}
.tab.on { color: var(--brass-300); background: var(--seg-fill); box-shadow: 0 1px 2px rgba(0, 0, 0, .35); }
.tab-body { background: var(--fill); border: 1px solid var(--hair); border-radius: var(--r-card); margin-top: 10px; }

/* Table talk: the messenger shape stays; the bubbles take the desk's fills
   and radii, your own keeps the felt's green because "mine" means something. */
.chat { padding: 12px 12px 8px; gap: 8px; }
.chat-empty { font-size: 13px; color: var(--dim); line-height: 1.5; }
.msg-body {
  background: var(--fill-hover); border-color: var(--hair);
  border-radius: 18px 18px 18px 6px; padding: 8px 12px 9px;
  font-size: 13.5px; line-height: 1.4; box-shadow: none;
}
.msg.mine .msg-body { border-radius: 18px 18px 6px 18px; }
.msg-quote { border-radius: 10px; background: rgba(0, 0, 0, .25); }
.reaction { background: var(--fill); border-color: var(--hair); }
.chat-compose { background: transparent; border-top: 1px solid var(--hair); padding: 10px 10px 8px; }
.chat-input { background: var(--fill); border-color: var(--hair); font-size: 15px; padding: 10px 14px; }
.chat-input:focus { border-color: var(--brass-line); }
.chat-send { background: var(--brass); color: var(--accent-ink); }
.chat-send:disabled { opacity: .32; }
.log { font-size: 13px; }
.log li { border-color: var(--hair); padding: 5px 0; }
.meta { font-size: 12px; color: var(--dim); }

/* The question and the winner's card: the desk's card on the desk's veil,
   pill buttons, cream for the thing to press. The winner's name takes the
   display face the desk greets you with. */
.ask-scrim, .win-scrim {
  background: rgba(4, 3, 1, .6);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.ask {
  border-radius: var(--r-card); background: var(--glass-strong);
  border-color: var(--hair-bright); box-shadow: var(--shadow-pop);
  padding: 22px 20px 18px;
}
.ask p { font-size: 15px; line-height: 1.5; margin: 0 0 18px; }
.ask-row .btn, .win-row .btn {
  border-radius: 999px; min-height: 44px; padding: 0 18px;
  font-weight: 650; font-size: 14px; box-shadow: none;
}
.ask-row .btn.ghost, .ask-row .btn.quiet, .win-row .btn.ghost, .win-row .btn.quiet {
  background: var(--fill); border: 1px solid var(--hair-bright); color: var(--ink);
}
.ask-row .btn.primary, .win-row .btn.primary {
  background: var(--accent); color: var(--accent-ink); border-color: transparent;
}
.ask-row .btn.primary:hover:not(:disabled), .win-row .btn.primary:hover:not(:disabled) { box-shadow: 0 0 22px var(--accent-glow); }
.win {
  border-radius: var(--r-hero); border-color: var(--hair-bright);
  box-shadow: var(--shadow-pop); padding: 26px 20px 18px;
}
.win-rank { font-size: 11px; letter-spacing: .14em; }
.win-who {
  font-family: var(--font-sans); font-size: var(--fs-display); font-weight: 800;
  letter-spacing: -0.02em; line-height: 1.05;
}
.win-order li { border-color: var(--hair); background: var(--fill); border-radius: 14px; font-size: 14px; padding: 8px 12px; }
.win-note { font-size: 13px; color: var(--dim); }


/* ------------------------------------------- the tablet's inner furniture */

@media (min-width: 720px) {
  /* Standings: the mode rail stands beside its table rather than above it. */
  #communityStandings {
    grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
    align-items: start; gap: 10px 26px;
  }
  #communityStandings > .lede { grid-column: 1; margin: 0; }
  #communityStandings > .mode-tabs { grid-column: 1; grid-row: 2; }
  #communityStandings > .board-table { grid-column: 2; grid-row: 1 / span 2; }
  /* The mode rail reads as a list of rooms, one per line. */
  #boardModeTabs .seg { display: grid; grid-auto-flow: row; border-radius: 18px; }
  #boardModeTabs .seg-thumb { display: none; }
  #boardModeTabs .seg-tab { justify-content: flex-start; text-align: left; padding: 11px 14px; }
  #boardModeTabs .seg-tab[aria-selected="true"] { background: var(--seg-fill); border-radius: 14px; }

  /* The greeting can afford its full size, and the hero its full padding. */
  .card.hero { padding: 26px 24px; }
  .mode-detail .detail-name { font-size: 30px; }
  .seat-row { padding: 15px 16px; }
}


/* The profile's own head, sized for a phone: the face is recognisable at 72px
   and the page is a page rather than a portrait. It grows again where there
   is room to grow into. */
.profile-card { padding: 16px 18px 15px; }
.profile-card .avatar.big { width: 72px; height: 72px; font-size: 26px; }
@media (min-height: 760px) and (max-width: 719px) {
  .profile-card .avatar.big { width: 84px; height: 84px; }
}
@media (min-width: 720px) {
  .profile-card { padding: 24px 22px 20px; }
  .profile-card .avatar.big { width: 96px; height: 96px; font-size: 34px; }
}

.fineprint { font-size: 11.5px; color: var(--dim); line-height: 1.45; }


/* --------------------------------------------------- the short phone
   A 667px phone has about a hundred fewer pixels than the pages were drawn
   for, and scale alone would take the type below reading size. So the page
   gives some furniture back instead: the logo is smaller chrome, the toggles
   lose their explanatory second line, and the mode card loses the note that
   repeats what the Profile already says. What is left is the page. */
@media (max-height: 700px) {
  :root {
    --head-room: 62px; --foot-room: 12px; --deck-gap: 8px;
    --fs-display: clamp(26px, 6.4vw, 32px);
  }
  #brandHeader { width: 88px; top: calc(8px + env(safe-area-inset-top)); }
  .screen:not(.match) > .corners { top: calc(env(safe-area-inset-top, 0px) + 18px); }
  .row-sub, .set-row small { display: none; }
  .set-row, .row-toggle { min-height: 44px; padding: 10px 14px; }
  .mode-detail { gap: 10px; }
  .mode-detail .note { display: none; }
  .card.hero { padding: 16px 16px; }
  .profile-card .avatar.big { width: 58px; height: 58px; font-size: 21px; }
  .identity { margin-top: 10px; }
  .identity-meta { margin-top: 6px; }
  .carousel-card.peek { padding-bottom: 20px; }
  .grouplab { margin: 0; }
  .next-line { margin-top: 8px; }
}




/* ------------------------------------------------------- pills and circles
   EVERY BUTTON IS A PILL OR A CIRCLE. The house has one shape for a thing you
   press: fully rounded. Round icons stay round; everything with a word in it
   is a pill. (Not the dice or the board — those are not buttons.) */
.btn, .cta, .mini, .chip, .head-btn, .msg-act, .seat-actions > *,
.avatar-actions .btn, .dd, button.set-row .value {
  border-radius: 999px;
}
.btn.play, .btn.block, .cta { border-radius: 999px; }

/* The way back is a chevron, everywhere: the desk's pages and the match's
   corner use the same glyph at the same weight, so "back" is one thing the
   whole app says the same way. */
.back-btn svg { display: block; }
.back-btn { color: var(--ink); }

/* One rule set, stated rather than offered. */
.field.static {
  display: flex; align-items: center; color: var(--ink);
  background: var(--fill-soft); border-style: dashed; cursor: default;
}
.field.static[hidden] { display: none; }

/* The columns fill the row they are given. Without this the groups sit at the
   top of a full-height page and every "push it to the foot" rule below has
   nothing to push against. */
@media (min-width: 720px) {
  .deck > .col { align-self: stretch; }
}

/* The band's own rhythm: it is a line of the page, not a card in it. */
.band { margin: 0; }
@media (min-width: 720px) { .deck > .band { margin-bottom: 4px; } }

/* ===================================================== THE SHARED SCREEN
   A television across a room, not a phone in a hand. Everything here is
   sized for the far end of a sofa: the code is the biggest thing on the
   glass, the QR is next, and the seats are a list you can read standing up.

   The Table holds no seat and takes no turn, so every personal control the
   client has is hidden rather than deleted — it is the same client, and the
   board it draws is the board the phones are drawing. */

body.as-table #brandHeader { width: 96px; }

.table-surface .table-band { text-align: center; }
.table-title {
  font-size: clamp(24px, 3.4vw, 40px); font-weight: 800; letter-spacing: -0.02em;
  line-height: 1.1; margin: 6px 0 8px; color: var(--ink);
}
.table-lede { color: var(--muted); font-size: clamp(14px, 1.4vw, 18px); margin: 0; }

/* The QR is a physical object on the glass: a light card, because a camera
   reads dark-on-light far more reliably than the other way round, and this
   one is being photographed across a room in a lit lounge. */
.table-qr {
  display: grid; place-items: center; gap: 14px;
  background: var(--fill); border-color: var(--hair-bright);
}
.table-qr canvas {
  width: min(100%, 320px); height: auto; aspect-ratio: 1;
  padding: 12px; border-radius: 18px; background: #f6efe0;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}
.table-qr-note { margin: 0; color: var(--muted); font-size: 13px; text-align: center; }

/* The code is the fallback that always works: somebody reads it out, somebody
   else types it. It is set as large as the column allows for exactly that. */
.table-code-panel { text-align: center; }
.table-code-panel .code {
  font-size: clamp(38px, 6vw, 76px); letter-spacing: .14em; font-weight: 800;
  color: var(--brass-300); line-height: 1.05;
}

/* Where a player is, beside who they are. */
.seat-where { font-style: normal; color: var(--dim); }
.table-surface .seat-row { padding: 14px 16px; font-size: 15px; }
.table-surface .seat-name { font-size: 15px; }

/* Gameplay chrome the shared screen has no business showing. Talk belongs on
   the phone that is doing the talking; the board just plays it. */
body.as-table .chat-bar,
body.as-table #chatFab { display: none !important; }

/* On a big screen the Table's two columns are the pairing that matters: how to
   get in on the left, who is in on the right. */
@media (min-width: 720px) {
  .table-body > .band { grid-column: 1 / -1; }
  .table-body { grid-template-rows: auto 1fr; }
  .table-body > .col-lead, .table-body > .col-main { grid-row: 2; }
}


/* ------------------------------------------------- parts that hold their size
   The mode rail is sized for a thumb and a glance. It once counter-scaled an
   elastic page; the page no longer scales, so all that is left is its width. */
.holds-size { width: 100%; align-self: start; }

/* ======================================================= THE GAME LOBBY
   Three moves: seats, characters, difficulty. The seats are tiles with faces
   in them; the characters are a grid you pick from; the card is what a tile
   opens into. Every face is the character's own art, framed on the head. */

.lobby-band .code-panel {
  padding: 12px 16px; text-align: left;
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
}
.lobby-band .code-panel .eyebrow { margin: 0 0 2px; }
.lobby-band .code { font-size: clamp(24px, 6vw, 34px); line-height: 1; }
.lobby-band .code-share { font-size: 12px; text-align: right; }
.lobby-band .code-share .url { display: block; }
#codePanel[hidden] { display: none; }

/* --- the seats: four tiles, one per edge of the board ------------------- */
.seat-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
/* A ROW IS A SIDE. Paired play puts the two seats that share a fate beside each
   other with the gap between rows opened up, so the pairing is legible before a
   die is thrown rather than being something to work out from the board. */
.seat-tiles.paired { row-gap: 22px; column-gap: 6px; }
.seat-tiles.paired .seat-tile:nth-child(odd) { border-top-right-radius: 6px; border-bottom-right-radius: 6px; }
.seat-tiles.paired .seat-tile:nth-child(even) { border-top-left-radius: 6px; border-bottom-left-radius: 6px; }
/* A SEAT IS ITS COLOUR. The board's four are the strongest naming the game has —
   south is clay, west is forest, north is indigo, east is gold — and a tile that
   only wore a coloured word for its seat was naming the seat twice and showing it
   once. Solid, with everything on it in white, so the four read as four at a
   glance and a player finds their own without reading anything. */
.seat-tile {
  position: relative; display: block;
  padding: 10px 12px; border-radius: 20px; min-width: 0;
  background: var(--seat, var(--fill));
  border: 1px solid rgba(255, 255, 255, .14);
  color: #fff;
  transition: border-color .3s var(--ease), background .3s var(--ease), transform .3s var(--ease);
}
/* An empty seat is not a colour yet — it is an invitation, and painting it the
   full seat colour would say somebody is sitting there. */
.seat-tile.open { background: var(--fill); border-color: var(--hair); color: var(--ink); }
/* Face on the left, the words on the right: who, in which seat, how hard. */
.seat-tile .seat-main {
  all: unset; display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: 10px; row-gap: 2px; align-items: center; width: 100%;
  cursor: pointer; min-width: 0; text-align: left;
}
.seat-tile .seat-face { grid-row: 1 / 3; }
.seat-tile .seat-label { grid-column: 2; grid-row: 1; align-self: end; }
.seat-tile .seat-who { grid-column: 2; grid-row: 2; align-self: start; text-align: left; }
.seat-tile.picked { box-shadow: 0 0 0 2px var(--brass); transform: translateY(-1px); }
.seat-tile.you { border-color: rgba(255, 255, 255, .5); }
.seat-face {
  width: 52px; height: 52px; border-radius: 50%; overflow: hidden; position: relative;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, .28); border: 2px solid rgba(255, 255, 255, .82);
  font-weight: 800; font-size: 20px; color: #fff;
}
.seat-tile.open .seat-face {
  background: var(--fill-hover); border-color: var(--hair-bright); color: var(--ink);
}
.seat-face img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%;
  transform: scale(2.1); transform-origin: 50% 14%;
}
/* Your own picture fills the circle, drawn the way the corner avatar is drawn:
   a covering background rather than an img, which left a hair of the circle
   showing at its edges. The cast's crop above is for full-length portraits and
   would show a photograph an eyebrow. */
.seat-face.has-photo {
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.seat-face .seat-plus { color: var(--dim); font-size: 26px; font-weight: 400; line-height: 1; }
.seat-label { font-size: 10px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; color: #fff; }
.seat-tile.open .seat-label { color: var(--seat-ink, var(--muted)); }
.seat-tile .seat-who {
  font-size: 12px; line-height: 1.25; color: rgba(255, 255, 255, .8);
  min-width: 0; max-width: 100%; overflow: hidden;
}
.seat-tile .seat-who b { color: #fff; }
.seat-tile.open .seat-who { color: var(--muted); }
.seat-tile .seat-who b, .seat-tile .seat-who em { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat-tile.south { --seat: var(--south); --seat-ink: var(--south-ink); }
.seat-tile.west  { --seat: var(--west);  --seat-ink: var(--west-ink); }
.seat-tile.north { --seat: var(--north); --seat-ink: var(--north-ink); }
.seat-tile.east  { --seat: var(--east);  --seat-ink: var(--east-ink); }
/* East is gold and light: its white would sit on top of a pale ground, so that
   one seat keeps the game's ink instead. */
.seat-tile.east:not(.open) {
  color: #1b1108;
  border-color: rgba(0, 0, 0, .18);
}
.seat-tile.east:not(.open) .seat-label,
.seat-tile.east:not(.open) .seat-who b { color: #1b1108; }
.seat-tile.east:not(.open) .seat-who { color: rgba(27, 17, 8, .78); }
.seat-tile.east:not(.open) .seat-face { border-color: rgba(27, 17, 8, .7); color: #1b1108; }
.seat-tile .seat-x {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--hair-bright); background: var(--glass-strong); color: var(--muted);
  font: inherit; font-size: 13px; line-height: 1; cursor: pointer; display: grid; place-items: center;
}
.seat-tile .seat-x:hover { color: var(--ink); }
.seat-actions-row { display: flex; gap: 8px; flex-wrap: wrap; }
.seat-actions-row[hidden] { display: none; }

/* --- the cast: a grid of faces ------------------------------------------ */
.cast-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.cast-tile { position: relative; min-width: 0; }
.cast-tile .cast-pick {
  all: unset; display: block; width: 100%; cursor: pointer; position: relative;
  padding: 0; border-radius: 18px; box-sizing: border-box; overflow: hidden;
  background: var(--fill); border: 1px solid var(--hair);
  transition: border-color .3s var(--ease), background .3s var(--ease), transform .3s var(--ease), opacity .3s var(--ease);
}
.cast-tile .cast-pick:hover { border-color: var(--hair-bright); transform: translateY(-1px); }
.cast-tile.seated .cast-pick { border-color: var(--brass-line); background: var(--brass-soft); }
.cast-tile.busy .cast-pick { opacity: .5; }
.cast-art {
  display: block; width: 100%; aspect-ratio: 6 / 5; border-radius: 18px; overflow: hidden;
  background: radial-gradient(80% 70% at 50% 30%, rgba(255, 236, 200, .1), transparent 70%), #1b1208;
}
.cast-art img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 8%;
  transform: scale(1.55); transform-origin: 50% 12%; display: block;
}
.cast-name {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 18px 8px 7px;
  font-size: 12px; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink);
  background: linear-gradient(180deg, transparent, rgba(12, 8, 3, .92));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cast-seat {
  position: absolute; left: 6px; top: 6px; padding: 3px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 800; letter-spacing: .06em;
  background: var(--glass-strong); color: var(--seat-ink, var(--brass-300)); border: 1px solid var(--hair-bright);
  pointer-events: none;
}
.cast-tile.south .cast-seat { --seat-ink: var(--south-ink); }
.cast-tile.west  .cast-seat { --seat-ink: var(--west-ink); }
.cast-tile.north .cast-seat { --seat-ink: var(--north-ink); }
.cast-tile.east  .cast-seat { --seat-ink: var(--east-ink); }
.cast-info {
  position: absolute; right: 5px; top: 5px; width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid var(--hair-bright); background: var(--glass-strong); color: var(--brass-300);
  font: inherit; font-size: 12px; font-weight: 800; font-style: italic; cursor: pointer;
  display: grid; place-items: center; line-height: 1;
}
.cast-info:hover { background: var(--brass-soft); }

@media (min-width: 720px) {
  .lobby-body > .band { grid-column: 1 / -1; grid-row: 1; }
  /* A page that scrolls is read top to bottom, so its rows follow its content
     rather than stretching to the foot — the difficulty belongs under the
     faces, not a hand's width below them. */
  .lobby-body { grid-template-rows: auto auto auto; align-content: start; }
  .lobby-body > .col-lead { grid-row: 2 / span 2 !important; }
  .lobby-body > .col-main { grid-row: 2 !important; }
  .lobby-body > .col-act  { grid-row: 3 !important; }
  .seat-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .seat-face { width: 70px; height: 70px; }
  .cast-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
  .cast-name { font-size: 13px; }
}
@media (min-width: 900px) and (orientation: landscape) {
  .lobby-body { grid-template-rows: auto auto; }
  .lobby-body > .col-lead, .lobby-body > .col-main, .lobby-body > .col-act { grid-row: 2 !important; }
  .seat-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ======================================================= THE CHARACTER CARD
   A physical object: it leans under the pointer, catches the light where the
   finger is, and turns over. CSS 3D and three custom properties — --rx, --ry
   for the lean, --flip for the turn — set from desk.js and nothing else. */

.pcard-veil {
  position: fixed; inset: 0; z-index: 70;
  display: grid; grid-template-rows: 1fr auto; place-items: center; gap: 14px;
  padding: max(18px, env(safe-area-inset-top)) 18px max(18px, env(safe-area-inset-bottom));
  background: rgba(4, 3, 1, .72);
  backdrop-filter: blur(10px) saturate(140%); -webkit-backdrop-filter: blur(10px) saturate(140%);
  animation: veil-in .22s ease-out;
  font-family: var(--font-sans); color: var(--ink);
}
.pcard-veil[data-out="1"] { animation: veil-out .22s ease-in forwards; }
.pcard-stage { perspective: 1100px; perspective-origin: 50% 40%; touch-action: none; }
.pcard {
  position: relative; width: min(84vw, 330px); aspect-ratio: 5 / 7;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(calc(var(--ry, 0deg) + var(--flip, 0deg)));
  transition: transform .18s ease-out;
  will-change: transform; outline: none; cursor: pointer;
  animation: pcard-in .5s var(--ease);
  --seat: var(--brass);
}
.pcard.flipped { transition: transform .6s var(--ease); }
.pcard.seat-south { --seat: var(--south-ink); }
.pcard.seat-west  { --seat: var(--west-ink); }
.pcard.seat-north { --seat: var(--north-ink); }
.pcard.seat-east  { --seat: var(--east-ink); }
@keyframes pcard-in { from { opacity: 0; transform: translateY(24px) rotateX(12deg); } }

.pcard-face {
  position: absolute; inset: 0; border-radius: 22px; overflow: hidden;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  background:
    linear-gradient(160deg, #2e1d0b 0%, #1b1208 55%, #120b04 100%);
  border: 2px solid var(--brass);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .65), inset 0 0 0 1px rgba(228, 194, 118, .25);
  display: grid; grid-template-rows: 1fr auto auto;
}
.pcard-back { transform: rotateY(180deg); grid-template-rows: 1fr; }

/* The frame's inner line, the way a printed card has one. */
.pcard-edge {
  position: absolute; inset: 7px; border-radius: 16px; pointer-events: none;
  border: 1px solid rgba(228, 194, 118, .35);
}

/* The portrait: the character's own art, framed on the head and shoulders,
   on a glow the colour of the seat they hold (brass when they hold none). */
.pcard-art {
  position: relative; overflow: hidden; margin: 12px 12px 0; border-radius: 14px;
  background:
    radial-gradient(70% 60% at 50% 35%, color-mix(in srgb, var(--seat) 32%, transparent), transparent 72%),
    linear-gradient(180deg, #24170a, #140d05);
}
.pcard-art img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0%;
  /* A full-length action shot, so the head and the hands are the picture. */
  transform: scale(1.18); transform-origin: 50% 6%;
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, .5));
}
.pcard-band { padding: 10px 16px 4px; }
.pcard-name { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; color: var(--ink); }
.pcard-sub { font-size: 11.5px; color: var(--seat); font-weight: 700; letter-spacing: .04em; margin-top: 2px; }

/* Six bars. The number is on the right because a bar is a feeling and a
   number is a fact, and a card should give both. */
.pcard-stats { list-style: none; margin: 0; padding: 6px 16px 14px; display: grid; gap: 5px; }
.pcard-stats li {
  display: grid; grid-template-columns: 74px 1fr 30px; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}
.pcard-stats i {
  display: block; height: 7px; border-radius: 999px; background: var(--track); position: relative; overflow: hidden;
}
.pcard-stats i::after {
  content: ""; position: absolute; inset: 0; width: calc(var(--v, 0) * 1%);
  border-radius: 999px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--seat) 70%, #fff 0%), var(--brass-300));
  animation: pcard-fill .8s var(--ease) backwards;
}
@keyframes pcard-fill { from { width: 0; } }
.pcard-stats b { text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }

/* The foil: a highlight that lives where the pointer is. */
.pcard-sheen {
  position: absolute; inset: 0; pointer-events: none; border-radius: 22px;
  background:
    radial-gradient(60% 45% at var(--mx, 50%) var(--my, 30%), rgba(255, 244, 214, .45), transparent 70%),
    linear-gradient(115deg, transparent 30%, rgba(228, 194, 118, .12) 45%, rgba(255, 255, 255, .18) 50%, rgba(228, 194, 118, .12) 55%, transparent 70%);
  background-position: 0 0, calc(var(--mx, 50%) * 1.4 - 70%) 0;
  mix-blend-mode: screen; opacity: .55;
}

/* The back: how they play, in words. */
.pcard-back-inner { padding: 26px 20px 20px; display: grid; gap: 12px; align-content: start; }
.pcard-eyebrow { margin: 0; font-size: 10px; letter-spacing: .24em; text-transform: uppercase; color: var(--seat); font-weight: 700; }
.pcard-temper { margin: 0; font-size: 14.5px; line-height: 1.5; color: var(--ink); }
.pcard-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.pcard-tags span {
  font-size: 11px; font-weight: 700; padding: 5px 10px; border-radius: 999px;
  background: var(--brass-soft); border: 1px solid var(--brass-line); color: var(--brass-300);
}
.pcard-luck { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.pcard-quote {
  margin: 4px 0 0; padding: 12px 14px; border-left: 3px solid var(--seat); border-radius: 0 12px 12px 0;
  background: var(--fill); color: var(--ink); font-size: 15px; font-style: italic; line-height: 1.4;
}
.pcard-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.pcard-actions .btn { border-radius: 999px; min-height: 44px; padding: 0 18px; font-size: 14px; }
.pcard-actions .btn.ghost { background: var(--fill); border: 1px solid var(--hair-bright); color: var(--ink); }
.pcard-actions .btn.primary { background: var(--brass); color: var(--accent-ink); border-color: transparent; box-shadow: none; }
.pcard-actions .btn.quiet { background: transparent; border: 1px solid var(--hair); color: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  .pcard, .pcard-stats i::after { animation: none; }
  .pcard { transition: none; }
}

/* A face in a seat row on the shared screen: the same framing, smaller. */
.seat-row .seat-face.small { width: 34px; height: 34px; grid-row: 1 / 3; align-self: center; font-size: 14px; }
.seat-row .seat-face.small img { transform: scale(2.1); transform-origin: 50% 14%; }
/* On a painted seat both lines are white; the seat's own colour is the ground.
   Stated HERE rather than beside the tile's other colours because these two
   rules come later in the file and would otherwise win with the old palette. */
.seat-tile .seat-who b { display: block; font-weight: 700; color: #fff; }
.seat-tile .seat-who em { display: block; font-style: normal; color: rgba(255, 255, 255, .72); font-size: 10.5px; }
.seat-tile.open .seat-who b { color: var(--ink); }
.seat-tile.open .seat-who em { color: var(--dim); }
/* Gold is a light ground: east reads in ink. */
.seat-tile.east:not(.open) .seat-who b { color: #1b1108; }
.seat-tile.east:not(.open) .seat-who em { color: rgba(27, 17, 8, .72); }

/* The cast is not finished: the eighth tile says so, and does nothing else. */
.cast-tile.soon { position: relative; }
.cast-tile.soon .cast-art, .cast-art:has(> .cast-soon-mark) {
  border: 1.5px dashed var(--hair-bright); background: var(--fill-soft);
  display: grid; place-items: center;
}
.cast-soon-mark {
  font-size: 34px; font-weight: 800; color: var(--dim); line-height: 1;
  transform: translateY(-8px);
}
.cast-tile.soon .cast-name { color: var(--dim); background: none; padding-bottom: 8px; }

/* In the social modes the characters are the understudies: same grid, quieter
   frame, so the seats and the code read first. */
#castSection.quiet .cast-tile .cast-pick { background: var(--fill-soft); border-color: var(--hair); }
#castSection.quiet .cast-art { opacity: .92; }
#castSection[hidden] { display: none; }
#fillGroup[hidden], #chooseCast[hidden] { display: none; }
#chooseCast { justify-self: start; }

/* The first tile is the table dealing: a die, not a face. */
.cast-tile.random .cast-art {
  display: grid; place-items: center;
  /* The die is centred between the top of the tile and the TOP OF THE WORD, not
     the bottom of the tile — so the space above it and the space below it are
     the same. 22px is what the name occupies from its text down: its own 7px of
     padding plus a 15px line, both fixed, so this holds at every tile size. */
  padding-bottom: 22px;
  background: linear-gradient(160deg, rgba(199, 149, 55, .22), rgba(199, 149, 55, .06)), #1b1208;
  border: 1.5px dashed var(--brass-line);
}
/* The die from the felt, sitting on the tile at a thrown angle. Shadowed rather
   than outlined: it is an object resting there, not a symbol printed on it. */
/* The die from the felt, sitting on the tile at a thrown angle. Shadowed rather
   than outlined: it is an object resting there, not a symbol printed on it. */
.cast-dice {
  width: 46%; max-width: 52px; height: auto; display: block;
  /* No lift of its own: the art box's padding does the centring (above), which
     keeps it true when the tile changes size. */
  transform: rotate(-12deg);
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .5));
}
.cast-tile.random .cast-pick:hover .cast-dice { transform: rotate(12deg); transition: transform .4s var(--ease); }
.cast-tile.random .cast-name { color: var(--brass-300); }

/* ============================================================== THE FACE
   One circle, everywhere a seat is named: a chat bubble, a notification, the
   winner's card, the standings. The ring is the seat's colour; the art is
   framed on the head, the same framing the lobby uses. */
.face {
  display: inline-grid; place-items: center; flex: none; vertical-align: middle;
  width: 30px; height: 30px; border-radius: 50%; overflow: hidden;
  background: var(--fill-hover); border: 1.5px solid var(--seat-ink, var(--hair-bright));
  color: var(--ink); font-weight: 800; font-size: 12px; line-height: 1;
  background-size: cover; background-position: center;
}
.face img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%; transform: scale(2.1); transform-origin: 50% 14%; display: block; }
.face.sm { width: 22px; height: 22px; font-size: 10px; border-width: 1px; }
.face.lg { width: 72px; height: 72px; font-size: 26px; border-width: 2px; box-shadow: 0 10px 26px rgba(0,0,0,.45); }
.face.south { --seat-ink: var(--south-ink); }
.face.west  { --seat-ink: var(--west-ink); }
.face.north { --seat-ink: var(--north-ink); }
.face.east  { --seat-ink: var(--east-ink); }

.notif > .face { margin-top: 2px; }
.msg-head { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }
.board-name .face { margin-right: 6px; }
#winTitle { display: grid; justify-items: center; gap: 10px; }

/* The standings row on a phone: the face says who is a character now, so the
   AI chip is redundant there and the empty crown slot reserved space for a
   crown that only one row has. The name gets the width back. */
.board-name .crown-slot { display: none; }
.board-name .crown { flex: none; }
.board-played { white-space: nowrap; font-size: 11.5px; }
@media (max-width: 430px) {
  .board-name .board-kind { display: none; }
  /* "1 played · unranked" nowrap took the row and left the name two letters.
     It wraps to two short lines; the name keeps its width. */
  .board-played { white-space: normal; text-align: right; max-width: 78px; line-height: 1.25; }
}
