/* ludoo.online — the public site.
 *
 * SEPARATE STYLESHEET, SAME LANGUAGE. The client is an app: fixed viewports,
 * no page scroll, a screen that is one screen. A website is a document — it
 * scrolls, it is read at arm's length, it is indexed, and it has to be fast on
 * a phone on a bad connection. Sharing one stylesheet would make both worse.
 *
 * What IS shared is everything a person can see: the wood and the felt, the
 * brass, the cream, the gold-leaf display face, the pills, the segmented tabs
 * whose selection slides, the peek carousels that show the next card's edge,
 * the bottom sheet that drags to dismiss, and the seat colours. Somebody who
 * reads this page and then opens the app should not have to be told they are
 * in the same place.
 *
 * THE PHONE IS THE DESIGN, not a narrowing of the desktop. Three rules follow
 * and they are the reason this file is shaped as it is:
 *
 *   1. NAVIGATION LIVES AT THE BOTTOM, in the thumb's arc — a fixed pill in the
 *      same idiom as the app's own bottom bar. The top of a phone is where the
 *      brand goes, because nobody can reach it.
 *   2. A LIST OF CARDS IS A RAIL, not a stack. Four things stacked is four
 *      screens of scrolling; four things on a rail with the fifth's edge
 *      showing is one screen and an invitation.
 *   3. NOTHING IMPORTANT IS TALLER THAN A THUMB CAN REACH. Cards top out around
 *      the height of a hand, and anything that would be taller becomes tabs.
 */

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

@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("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("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: "Inter Variable", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  /* The display face is the app's: Georgia, which is on every device the site
     will be read on and is what the wordmark, the winner's card and YOUR TURN
     are already set in. A webfont here would be a second personality. */
  --display: Georgia, "Iowan Old Style", "Times New Roman", serif;

  --bg: #140d05;
  --ink: #f2e7ce;
  --muted: #b5a084;
  --dim: #8a7a5e;

  --brass: #c79537;
  --brass-lit: #e4c276;
  --brass-soft: rgba(199, 149, 55, .12);
  --brass-line: rgba(199, 149, 55, .5);
  --brass-glow: rgba(199, 149, 55, .32);

  --green: #1e6a3e;
  --green-lit: #2a8b53;

  /* The four seats, exactly as the board paints them. */
  --south: #a44735;  --south-ink: #d98c79;
  --west:  #1e6a3e;  --west-ink:  #5fb183;
  --north: #28567e;  --north-ink: #6fa3d1;
  --east:  #d5a520;  --east-ink:  #e8c25c;

  --fill: rgba(255, 236, 200, .045);
  --fill-soft: rgba(255, 236, 200, .028);
  --fill-hover: rgba(255, 236, 200, .08);
  --hair: rgba(228, 194, 118, .13);
  --hair-bright: rgba(228, 194, 118, .28);
  --glass: rgba(52, 36, 18, .58);
  --glass-strong: rgba(30, 20, 9, .9);
  --track: rgba(255, 236, 200, .08);
  --seg-fill: #5a4114;

  --r-card: 24px;
  --r-hero: 32px;
  --shadow-pop: 0 20px 60px rgba(0, 0, 0, .55);
  --ease: cubic-bezier(.16, 1, .3, 1);
  --col: min(100% - 36px, 1120px);
  /* How much room the fixed bottom bar needs from every page that scrolls
     under it. Stated once so no page has to remember. */
  --thumb-bar: calc(70px + env(safe-area-inset-bottom, 0px));
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.62;
  color: var(--ink);
  /* The felt at the top of the glass, exactly as the app's body paints it. */
  background:
    radial-gradient(120% 70% at 50% -8%, #2d1d0c 0%, var(--bg) 58%),
    var(--bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  padding-bottom: var(--thumb-bar);
}
@media (min-width: 900px) { body { padding-bottom: 0; } }

.wrap { width: var(--col); margin-inline: auto; }

::selection { background: var(--brass); color: #1b1108; }
:focus-visible { outline: 2px solid var(--brass-lit); outline-offset: 3px; border-radius: 6px; }

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

h1, h2, h3, h4 { letter-spacing: -0.02em; line-height: 1.12; margin: 0 0 14px; }
h1 { font-size: clamp(36px, 7.4vw, 66px); font-weight: 800; }
/* The display face runs wide — uppercase, letterspaced, and a serif. Given the
   sans's scale it put four one-word lines on a phone, so it gets its own. */
h1.leaf { font-size: clamp(31px, 8.2vw, 60px); }
h2.leaf { font-size: clamp(25px, 5vw, 42px); }
h2 { font-size: clamp(26px, 4vw, 40px); font-weight: 780; }
h3 { font-size: clamp(19px, 2vw, 22px); font-weight: 700; }
h4 { font-size: 16px; font-weight: 700; }
p { margin: 0 0 18px; }
a { color: var(--brass-lit); text-underline-offset: 3px; }
strong, b { color: var(--ink); font-weight: 700; }

/* THE TABLE'S OWN VOICE: gold leaf, lit at the top and bronze at the foot,
   with a shadow under it. The same treatment as YOUR TURN on the board, so a
   headline here and the label over a match are recognisably one product. */
.leaf {
  font-family: var(--display);
  font-weight: 700; text-transform: uppercase; letter-spacing: .055em;
  line-height: 1.1;
  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);
}

.eyebrow {
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--brass); font-weight: 700; margin: 0 0 12px;
}
.lede { font-size: clamp(17.5px, 2.1vw, 21px); color: var(--muted); line-height: 1.55; }
.small { font-size: 14.5px; color: var(--dim); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------ the top bar */

/* On a phone the header carries the mark and nothing else — the navigation is
   at the other end of the screen, where the thumb is. It scrolls away with the
   page rather than eating 56px of a small screen for the whole visit. */
header.top {
  position: relative; z-index: 20;
  padding: 14px 0 6px;
}
header.top .wrap { display: flex; align-items: center; gap: 22px; }
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--ink); }
.brand img { width: 96px; height: auto; display: block; }
nav.links { display: none; }

@media (min-width: 900px) {
  header.top {
    position: sticky; top: 0;
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    background: rgba(20, 13, 5, .72);
    border-bottom: 1px solid var(--hair);
    padding: 10px 0;
  }
  nav.links { display: flex; gap: 2px; margin-left: auto; align-items: center; }
  nav.links a {
    color: var(--muted); text-decoration: none; font-size: 14.5px; font-weight: 600;
    padding: 9px 13px; border-radius: 999px;
    transition: color .3s var(--ease), background .3s var(--ease);
  }
  nav.links a:hover { color: var(--ink); background: var(--fill-hover); }
  nav.links a[aria-current="page"] { color: var(--brass-lit); background: var(--brass-soft); }
  nav.links .btn { margin-left: 8px; }
}

/* ----------------------------------------------------- the bottom bar

   The phone's navigation, in the thumb's arc. A pill that floats over the page
   rather than a bar welded to the foot: the page keeps its full height, the
   bar keeps its own shape, and the last item — the one people actually want —
   wears brass so the thumb can find it without reading.

   The row scrolls when it overflows, with a fade at whichever edge has more
   behind it, so nothing is ever hidden behind a menu nobody opens. */
.thumbnav {
  position: fixed; z-index: 40;
  left: 0; right: 0; bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  display: flex; justify-content: center; pointer-events: none;
}
@media (min-width: 900px) { .thumbnav { display: none; } }

.thumbnav-pill {
  pointer-events: auto; position: relative; overflow: hidden;
  max-width: calc(100vw - 24px);
  padding: 5px;
  border-radius: 999px;
  background: var(--glass-strong);
  border: 1px solid var(--hair-bright);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .6);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
}
.thumbnav-rail {
  display: flex; align-items: center; gap: 2px;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.thumbnav-rail::-webkit-scrollbar { display: none; }
.thumbnav a, .thumbnav button {
  flex: none; scroll-snap-align: center;
  display: inline-flex; align-items: center; gap: 6px;
  /* 44px of height, which is the smallest a thumb should be asked to hit. */
  min-height: 44px; padding: 0 15px;
  border: 0; background: none; font: inherit; cursor: pointer;
  border-radius: 999px; white-space: nowrap; text-decoration: none;
  font-size: 13px; font-weight: 650; letter-spacing: .01em;
  color: var(--muted);
  transition: color .3s var(--ease), background .3s var(--ease);
}
.thumbnav a[aria-current="page"] { color: var(--brass-lit); background: var(--seg-fill); }
.thumbnav a.go { color: #fff; background: linear-gradient(180deg, var(--green-lit), var(--green)); }
.thumbnav-fade {
  position: absolute; top: 0; bottom: 0; width: 30px; pointer-events: none;
  opacity: 0; transition: opacity .25s var(--ease);
}
.thumbnav-fade.on { opacity: 1; }
.thumbnav-fade.l { left: 0; background: linear-gradient(90deg, #1e1409, transparent); }
.thumbnav-fade.r { right: 0; background: linear-gradient(270deg, #1e1409, transparent); }

/* ---------------------------------------------------------------- blocks */

section { padding: clamp(46px, 7vw, 92px) 0; position: relative; }
section.hairline { border-top: 1px solid var(--hair); }

.grid { display: grid; gap: 16px; }
@media (min-width: 760px) {
  .grid.two { grid-template-columns: 1fr 1fr; gap: 20px; }
  .grid.three { grid-template-columns: repeat(3, 1fr); gap: 20px; }
  .grid.split { grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 64px); align-items: center; }
}

.card {
  background: var(--fill); border: 1px solid var(--hair);
  border-radius: var(--r-card); padding: 24px 22px;
}
.card h3 { margin-bottom: 8px; }
.card p:last-child { margin-bottom: 0; }
.card.lit { border-color: var(--hair-bright); background: var(--fill-hover); }

/* A card with a number in front of it — the app's own eyebrow-and-figure. */
.stat { display: grid; gap: 2px; }
.stat b { font-family: var(--display); font-size: clamp(30px, 5vw, 42px); font-weight: 700; color: var(--brass-lit); line-height: 1; }
.stat span { font-size: 13.5px; color: var(--muted); }

.rail-cta { display: flex; gap: 12px; flex-wrap: wrap; margin: 26px 0 0; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border-radius: 999px; padding: 0 24px; min-height: 52px;
  font: inherit; font-weight: 700; font-size: 16px;
  text-decoration: none; cursor: pointer; border: 1px solid transparent;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease),
    background .3s var(--ease), border-color .3s var(--ease);
}
.btn.go {
  background: linear-gradient(180deg, var(--green-lit), var(--green));
  color: #ffffff; box-shadow: 0 10px 26px rgba(0, 0, 0, .45);
}
.btn.go:hover { transform: translateY(-1px); box-shadow: 0 14px 32px rgba(0, 0, 0, .55); }
.btn.brass {
  background: linear-gradient(180deg, var(--brass-lit), var(--brass));
  color: #1b1108; box-shadow: 0 10px 26px rgba(0, 0, 0, .45);
}
.btn.brass:hover { transform: translateY(-1px); }
.btn.quiet { background: var(--fill); border-color: var(--hair-bright); color: var(--ink); }
.btn.quiet:hover { background: var(--fill-hover); border-color: var(--brass-line); }
.btn.mini { min-height: 40px; padding: 0 16px; font-size: 14px; }

/* Chips, exactly as the app wears them. */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  border-radius: 999px; padding: 8px 14px; font: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--muted); background: var(--fill); border: 1px solid var(--hair);
}
.chip.on { color: var(--brass-lit); border-color: var(--brass-line); background: var(--brass-soft); }
.chip.seat-south { color: var(--south-ink); border-color: rgba(217, 140, 121, .4); }
.chip.seat-west { color: var(--west-ink); border-color: rgba(95, 177, 131, .4); }
.chip.seat-north { color: var(--north-ink); border-color: rgba(111, 163, 209, .4); }
.chip.seat-east { color: var(--east-ink); border-color: rgba(232, 194, 92, .4); }

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

   The app's control, unchanged: a grey track with one raised pill that SLIDES
   to the selected tab, so the movement reads as the selection travelling and
   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%;
  background: var(--track); border-radius: 999px; padding: 4px;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .35);
}
.seg.block { display: grid; width: 100%; }
.seg-thumb {
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  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: 1px solid var(--brass-line);
  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; min-height: 40px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; border-radius: 999px; border: 0; background: none; cursor: pointer;
  font: inherit; 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-lit); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .seg-thumb { transition: none; } }

/* A rail of tabs, for when there are more labels than a phone shares out
   evenly — the standings pattern: 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. */
.seg.rail { display: flex; width: 100%; gap: 2px; overflow-x: auto; scrollbar-width: none; contain: inline-size; }
.seg.rail::-webkit-scrollbar { display: none; }
.seg.rail .seg-thumb { display: none; }
.seg.rail .seg-tab[aria-selected="true"] { background: var(--seg-fill); border: 1px solid var(--brass-line); }

/* -------------------------------------------------------- the peek rail

   Cards a little under half the width, so two sit in view and the third shows
   its edge — and the EDGE is what says there is more, which is why there are
   no dots on this one. The rail bleeds past the text column to the glass,
   because a card that stops neatly at the margin looks like the last card. */
.rail {
  margin-inline: calc(50% - 50vw); width: 100vw;
  padding-inline: max(18px, calc(50vw - var(--col) / 2));
  display: flex; gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  /* WITHOUT THIS THE RAIL SETTLES ON THE WRONG PIXEL. A snap point aligns to
     the scrollport's edge, not to the padding inside it, so the first card
     snapped flush against the glass and threw the whole rail 36px out of line
     with the column above it. */
  scroll-padding-inline: max(18px, calc(50vw - var(--col) / 2));
  -webkit-overflow-scrolling: touch;
  padding-block: 4px 8px;
}
.rail::-webkit-scrollbar { display: none; }
.rail > * { flex: 0 0 var(--peek, 78%); max-width: 340px; scroll-snap-align: start; }
@media (min-width: 620px) { .rail > * { flex-basis: var(--peek-md, 42%); } }
@media (min-width: 1000px) {
  /* On a laptop a rail that cannot be swiped is just a row, so it becomes
     one — with everything in view and nothing to drag. */
  .rail { display: grid; grid-template-columns: repeat(var(--cols, 4), 1fr); width: auto; margin-inline: 0; padding-inline: 0; overflow: visible; }
  .rail > * { max-width: none; }
}

.dots { display: flex; justify-content: center; gap: 0; padding: 6px 0 0; }
/* SIX PIXELS TO LOOK AT, THIRTY-FOUR TO HIT. The dot is drawn on a
   pseudo-element and the button around it is a proper target — a 6px control
   is a decoration that happens to be clickable, which is not the same thing. */
.dot {
  width: 34px; height: 34px; border: 0; padding: 0; cursor: pointer;
  background: none; display: grid; place-items: center;
}
.dot::before {
  content: ""; width: 6px; height: 6px; border-radius: 999px;
  background: var(--hair-bright); transition: all .32s var(--ease);
}
.dot[aria-current="true"]::before { background: var(--brass-lit); width: 18px; }
@media (min-width: 1000px) { .dots { display: none; } }

/* ------------------------------------------------------------ the hero */

.hero {
  padding-top: clamp(18px, 3vw, 34px);
  /* Room under the words for the board to sit in, cut off by the foot of the
     section — a table you are at rather than a picture behind the type. */
  padding-bottom: clamp(250px, 46vw, 330px);
  /* GRID, NOT FLEX. `.wrap` is sized with `min(100% - 36px, 1120px)`, and a
     percentage inside min() on a FLEX item resolves against a base size that
     is still indefinite while the row is being laid out — so the column
     collapsed to its content width and the headline ran off the left edge.
     A grid item's percentage resolves against the track, which is definite. */
  display: grid; align-content: start;
}
@media (min-width: 760px) { .hero { padding-bottom: clamp(40px, 6vw, 80px); align-content: center; min-height: 76vh; } }
.hero h1 { margin-bottom: 18px; }
.hero .lede { max-width: 34ch; }
@media (min-width: 760px) { .hero .lede { max-width: 46ch; } }

/* THE BOARD AND THE DIE, behind the words.
   A canvas pinned behind the hero column, faded out at its foot so the type
   never has to compete with a rendered edge. It is decoration: it takes no
   pointer, it is announced to nothing, and the page is complete without it. */
.stage {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 0 62%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0 62%, transparent 100%);
}
.stage canvas { display: block; width: 100%; height: 100%; }
/* THE WORDS ALWAYS WIN. A scrim over the board, heaviest where the column is,
   so a headline in gold leaf never has to be read through a yellow home
   square. Painted here rather than dimmed in the scene, because the still SVG
   needs the same protection and neither should know about the other. */
.stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(20, 13, 5, .96) 0%, rgba(20, 13, 5, .93) 42%,
    rgba(20, 13, 5, .5) 60%, rgba(20, 13, 5, .06) 100%);
}
@media (min-width: 760px) {
  .stage::after {
    background: linear-gradient(95deg,
      rgba(20, 13, 5, .95) 0%, rgba(20, 13, 5, .9) 38%,
      rgba(20, 13, 5, .42) 62%, rgba(20, 13, 5, .04) 88%);
  }
}
.hero .wrap { position: relative; z-index: 1; }
/* The still that stands in until — or instead of — the canvas: a board drawn
   in SVG, which costs nothing and is what somebody with reduced motion, no
   WebGL or a slow connection actually sees. */
.stage-still {
  position: absolute; left: 50%; bottom: -14%;
  transform: translateX(-46%) rotate(-6deg);
  width: min(86vw, 460px); opacity: .8;
  transition: opacity .6s var(--ease);
}
.stage.live .stage-still { opacity: 0; }
@media (min-width: 760px) {
  .stage-still { left: auto; right: 2%; bottom: auto; top: 50%; transform: translateY(-46%) rotate(-6deg); width: min(46vw, 620px); opacity: .62; }
}

/* ------------------------------------------------------- the phone frame

   A real phone around a real screenshot. Drawn rather than photographed: a
   device photograph dates the moment the next handset ships, and this one is
   the right shape on every screen because it is a box with a radius. */
.phone {
  position: relative;
  /* Bounded by the viewport's HEIGHT as well as its width: a 300px phone is
     650px tall, which on a small screen is a section you scroll past rather
     than a picture you look at. */
  width: 100%; max-width: min(300px, 42vh); margin-inline: auto;
  aspect-ratio: 390 / 844;
  border-radius: 40px;
  padding: 8px;
  background: linear-gradient(160deg, #4a3116 0%, #241708 40%, #35220d 100%);
  box-shadow:
    0 0 0 1px rgba(228, 194, 118, .22),
    0 30px 70px rgba(0, 0, 0, .6),
    inset 0 1px 0 rgba(255, 236, 200, .18);
}
.phone-screen {
  position: relative; height: 100%; width: 100%;
  border-radius: 33px; overflow: hidden;
  background: var(--bg);
}
.phone-screen img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* NO ISLAND. A drawn phone wants one, and the first version had one — but the
   screenshots inside are captured without a status bar, so the island landed
   squarely on the app's own wordmark. A frame that covers the product it is
   framing is a worse lie than a phone with no notch. */
/* A glint down the left edge instead, which is what actually reads as glass. */
.phone::after {
  content: ""; position: absolute; inset: 0; border-radius: 40px; pointer-events: none;
  background: linear-gradient(100deg, rgba(255, 236, 200, .16) 0%, transparent 18%, transparent 82%, rgba(255, 236, 200, .07) 100%);
}
/* Two phones side by side, the back one turned — a table, not a product shot. */
.phones { position: relative; display: grid; place-items: center; padding: 8px 0; }
.phones .phone { max-width: min(268px, 40vh); }
.phones .phone.behind {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-78%, -50%) rotate(-9deg) scale(.86);
  opacity: .55; filter: saturate(.85);
  z-index: 0;
}
.phones .phone.front { z-index: 1; }
@media (max-width: 520px) { .phones .phone.behind { display: none; } }

/* A screen everyone can see: the Table, in a laptop's shape. */
.screen-frame {
  border-radius: 18px; padding: 10px 10px 0;
  background: linear-gradient(160deg, #4a3116, #241708);
  box-shadow: 0 0 0 1px rgba(228, 194, 118, .2), 0 26px 60px rgba(0, 0, 0, .55);
}
.screen-frame img { display: block; width: 100%; border-radius: 10px 10px 0 0; }
.screen-frame + .screen-foot {
  height: 12px; border-radius: 0 0 14px 14px; margin-inline: -2%;
  background: linear-gradient(180deg, #4a3116, #1c1207);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .5);
}

/* ------------------------------------------------------- the mode poster

   The app's own card: a group picture in the top half, cropped at the legs and
   never at the faces, the name in the display face at the foot, an eyebrow
   above it. Unchosen cards are muted rather than drained — a pink hoodie
   should still be a pink hoodie on a card you have not opened. */
.poster {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: 310px; padding: 0 18px 20px;
  border-radius: var(--r-card);
  border: 1px solid var(--hair);
  background: linear-gradient(180deg, rgba(58, 42, 22, .34), rgba(20, 13, 5, .62));
  text-decoration: none; color: inherit;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
}
.poster:hover { border-color: var(--brass-line); transform: translateY(-2px); }
/* THE PICTURE IS BEHIND THE WORDS, cropped at the legs and never at the faces
   — the app's own rule. It fills the card's width from the top, is cut off by
   its own box, and fades out well before the type starts, so the name always
   stands on felt rather than on somebody's chest. `z-index: -1` inside the
   card's isolated stacking context, which is exactly how the client does it. */
.poster img {
  position: absolute; left: 0; right: 0; top: 0; z-index: -1;
  width: 100%; height: 74%;
  object-fit: cover; object-position: top center;
  -webkit-mask-image: linear-gradient(180deg, #000 44%, transparent 94%);
  mask-image: linear-gradient(180deg, #000 44%, transparent 94%);
}
.poster-text { position: relative; }
.poster-eyebrow {
  display: block; font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--brass); font-weight: 700; margin-bottom: 4px;
}
.poster-name { display: block; font-family: var(--display); font-size: 26px; font-weight: 700; line-height: 1.05; }
.poster-blurb { margin: 6px 0 0; font-size: 13.5px; color: var(--muted); line-height: 1.45; }

/* --------------------------------------------------------- the cast card

   The app's character card, restated for a page: the action shot, the name,
   and the six numbers the engine actually plays with. The numbers are derived
   from the cast file, not written by hand — a card that showed a temperament
   the engine does not play would be a lie. */
.cast-card {
  position: relative; overflow: hidden;
  border-radius: var(--r-card); border: 1px solid var(--hair);
  background: linear-gradient(180deg, rgba(58, 42, 22, .5), rgba(20, 13, 5, .5));
  display: flex; flex-direction: column;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
}
.cast-card:hover { border-color: var(--brass-line); transform: translateY(-2px); }
.cast-art {
  position: relative; aspect-ratio: 1 / 1; overflow: hidden;
  background: radial-gradient(70% 60% at 50% 30%, #3a2a16, #161007);
}
.cast-art img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 8%; display: block;
  -webkit-mask-image: linear-gradient(180deg, #000 0 78%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0 78%, transparent 100%);
}
.cast-body { padding: 0 18px 18px; }
.cast-name { font-family: var(--display); font-size: 23px; font-weight: 700; margin: -14px 0 2px; position: relative; }
.cast-say { font-size: 13px; color: var(--muted); line-height: 1.45; margin: 0 0 14px; min-height: 3.6em; }

.bars { display: grid; gap: 7px; margin: 0; }
.bar { display: grid; grid-template-columns: 74px 1fr 28px; align-items: center; gap: 9px; }
.bar dt { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); font-weight: 700; }
.bar-track { height: 6px; border-radius: 999px; background: var(--track); overflow: hidden; }
.bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--brass), var(--brass-lit));
  /* Grown from nothing when the card first comes into view: the numbers ARE
     the content here, and watching them fill is how a reader notices they
     differ from one another. */
  width: 0; transition: width .9s var(--ease);
}
.in-view .bar-fill { width: var(--v, 0%); }
@media (prefers-reduced-motion: reduce) { .bar-fill { transition: none; width: var(--v, 0%); } }
.bar dd { margin: 0; font-size: 12px; font-weight: 700; color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------- steps and lists */

ol.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
ol.steps li {
  counter-increment: step; position: relative;
  padding: 18px 20px 18px 62px;
  background: var(--fill); border: 1px solid var(--hair); border-radius: 18px;
}
ol.steps li::before {
  content: counter(step);
  position: absolute; left: 18px; top: 16px;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brass-soft); color: var(--brass-lit);
  border: 1px solid var(--brass-line);
  font-size: 14px; font-weight: 800;
}
ol.steps li b { display: block; margin-bottom: 2px; }

ul.plain { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 10px; }
ul.plain li { padding-left: 26px; position: relative; color: var(--muted); }
ul.plain li::before {
  content: ""; position: absolute; left: 6px; top: .62em;
  width: 7px; height: 7px; border-radius: 2px; background: var(--brass);
  transform: rotate(45deg);
}
ul.plain li b { color: var(--ink); }

/* An honest note about something that is not built yet. Kept, and kept
   prominent: this site says what is not finished, and the design should not
   make that look like fine print. */
.note {
  border-radius: 18px; padding: 18px 20px;
  background: var(--brass-soft); border: 1px solid rgba(199, 149, 55, .24);
  color: var(--muted); font-size: 15.5px;
}
.note b { color: var(--brass-lit); }
.note p:last-child { margin-bottom: 0; }

/* An accordion, for a page of rules on a phone: the answer is one tap away and
   the questions all fit on one screen, which a stack of open paragraphs never
   does. <details> because the browser already knows how, and because a closed
   answer is still in the page for a search engine to read. */
details.fold {
  border: 1px solid var(--hair); border-radius: 18px; background: var(--fill-soft);
  padding: 0 18px; margin: 0 0 10px;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
details.fold[open] { border-color: var(--hair-bright); background: var(--fill); }
details.fold > summary {
  cursor: pointer; list-style: none; padding: 16px 30px 16px 0; position: relative;
  font-weight: 700; font-size: 16px; min-height: 44px; display: flex; align-items: center;
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::after {
  content: ""; position: absolute; right: 2px; top: 50%;
  width: 9px; height: 9px; margin-top: -6px;
  border-right: 2px solid var(--brass); border-bottom: 2px solid var(--brass);
  transform: rotate(45deg); transition: transform .3s var(--ease);
}
details.fold[open] > summary::after { transform: rotate(-135deg); margin-top: -2px; }
details.fold > *:not(summary) { margin-bottom: 16px; color: var(--muted); font-size: 15.5px; }

table.plain { width: 100%; border-collapse: collapse; font-size: 15.5px; }
table.plain th, table.plain td {
  text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--hair); vertical-align: top;
}
table.plain th { color: var(--brass); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
.scroller { overflow-x: auto; }

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

   The app's drawer: a sheet that comes up from the foot, drags down to
   dismiss, and never covers more of the screen than it needs. Used here for
   the rest of the navigation and for a character read in full. */
.sheet-scrim {
  position: fixed; inset: 0; z-index: 50; background: rgba(8, 5, 2, .6);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  opacity: 0; transition: opacity .3s var(--ease);
}
.sheet-scrim.open { opacity: 1; }
.sheet {
  position: fixed; z-index: 51; left: 0; right: 0; bottom: 0;
  max-height: 86dvh; overflow: hidden;
  border-radius: 26px 26px 0 0;
  background: var(--glass-strong);
  border-top: 1px solid var(--hair-bright);
  box-shadow: 0 -20px 60px rgba(0, 0, 0, .6);
  backdrop-filter: blur(20px) saturate(160%); -webkit-backdrop-filter: blur(20px) saturate(160%);
  transform: translateY(100%);
  transition: transform .38s var(--ease);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  touch-action: none;
}
.sheet.open { transform: translateY(0); }
.sheet-handle {
  width: 42px; height: 4px; border-radius: 999px; background: var(--hair-bright);
  margin: 10px auto 4px;
}
.sheet-head { display: flex; align-items: center; gap: 12px; padding: 4px 20px 8px; }
.sheet-head h3 { margin: 0; font-size: 17px; }
.sheet-head .close {
  margin-left: auto; width: 36px; height: 36px; border-radius: 999px;
  border: 1px solid var(--hair); background: var(--fill); color: var(--ink);
  font-size: 18px; line-height: 1; cursor: pointer;
}
.sheet-body { padding: 4px 20px 24px; overflow-y: auto; max-height: calc(86dvh - 70px); touch-action: pan-y; }
.sheet-links { display: grid; gap: 2px; }
.sheet-links a {
  display: flex; align-items: center; min-height: 52px; padding: 0 14px;
  border-radius: 14px; text-decoration: none; color: var(--ink); font-weight: 600;
}
.sheet-links a:hover, .sheet-links a[aria-current="page"] { background: var(--fill-hover); color: var(--brass-lit); }
.sheet-links small { display: block; color: var(--dim); font-weight: 400; font-size: 13px; }

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

   Sections rise a few pixels as they come into view. Small on purpose: the
   page is a document, and a document that performs is a document nobody
   finishes. Off entirely under reduced motion. */
.rise { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.rise.in-view { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .rise { opacity: 1; transform: none; transition: none; }
}
/* Nothing hides before the script that reveals it has had a chance to run. */
html.no-js .rise { opacity: 1; transform: none; }

/* ----------------------------------------------------------- the footer */

footer.foot {
  border-top: 1px solid var(--hair);
  padding: 40px 0 44px;
  color: var(--dim); font-size: 14.5px;
}
footer.foot .wrap { display: grid; gap: 18px; }
footer.foot nav { display: flex; gap: 10px 20px; flex-wrap: wrap; }
footer.foot a { color: var(--muted); text-decoration: none; }
footer.foot a:hover { color: var(--ink); }

/* ------------------------------------------------------------ the ask

   Anonymous usage data, asked for once, at the foot and never over a button.
   Same wording and same shape as the app's, because it is the same question
   and a person who has answered it in one place should recognise it in the
   other. */
.consent {
  position: fixed; z-index: 45;
  left: 12px; right: 12px; bottom: calc(var(--thumb-bar) + 6px);
  max-width: 520px; margin-inline: auto;
  display: none; gap: 10px;
  padding: 14px 16px; border-radius: 20px;
  background: var(--glass-strong); border: 1px solid var(--hair-bright);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(16px) saturate(150%); -webkit-backdrop-filter: blur(16px) saturate(150%);
}
.consent.open { display: grid; }
.consent p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--muted); }
.consent p b { display: block; color: var(--ink); font-size: 14px; margin-bottom: 2px; }
.consent-row { display: flex; gap: 8px; justify-content: flex-end; }
@media (min-width: 900px) { .consent { bottom: 16px; } }

/* --------------------------------------------------------------- narrow */

@media (max-width: 560px) {
  body { font-size: 16.5px; }
  section { padding: 40px 0; }
  .card { padding: 20px 18px; }
  ol.steps li { padding: 16px 18px 16px 56px; }
  ol.steps li::before { left: 16px; }
}

/* The cast around a board — the same picture the game opens on, so arriving at
   the app after this page is a continuation rather than a surprise. */
.gather { margin: 34px 0 0; padding: 0; }
.gather img {
  display: block; width: 100%; max-width: 980px; margin-inline: auto;
  -webkit-mask-image: linear-gradient(180deg, #000 0 62%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0 62%, transparent 100%);
}

/* The eighth tile: the cast is not finished, and a grid that pretends it is
   would be the one dishonest thing on the page. Matches the app's own
   "more soon" tile — a dashed outline and a question mark. */
.cast-card.soon { border-style: dashed; background: var(--fill-soft); }
.cast-card.soon .cast-art {
  display: grid; place-items: center;
  background: radial-gradient(70% 60% at 50% 40%, rgba(199, 149, 55, .08), transparent);
}
.cast-card.soon .cast-art span {
  font-family: var(--display); font-size: 64px; color: var(--hair-bright); line-height: 1;
}
.cast-card.soon .cast-name { margin-top: 0; }
.cast-card.soon:hover { transform: none; border-color: var(--hair); }

/* --------------------------------------------------------------- the tray

   Where the die lives on this page. Sized like the client's own throw
   surface — wide enough that a sweep has somewhere to go, short enough that
   it does not become the section. It takes the pointer, and only it: the
   page must still scroll everywhere else, which is why `touch-action` is
   `none` on the tray alone and not on anything around it. */
.tray {
  position: relative; margin: 22px 0 0;
  aspect-ratio: 3 / 2; max-height: 300px;
  border-radius: var(--r-card);
  border: 1px solid var(--hair);
  background:
    radial-gradient(80% 70% at 50% 30%, #1b5334 0%, #0e2c1c 62%, #0a1f14 100%);
  overflow: hidden;
  box-shadow: inset 0 2px 24px rgba(0, 0, 0, .5);
}
/* THE PAD IS THE DIE. `touch-action: none` lives on this square alone, which
   follows the die: everywhere else on the tray a thumb still scrolls the page,
   which on a phone is what a thumb in the middle of an article is doing. */
.tray-grip {
  position: absolute; width: 96px; height: 96px;
  transform: translate(-50%, -50%);
  touch-action: none; cursor: grab;
  border-radius: 50%;
  transition: opacity .2s var(--ease);
}
.tray.held .tray-grip { cursor: grabbing; }
.tray canvas { display: block; width: 100%; height: 100%; }
.tray-say {
  position: absolute; left: 0; right: 0; bottom: 12px; margin: 0;
  text-align: center; font-size: 11.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--brass); font-weight: 700; pointer-events: none;
  transition: opacity .4s var(--ease);
}
/* The face it landed on, read out under the die — the number is the point,
   and a die you have to squint at has not answered you. */
.tray[data-face]::after {
  content: attr(data-face);
  position: absolute; top: 12px; right: 16px;
  font-family: var(--display); font-size: 30px; font-weight: 700;
  color: var(--brass-lit); opacity: .9; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  /* No die, and no empty green box either: the paragraph above says it. */
  .tray { display: none; }
}
/* The nickname under the name on a cast card — the same brass, letterspaced
   voice the app's own card uses, because it is the same idea. */
.cast-alias {
  margin: 1px 0 8px; font-size: 10.5px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--brass); font-weight: 700;
}
