/* =========================================================================
   CITY RIVALS — design system
   -------------------------------------------------------------------------
   SURFACE RULE (the one that keeps the interface calm)

   There is exactly ONE level of surface. Panels and modal cards are the only
   bordered containers on screen. Everything inside them is flat: sections are
   separated by a hairline or by space, never by a second box. Nothing is ever
   a card inside a card. The only bordered things inside a panel are actual
   controls — buttons, inputs, chips, board tiles.

   -------------------------------------------------------------------------
   COLOUR CONTRACT (do not extend without deleting something first)

   One background. No gradients, no backdrop-filter. Shadow is reserved for
   things that float above the page (modals, toasts) — a panel that sits in
   the layout never casts one, so "raised" always means "on top".

     --ink       the primary action of the moment: roll, start, send, done
     --positive  green   money coming in or an acquisition: buy, build, accept
     --danger    red     genuinely destructive: fold, leave, decline
     --gold      gold    hotels, the pot, the winner
     --info      blue    selection, navigation, neutral information

   The eight property-set colours and the player token colours are DATA, not
   accents. They appear only on the set band of a tile, the accent rail of a
   deed, the swatch of a district row, and player tokens/dots.

   -------------------------------------------------------------------------
   MOTION CONTRACT

   Every animation is caused by something a player did. There is no ambient
   motion: nothing loops, pulses or breathes on its own. Two tiers:

     interface   <=140ms. Hover changes colour, press moves 1px. Nothing else.
     game event  up to ~1s, and only for the four moments that carry real
                 information: dice tumbling, a token walking, a building going
                 up, a cash figure changing.

   Both collapse to nothing under `prefers-reduced-motion` and under the
   Animations switch (body.no-anim).
   ========================================================================= */

/* ---- fonts -------------------------------------------------------------- */
@font-face{font-family:Manrope;font-style:normal;font-display:swap;font-weight:200 800;src:url(assets/manrope-latin-wght-normal-DHIcAJRg.woff2) format("woff2-variations");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+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:Manrope;font-style:normal;font-display:swap;font-weight:200 800;src:url(assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Space Grotesk";font-style:normal;font-display:swap;font-weight:300 700;src:url(assets/space-grotesk-latin-wght-normal-BhU9QXUp.woff2) format("woff2-variations");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+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Space Grotesk";font-style:normal;font-display:swap;font-weight:300 700;src:url(assets/space-grotesk-latin-ext-wght-normal-D9tNdqV9.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
/* Player names are free text — these subsets only download if a name needs them. */
@font-face{font-family:Manrope;font-style:normal;font-display:swap;font-weight:200 800;src:url(assets/manrope-cyrillic-wght-normal-Dvxsihut.woff2) format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}
@font-face{font-family:Manrope;font-style:normal;font-display:swap;font-weight:200 800;src:url(assets/manrope-greek-wght-normal-DL7QRZyv.woff2) format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}
@font-face{font-family:Manrope;font-style:normal;font-display:swap;font-weight:200 800;src:url(assets/manrope-vietnamese-wght-normal-usUDDRr7.woff2) format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}
@font-face{font-family:"Space Grotesk";font-style:normal;font-display:swap;font-weight:300 700;src:url(assets/space-grotesk-vietnamese-wght-normal-D0rl6rjA.woff2) format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}

/* ---- tokens ------------------------------------------------------------- */
:root{
  --bg:#0e1116;
  --surface:#161a23;
  --surface-2:#1e2330;
  --surface-3:#2a3040;
  --line:#2f3646;
  --line-soft:#232936;

  --ink:#eef1f7;
  --ink-2:#a8b2c4;
  --ink-3:#78849b;

  --brand:#5b8cff;    /* the app's own colour: navigation, selection, links */
  --info:#5b8cff;     /* same hue — kept as an alias so old rules still read */
  --positive:#35d07f;
  --danger:#ff5c62;
  --gold:#ffc247;
  --on-accent:#0b0e14;

  /* Three steps of elevation. A board game has physical pieces sitting on a
     table, so height is meaningful here in a way it was not before — but it
     is still only ever soft neutral shadow, never a glow. */
  --e1:0 1px 2px rgba(0,0,0,.28);
  --e2:0 2px 6px rgba(0,0,0,.34),0 1px 2px rgba(0,0,0,.3);
  --e3:0 18px 44px rgba(0,0,0,.5),0 3px 10px rgba(0,0,0,.36);
  --shadow-pop:var(--e3);   /* legacy alias */

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;
  --r-sm:6px; --r:10px; --r-lg:16px; --r-xl:24px; --r-pill:999px;

  --t-xs:11px; --t-sm:12.5px; --t-md:14px; --t-lg:16px; --t-xl:20px; --t-2xl:26px; --t-3xl:34px;

  --dur:130ms;
  --ease:cubic-bezier(.2,.6,.35,1);

  --z-sticky:10; --z-backdrop:40; --z-modal:50; --z-toast:60;

  --side:250px;   /* players + feed rail */
  --rail:330px;   /* turn / assets / trade / chat rail */
  --nav:52px;     /* the persistent top bar */

  /* Per-city board surfaces. styles/cities.css overrides these per data-city;
     these are the neutral fallback so the board renders before a city is set. */
  --felt:#232936;
  --rim:#2f3646;
  --tile:#161a23;
  --tile-2:#1e2330;
  --tile-ink:#a8b2c4;
  --tile-sub:#78849b;
  --centre:#0e1116;
  --city-accent:#5b8cff;

  --font-ui:Manrope,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --font-display:"Space Grotesk",Manrope,ui-sans-serif,system-ui,sans-serif;
}

/* ---- reset -------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-ui);
  font-size:var(--t-md);
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
h1,h2,h3,h4,p,figure{margin:0}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer;text-align:inherit}
button:disabled{cursor:not-allowed}
img,svg{display:block;max-width:100%}
ul,ol{margin:0;padding:0;list-style:none}
:focus-visible{outline:2px solid var(--info);outline-offset:2px;border-radius:var(--r-sm)}
::selection{background:var(--info);color:var(--on-accent)}

*{scrollbar-width:thin;scrollbar-color:var(--surface-3) transparent}
*::-webkit-scrollbar{width:9px;height:9px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background:var(--surface-3);border-radius:var(--r-pill);border:3px solid transparent;background-clip:content-box}
*::-webkit-scrollbar-thumb:hover{background:var(--line);background-clip:content-box}

/* ---- utility ------------------------------------------------------------ */
.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}
/* A position:absolute element resolves against its nearest POSITIONED
   ancestor. Screen-reader labels deep inside a scrolling panel had none, so
   their containing block was the initial one: they escaped the panel's clip
   and added their static offset to the *document's* scroll height. On a phone
   that let a hard flick drag the whole interface off the top of the window
   into a void — 638px of it in the lobby. Every scroll container is now its
   own containing block, which is what it should have been anyway. */
.mount,.lobby,.home,.tab-panel,.feed,.roster,.chat-log,.modal-body,
.team-standings,.board-wrap,.game-body,.seat-list{position:relative}
.hidden{display:none !important}
[hidden]{display:none !important}
.num{font-family:var(--font-display);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.dim{color:var(--ink-3)}
.pos{color:var(--positive)}
.neg{color:var(--danger)}
.gold{color:var(--gold)}
.info{color:var(--info)}
.row{display:flex;align-items:center;gap:var(--s2)}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:var(--s2)}
.stack{display:flex;flex-direction:column;gap:var(--s2)}
.stack-lg{display:flex;flex-direction:column;gap:var(--s3)}
.grow{flex:1;min-width:0}
.eyebrow{font-size:var(--t-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);font-weight:700}
.hint{font-size:var(--t-xs);color:var(--ink-3);text-wrap:pretty}
.hr{height:1px;background:var(--line-soft);margin:var(--s3) 0}
.ic{width:16px;height:16px;flex:none;fill:none;stroke:currentColor}

/* =========================================================================
   BUTTONS
   One primary per view. Filled buttons brighten on hover; quiet ones gain a
   surface. Press moves one pixel — nothing scales.
   ========================================================================= */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  padding:0 var(--s4);height:38px;
  border-radius:var(--r);
  background:var(--surface-2);
  color:var(--ink);
  border:1px solid var(--line);
  font-size:var(--t-sm);font-weight:600;
  white-space:nowrap;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),
             color var(--dur) var(--ease),box-shadow var(--dur) var(--ease),
             transform var(--dur) var(--ease);
}
.btn:hover:not(:disabled){background:var(--surface-3)}
/* pieces on a table: a filled button sits slightly proud and presses flat */
.btn:active:not(:disabled){transform:translateY(1px)}
.btn:disabled{opacity:.42}

.btn-primary,.btn-positive,.btn-danger,.btn-gold,.btn-info{
  border-color:transparent;font-weight:700;box-shadow:var(--e1);
}
.btn-primary:active:not(:disabled),.btn-positive:active:not(:disabled),
.btn-danger:active:not(:disabled),.btn-gold:active:not(:disabled),
.btn-info:active:not(:disabled){box-shadow:none}

.btn-primary{background:var(--ink);color:var(--bg)}
.btn-primary:hover:not(:disabled){background:#fff;color:var(--bg)}
.btn-positive{background:var(--positive);color:var(--on-accent)}
.btn-positive:hover:not(:disabled){background:color-mix(in srgb,var(--positive) 84%,#fff)}
.btn-danger{background:var(--danger);color:var(--on-accent)}
.btn-danger:hover:not(:disabled){background:color-mix(in srgb,var(--danger) 84%,#fff)}
.btn-gold{background:var(--gold);color:var(--on-accent)}
.btn-gold:hover:not(:disabled){background:color-mix(in srgb,var(--gold) 84%,#fff)}
.btn-info{background:var(--brand);color:#fff}
.btn-info:hover:not(:disabled){background:color-mix(in srgb,var(--brand) 82%,#fff)}
.btn-ghost{background:transparent;border-color:var(--line)}
.btn-ghost:hover:not(:disabled){background:var(--surface-2);border-color:var(--surface-3)}
.btn-quiet{background:transparent;border-color:transparent;color:var(--ink-2)}
.btn-quiet:hover:not(:disabled){background:var(--surface-2);color:var(--ink)}

.btn-lg{height:48px;font-size:var(--t-md);padding:0 var(--s5);border-radius:var(--r-lg)}
.btn-sm{height:30px;font-size:var(--t-xs);padding:0 var(--s3);border-radius:var(--r-sm)}
.btn-block{width:100%}
.btn-icon{width:38px;padding:0;flex:none}
.btn-icon.btn-sm{width:30px}

/* a quiet inline text action — used where a button would be too loud */
.linkish{
  font-size:var(--t-xs);font-weight:600;color:var(--info);
  padding:2px 0;border-radius:var(--r-sm);
}
.linkish:hover{text-decoration:underline}

/* =========================================================================
   PANELS — the only bordered container in the layout
   ========================================================================= */
.panel{
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--e1);
  min-width:0;
}
.panel-head{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);
  min-height:38px;
  padding:var(--s2) var(--s3);
  border-bottom:1px solid var(--line-soft);
}
.panel-head h2{
  font-size:var(--t-xs);font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);
}
.panel-head small,.panel-head .hint{font-size:var(--t-xs);color:var(--ink-3)}
.panel-body{padding:var(--s3)}

/* =========================================================================
   FORM CONTROLS
   ========================================================================= */
.field{display:flex;flex-direction:column;gap:5px}
.field > label{font-size:var(--t-xs);font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em}
.input,select.input{
  height:38px;padding:0 var(--s3);
  background:var(--surface-2);
  border:1px solid var(--line);
  border-radius:var(--r);
  color:var(--ink);
  width:100%;
  font-size:var(--t-sm);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.input::placeholder{color:var(--ink-3)}
.input:hover:not(:focus):not(:disabled){border-color:var(--surface-3)}
.input:focus{border-color:var(--brand);outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 22%,transparent)}
.input:disabled{opacity:.5;cursor:not-allowed}
select.input{appearance:none;cursor:pointer;padding-right:26px;
  background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23949eb5' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right var(--s2) center}
input[type=number].input{text-align:right}

.switch{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);padding:var(--s2) 0;cursor:pointer}
.switch > span{font-size:var(--t-sm);min-width:0}
.switch > span > b{font-weight:600}
.switch small{display:block;color:var(--ink-3);font-size:var(--t-xs);font-weight:400;line-height:1.35;margin-top:1px}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch .track{
  position:relative;flex:none;width:36px;height:20px;border-radius:var(--r-pill);
  background:var(--surface-3);border:1px solid var(--line);
  transition:background var(--dur) var(--ease);
}
.switch .track::after{
  content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
  background:var(--ink-3);
  transition:transform var(--dur) var(--ease),background var(--dur) var(--ease);
}
.switch input:checked + .track{background:var(--info);border-color:transparent}
.switch input:checked + .track::after{transform:translateX(16px);background:var(--on-accent)}
.switch input:focus-visible + .track{outline:2px solid var(--info);outline-offset:2px}
.switch-bare{padding:0;gap:0}

.stepper{display:inline-flex;align-items:center;gap:var(--s1)}
.stepper .num{min-width:22px;text-align:center;font-size:var(--t-sm)}

.setting-row{display:grid;grid-template-columns:1fr 96px;align-items:center;gap:var(--s3);padding:var(--s2) 0}
.setting-row > span{font-size:var(--t-sm);min-width:0}
.setting-row > span > b{font-weight:600}
.setting-row small{display:block;color:var(--ink-3);font-size:var(--t-xs);line-height:1.35;margin-top:1px}
.setting-row .input{height:32px}
.rules-list > .setting-row + .setting-row{border-top:1px solid var(--line-soft)}

.tag{
  display:inline-flex;align-items:center;gap:5px;
  height:22px;padding:0 8px;
  border-radius:var(--r-pill);
  background:var(--surface-2);border:1px solid var(--line);
  font-size:var(--t-xs);font-weight:600;letter-spacing:.02em;color:var(--ink-2);
}
.tag-positive{color:var(--positive);border-color:color-mix(in srgb,var(--positive) 45%,transparent)}
.tag-danger{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 45%,transparent)}
.tag-gold{color:var(--gold);border-color:color-mix(in srgb,var(--gold) 45%,transparent)}
.tag-info{color:var(--info);border-color:color-mix(in srgb,var(--info) 45%,transparent)}

.dot{width:7px;height:7px;border-radius:50%;flex:none;background:var(--ink-3)}
.dot-live{background:var(--positive)}

/* notices carry one sentence, never a paragraph */
.notice{
  display:flex;gap:var(--s2);align-items:center;
  padding:var(--s2) var(--s3);border-radius:var(--r);
  background:var(--surface-2);
  border-left:3px solid var(--line);
  font-size:var(--t-sm);color:var(--ink-2);text-wrap:pretty;line-height:1.4;
}
.notice-danger{border-left-color:var(--danger);color:var(--danger)}
.notice-positive{border-left-color:var(--positive);color:var(--positive)}
.notice-info{border-left-color:var(--info);color:var(--ink-2)}
.notice-gold{border-left-color:var(--gold);color:var(--gold)}

.empty{padding:var(--s5) var(--s3);text-align:center;color:var(--ink-3);font-size:var(--t-sm)}
.empty strong{display:block;color:var(--ink-2);margin-bottom:2px}
.empty p{max-width:32ch;margin:0 auto;text-wrap:pretty}

/* =========================================================================
   APP SHELL
   ========================================================================= */
.app{height:100dvh;display:flex;flex-direction:column}
.screen{display:none;flex:1;min-height:0}
.screen.active{display:flex;flex-direction:column}

/* =========================================================================
   NAVIGATION
   One bar across the whole product. It disappears in the lobby and during a
   match, because both of those need every pixel of height for the board and
   already carry their own context bar.
   ========================================================================= */
.nav{
  display:flex;align-items:center;gap:var(--s2);
  height:var(--nav);flex:none;
  padding:0 var(--s3);
  background:var(--surface);
  border-bottom:1px solid var(--line);
}
body.in-match .nav{display:none}
.nav-brand{display:flex;align-items:center;gap:var(--s2);padding:0 var(--s2) 0 0;flex:none}
.nav-brand img{width:24px;height:24px;border-radius:var(--r-sm)}
/* min-width:0 with unshrinkable children and visible overflow meant the
   links kept their full width while the box collapsed, so on a 375px phone
   "Rooms", "Store" and "Ladder" painted UNDER the coin chip and the account
   button and handed their taps to them. Scroll instead of overlap. */
.nav-links{
  display:flex;align-items:center;gap:2px;
  flex:0 1 auto;min-width:0;
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-ms-overflow-style:none;
  overscroll-behavior-x:contain;
}
.nav-links::-webkit-scrollbar{display:none}
.nav-link{flex:0 0 auto}
.nav-link{
  height:34px;padding:0 var(--s3);border-radius:var(--r);
  font-size:var(--t-sm);font-weight:600;color:var(--ink-3);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
}
.nav-link:hover{color:var(--ink);background:var(--surface-2)}
.nav-link.is-on{color:var(--ink);background:var(--surface-2)}
.coin-chip{
  display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 var(--s3);
  border-radius:var(--r-pill);
  background:color-mix(in srgb,var(--gold) 14%,transparent);
  border:1px solid color-mix(in srgb,var(--gold) 38%,transparent);
  color:var(--gold);font-size:var(--t-sm);font-weight:700;
}
.coin-chip:hover{background:color-mix(in srgb,var(--gold) 22%,transparent)}
.nav-account{
  display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 var(--s3);
  border-radius:var(--r-pill);
  background:var(--surface-2);border:1px solid var(--line);
  font-size:var(--t-sm);font-weight:600;color:var(--ink-2);
  max-width:170px;
}
.nav-account:hover{background:var(--surface-3);color:var(--ink)}
.nav-account span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-account.is-in{color:var(--ink);border-color:var(--brand)}

/* the modules own everything inside their mount; the shell only scrolls it */
.mount{flex:1;min-height:0;overflow-y:auto}

.topbar{
  display:flex;align-items:center;gap:var(--s2);
  padding:var(--s2) var(--s3);
  background:var(--surface);
  border-bottom:1px solid var(--line);
  flex:none;
}
.topbar-title{font-size:var(--t-sm);font-weight:600;color:var(--ink-2);margin-left:var(--s2)}
.brand{display:flex;align-items:center;gap:var(--s2);flex:none}
.brand img{width:26px;height:26px;border-radius:var(--r-sm)}
.brand-name{font-family:var(--font-display);font-size:var(--t-sm);font-weight:700;letter-spacing:.07em;line-height:1}
.brand-name b{color:var(--info);font-weight:700}

.banner{
  display:flex;align-items:center;justify-content:center;gap:var(--s2);
  padding:6px var(--s4);
  background:var(--danger);color:var(--on-accent);
  font-size:var(--t-sm);font-weight:600;
  flex:none;
}

/* ---- loading ------------------------------------------------------------ */
#screen-loading{align-items:center;justify-content:center;gap:var(--s3);padding:var(--s3)}
#screen-loading.active{display:flex;flex-direction:column}
.loading-copy{font-size:var(--t-sm);color:var(--ink-3);flex:none}
.skeleton{
  display:grid;
  grid-template-columns:var(--side) minmax(0,1fr) var(--rail);
  gap:var(--s3);width:100%;max-width:1500px;flex:1;min-height:0;
}
.sk-block{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);position:relative;overflow:hidden}
.sk-block::after{content:"";position:absolute;inset:0;background:var(--surface-2);opacity:0;animation:sk-pulse 1400ms ease-in-out infinite}
.sk-board{aspect-ratio:1;justify-self:center;align-self:center;width:auto;height:100%;max-width:100%}
@keyframes sk-pulse{0%,100%{opacity:0}50%{opacity:.5}}

/* =========================================================================
   HOME — one column, one decision at a time
   ========================================================================= */
.home{flex:1;min-height:0;overflow-y:auto;display:flex;align-items:center;justify-content:center;padding:var(--s5) var(--s4)}
.home-card{width:100%;max-width:420px;display:flex;flex-direction:column;gap:var(--s4);margin:auto}
.home-head{text-align:center;display:flex;flex-direction:column;gap:var(--s2)}
.home-head h1{font-family:var(--font-display);font-size:var(--t-2xl);font-weight:700;letter-spacing:-.02em}
.home-head p{color:var(--ink-2);font-size:var(--t-sm);text-wrap:pretty;max-width:42ch;margin:0 auto}

.identity{display:flex;align-items:center;gap:var(--s2)}

.modes{display:flex;flex-direction:column;gap:var(--s2)}
.mode{
  display:flex;align-items:center;gap:var(--s3);
  width:100%;padding:var(--s4);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--e1);
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.mode:hover:not(:disabled){background:var(--surface-2);border-color:var(--surface-3)}
.mode:active:not(:disabled){transform:translateY(1px)}
.mode:disabled{opacity:.45}
.mode-icon{
  width:36px;height:36px;flex:none;border-radius:var(--r);
  display:grid;place-items:center;
  background:var(--surface-3);color:var(--ink-2);
}
.mode-primary .mode-icon{background:var(--brand);color:#fff}
.mode-copy{min-width:0;flex:1;line-height:1.3}
.mode-copy strong{display:block;font-size:var(--t-md);font-weight:700}
.mode-copy small{display:block;color:var(--ink-3);font-size:var(--t-xs);text-wrap:pretty}
.mode-go{color:var(--ink-3)}
.mode-primary{background:var(--surface-2);border-color:var(--brand)}
.mode-primary .mode-copy strong{color:var(--ink)}
.mode-primary .mode-go{color:var(--ink-2)}
.mode[aria-expanded="true"] .mode-go{transform:rotate(90deg)}
.mode-extra{display:flex;flex-direction:column;gap:var(--s2);padding:0 var(--s3) var(--s1)}
.join-row{display:flex;gap:var(--s2);flex-wrap:wrap}
.join-row .input{flex:1 1 130px;min-width:0}
.code-row{padding-top:var(--s1)}
#home-code{text-align:center;letter-spacing:.1em;font-weight:700;text-transform:uppercase}
.home-foot{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;padding-top:var(--s2)}

/* =========================================================================
   LOBBY
   ========================================================================= */
.lobby{flex:1;min-height:0;overflow-y:auto;padding:var(--s4) var(--s4) var(--s5)}
.lobby-inner{max-width:1120px;margin:0 auto;display:flex;flex-direction:column;gap:var(--s3)}
.lobby-grid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:var(--s3);align-items:start}
.lobby-col{display:flex;flex-direction:column;gap:var(--s3);min-width:0}
/* the city runs the full measure: it is the decision that changes the game */
.city-panel{grid-column:1 / -1}

/* a panel head can carry a reading of its own state, and the one word that
   explains why its controls are dead */
.head-side{display:flex;align-items:center;gap:var(--s2);min-width:0}
.head-side small{font-size:var(--t-xs);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.host-lock{color:var(--ink-3)}
.panel-note{padding:var(--s3);font-size:var(--t-xs);color:var(--ink-3);text-wrap:pretty}

.room-bar{
  display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s2) var(--s3);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
}
.room-code-box{line-height:1.1}
.room-code{font-size:var(--t-lg);letter-spacing:.1em;display:block}

.lobby-bar{
  flex:none;
  padding:var(--s2) var(--s4);
  background:var(--surface);border-top:1px solid var(--line);
  padding-bottom:calc(var(--s2) + env(safe-area-inset-bottom,0px));
}
/* the bar sits on the same measure as the panels above it */
.lobby-bar-inner{max-width:1120px;margin:0 auto;display:flex;align-items:center;gap:var(--s3)}
.lobby-summary{flex:1;min-width:0;display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;font-size:var(--t-sm);color:var(--ink-2)}
.lobby-summary .sep{color:var(--ink-3)}
.lobby-summary .lobby-city{font-family:var(--font-display);font-size:var(--t-md);color:var(--ink);font-weight:700}
.lobby-summary small{color:var(--ink-3);font-size:var(--t-xs);flex-basis:100%}

/* =========================================================================
   CITY — six different boards, so the picker has to say how they differ
   ========================================================================= */
.city-body{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:var(--s4);align-items:start}
.map-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--s2)}
.map-card{
  position:relative;text-align:left;
  border:1px solid var(--line);border-radius:var(--r);
  background:var(--surface-2);overflow:hidden;
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.map-card:hover:not(:disabled){border-color:var(--surface-3)}
.map-card:active:not(:disabled){transform:translateY(1px)}
.map-card:disabled{opacity:.5}
/* Six cities on one 3x2 sprite — flat vector skylines instead of 1.2 MB of
   photographs. Cells are 2:1, so the thumb declares that ratio exactly. */
.map-thumb{
  display:block;width:100%;aspect-ratio:2/1;
  background-image:url(images/maps/cities.svg);
  background-size:300% 200%;
  background-repeat:no-repeat;
}
.map-cap{
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
  gap:0 var(--s1);padding:5px var(--s2);line-height:1.25;
}
.map-card strong{display:block;font-size:var(--t-xs);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.map-card small{
  grid-column:1;display:block;font-size:var(--t-xs);color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.map-tick{grid-row:1 / span 2;grid-column:2;width:14px;height:14px;opacity:0;stroke-width:3}
.map-card[aria-pressed="true"]{border-color:var(--brand)}
.map-card[aria-pressed="true"] .map-cap{background:var(--brand);color:var(--on-accent)}
.map-card[aria-pressed="true"] small{color:var(--on-accent);opacity:.75}
.map-card[aria-pressed="true"] .map-tick{opacity:1}

/* the brief: four bars that only mean anything next to the other cities,
   then the counts that shape the board. Every figure is read off the map. */
.city-brief{border-left:1px solid var(--line-soft);padding-left:var(--s4);display:flex;flex-direction:column;gap:var(--s3)}
.city-character{color:var(--ink-2);font-size:var(--t-sm)}
.city-meters{display:flex;flex-direction:column;gap:6px}
.meter{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:baseline;gap:0 var(--s2)}
.meter-label{font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.03em;text-transform:uppercase;font-weight:700}
.meter-val{font-size:var(--t-sm);color:var(--ink);text-align:right}
.meter-track{
  grid-column:1 / -1;height:4px;border-radius:var(--r-pill);
  background:var(--surface-3);overflow:hidden;margin-top:3px;
}
.meter-fill{display:block;height:100%;background:var(--brand);border-radius:var(--r-pill)}
/* in contrast the track colour collapses into the panel, so it needs an edge */
body.contrast .meter-track{outline:1px solid var(--line);outline-offset:-1px}
.meter-note{margin-top:2px}
.city-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(92px,1fr));gap:var(--s2) var(--s3)}
.city-fact{line-height:1.25;min-width:0}
.city-fact small{display:block;font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.03em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.city-fact strong{display:block;font-size:var(--t-md);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.city-fact span{display:block;font-size:var(--t-xs);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* =========================================================================
   SEATS
   ========================================================================= */
.seat-list{display:flex;flex-direction:column}
.seat{
  display:grid;grid-template-columns:3px auto minmax(0,1fr) auto auto;
  align-items:center;gap:var(--s2);
  padding:5px 0;
}
.seat + .seat{border-top:1px solid var(--line-soft)}
.seat .seat-name{background:transparent;border:0;height:30px;font-weight:600;width:100%;min-width:0;padding:0;font-size:var(--t-sm);border-bottom:1px solid transparent}
.seat .seat-name:focus{outline:none;border-bottom-color:var(--brand)}
.seat .seat-name[readonly]{color:var(--ink-2)}
.seat select.input{height:30px;width:auto;min-width:92px;font-size:var(--t-xs)}
.seat-actions{display:flex;align-items:center;justify-content:flex-end;gap:6px;min-width:30px}
/* the token colour is the seat's own mark, so it rides the row edge */
.seat-color{width:3px;align-self:stretch;min-height:26px;border-radius:var(--r-pill);background:var(--seat-color,var(--surface-3))}
.seat-spacer{display:block;width:30px;height:1px}
.seat.is-you .seat-name{color:var(--brand)}
.seat-toggles{display:flex;flex-wrap:wrap;gap:var(--s1);padding-top:var(--s2);border-top:1px solid var(--line-soft);margin-top:var(--s2)}
.seats-panel .panel-body > .hint{margin-top:var(--s2)}

/* Eight abstract tokens on one 4x2 sprite, addressed by background-position.
   They are shapes rather than faces: identity survives the colour-blind
   filters and never competes with the player colour drawn on the board. */
.avatar{
  width:28px;height:28px;flex:none;border-radius:var(--r-sm);
  background-image:url(images/avatars/tokens.svg);
  background-size:400% 200%;
  background-color:var(--surface-3);
  border:1px solid var(--line);
}
.avatar-lg{width:38px;height:38px;border-radius:var(--r)}
.avatar-sm{width:20px;height:20px;border-radius:3px}
button.avatar{transition:border-color var(--dur) var(--ease)}
button.avatar:hover:not(:disabled){border-color:var(--info)}

/* teams */
.team-count-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:2px var(--s2)}
.team-count-row .team-limit{grid-column:1 / -1;margin:0}
.team-list{display:flex;flex-direction:column}
.team-row{display:grid;grid-template-columns:3px minmax(0,1fr) auto;align-items:center;gap:var(--s2);padding:5px 0}
.team-row + .team-row{border-top:1px solid var(--line-soft)}
.team-swatch{width:3px;align-self:stretch;min-height:26px;border-radius:var(--r-pill)}
.team-row .seat-name{background:transparent;border:0;height:24px;font-weight:600;width:100%;padding:0;font-size:var(--t-sm)}
.team-members{display:block;font-size:var(--t-xs);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.label-2{font-size:var(--t-sm);font-weight:600}

/* =========================================================================
   HOUSE RULES — five groups, each closed on a line that reads its own state
   ========================================================================= */
.rules-list{display:flex;flex-direction:column}
.rule-group + .rule-group{border-top:1px solid var(--line-soft)}
.rule-sum{
  display:grid;grid-template-columns:minmax(0,auto) minmax(0,1fr) 16px;
  align-items:center;gap:var(--s2);
  padding:var(--s3) 0;cursor:pointer;list-style:none;
}
.rule-sum::-webkit-details-marker{display:none}
.rule-sum:hover .rule-name{color:var(--brand)}
.rule-sum:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:var(--r-sm)}
.rule-name{font-size:var(--t-sm);font-weight:700}
.rule-state{font-size:var(--t-xs);color:var(--ink-3);text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rule-caret{width:16px;height:16px;color:var(--ink-3)}
.rule-group[open] .rule-caret{transform:rotate(90deg)}
.rule-group[open] .rule-sum{padding-bottom:var(--s1)}
.rule-group[open] .rule-name{color:var(--ink)}
.rule-body{padding-bottom:var(--s2)}
.rule-body > * + *{border-top:1px solid var(--line-soft)}
.rule-body .setting-row,.rule-body .switch{padding:var(--s2) 0}

/* =========================================================================
   TOUCH — the lobby packs more controls into a row than any other screen,
   and its own rules out-specify the shared coarse block, so it has to raise
   its own targets to the same 44px.
   ========================================================================= */
@media (pointer:coarse){
  .seat .avatar{width:44px;height:44px;border-radius:var(--r)}
  .seat .seat-name{height:44px}
  .seat select.input{height:44px;min-width:104px}
  .seat-actions{min-width:44px}
  .seat-spacer{width:44px}
  .seat-color{min-height:44px}
  .team-row .seat-name{height:44px}
  .team-swatch{min-height:44px}
  .switch-bare{min-height:44px;align-items:center}
  .rule-sum{min-height:44px}
  /* a summary line is a target: give the caret room and the row a floor */
  .rule-group[open] .rule-sum{padding-bottom:var(--s2)}
  /* the narrow-topbar padding squeezes "Back" to 41px wide in here */
  #screen-lobby .topbar .btn-sm{min-width:44px}
}

/* =========================================================================
   GAME SHELL — the board is the hero; the rails stay quiet
   ========================================================================= */
.match-meta{display:flex;flex-direction:column;line-height:1.2;min-width:0}
.match-meta strong{font-family:var(--font-display);font-size:var(--t-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.match-meta small{color:var(--ink-3);font-size:var(--t-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.timer{
  display:inline-flex;align-items:center;gap:5px;
  padding:0 var(--s2);height:28px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  color:var(--ink-2);
}
.timer .num,.timer b{font-size:var(--t-sm);font-weight:700;color:var(--ink);min-width:16px;text-align:right}
.timer.low{border-color:var(--danger);color:var(--danger)}
.timer.low .num,.timer.low b{color:var(--danger)}

.game-body{
  flex:1;min-height:0;
  display:grid;
  grid-template-columns:var(--side) minmax(0,1fr) var(--rail);
  gap:var(--s3);
  padding:var(--s3);
  align-items:stretch;
}
.col{min-height:0;display:flex;flex-direction:column;gap:var(--s3)}
.col-side{min-width:0}
.players-panel{display:flex;flex-direction:column;min-height:0;flex:none}
.feed-panel{display:flex;flex-direction:column;min-height:0;flex:1}
.control-panel{display:flex;flex-direction:column;min-height:0;flex:1;overflow:hidden}

/* ---- players ------------------------------------------------------------ */
.roster{display:flex;flex-direction:column;overflow-y:auto;min-height:0}
.roster-item{
  position:relative;
  display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--s2);
  width:100%;text-align:left;
  padding:7px var(--s3) 7px calc(var(--s3) - 3px);
  border-left:3px solid transparent;
  transition:background var(--dur) var(--ease);
}
.roster-item + .roster-item{border-top:1px solid var(--line-soft)}
.roster-item:hover{background:var(--surface-2)}
.roster-item.is-turn{background:var(--surface-2);border-left-color:var(--pc)}
.roster-item.is-out{opacity:.4}
.roster-token{position:relative;flex:none}
.roster-token::after{
  content:"";position:absolute;inset:auto -2px -2px auto;
  width:9px;height:9px;border-radius:50%;
  background:var(--pc);border:2px solid var(--surface);
}
.roster-item.is-turn .roster-token::after{border-color:var(--surface-2)}
.roster-name{display:flex;flex-direction:column;line-height:1.25;min-width:0}
.roster-name strong{font-size:var(--t-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}
.roster-name small{color:var(--ink-3);font-size:var(--t-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.roster-cash{text-align:right;line-height:1.25;flex:none}
.roster-cash strong{display:block;font-family:var(--font-display);font-size:var(--t-sm);font-variant-numeric:tabular-nums}
.roster-cash small{color:var(--ink-3);font-size:var(--t-xs);display:flex;align-items:center;gap:4px;justify-content:flex-end}
.you-chip{
  display:inline-block;margin-left:5px;padding:0 4px;border-radius:3px;
  font-size:9px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  background:var(--surface-3);color:var(--ink-2);vertical-align:1px;
}
.bot-chip{font-size:var(--t-xs);font-weight:400;color:var(--ink-3);margin-left:4px}
.team-chip{
  display:inline-block;padding:0 5px;border-radius:3px;
  font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  /* --ti is computed per team colour: gold and pale blue need dark ink, deep
     red and violet need light, and a fixed choice fails half of them */
  background:var(--tc);color:var(--ti,var(--on-accent));
}
.roster-ping{font-size:9px;font-weight:700;letter-spacing:.02em;color:var(--ink-3)}
.roster-ping.has{color:var(--info)}
body[data-ping="off"] .roster-ping{display:none}

.team-standings{display:flex;flex-direction:column}
.team-standings .row-between{padding:6px var(--s3);font-size:var(--t-sm)}
.team-standings .row-between + .row-between{border-top:1px solid var(--line-soft)}

/* ---- match feed --------------------------------------------------------- */
.feed{display:flex;flex-direction:column;overflow-y:auto;min-height:0;flex:1;padding:var(--s2) var(--s3)}
.feed p{font-size:var(--t-sm);color:var(--ink-2);padding:3px 0;text-wrap:pretty;line-height:1.35}
/* 'info' is the engine's most common log kind and had no rule at all, so
   most of the feed fell through to the base colour by accident. */
.feed p.k-info{color:var(--ink-2)}
.feed p.k-buy{color:var(--positive)}
.feed p.k-danger,.feed p.k-sell{color:var(--danger)}
.feed p.k-money,.feed p.k-build{color:var(--gold)}
.feed p.k-trade,.feed p.k-card,.feed p.k-system{color:var(--info)}
.feed p.k-win{color:var(--gold);font-weight:700}
.feed p.k-turn{
  color:var(--ink-3);font-size:var(--t-xs);letter-spacing:.08em;text-transform:uppercase;
  display:flex;align-items:center;gap:var(--s2);margin:var(--s1) 0;
}
.feed p.k-turn::before,.feed p.k-turn::after{content:"";flex:1;height:1px;background:var(--line-soft)}

/* =========================================================================
   BOARD
   The board sizes itself off whichever of its container's dimensions is
   smaller, so it is square at every window size instead of stretching.
   ========================================================================= */
.board-wrap{
  position:relative;
  flex:1;min-height:0;
  display:grid;place-items:center;
  container-type:size;
}
.board{
  position:relative;
  aspect-ratio:1;
  height:100%;max-width:100%;             /* fallback for no container queries */
  width:min(100cqw,100cqh);height:min(100cqw,100cqh);
  container-type:size;
  display:grid;
  grid-template-columns:repeat(10,1fr);
  grid-template-rows:repeat(10,1fr);
  gap:2px;
  padding:6px;
  /* the board is an object on a table, and each city has its own */
  background:var(--felt);
  border:1px solid var(--rim);
  border-radius:var(--r-xl);
  box-shadow:var(--e2);
}

.tile{
  position:relative;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:1px;
  padding:3px 2px;
  background:var(--tile);
  border:1px solid transparent;
  border-radius:5px;
  overflow:hidden;
  text-align:center;
  transition:background var(--dur) var(--ease);
}
button.tile{cursor:pointer;width:100%;height:100%}
button.tile:hover{background:var(--tile-2)}

/* The set band always faces the middle of the board and the ownership bar
   always sits on the outer rim, so a glance around the edge reads correctly
   from every side. */
.tile-band{position:absolute;background:var(--sc,var(--surface-3))}
.tile.bottom .tile-band{inset:0 0 auto 0;height:12%;min-height:6px}
.tile.top    .tile-band{inset:auto 0 0 0;height:12%;min-height:6px}
.tile.left   .tile-band{inset:0 0 0 auto;width:12%;min-width:6px}
.tile.right  .tile-band{inset:0 auto 0 0;width:12%;min-width:6px}
.tile.bottom{padding-top:calc(12% + 3px)}
.tile.top{padding-bottom:calc(12% + 3px)}
.tile.left{padding-right:calc(12% + 3px)}
.tile.right{padding-left:calc(12% + 3px)}

.tile-name{
  font-size:clamp(6px,1.25cqw,10px);
  font-weight:700;line-height:1.05;letter-spacing:-.01em;
  text-transform:uppercase;color:var(--tile-ink);
  max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  flex:none;
}
.tile-price{
  font-family:var(--font-display);font-size:clamp(6px,1.1cqw,9px);
  font-variant-numeric:tabular-nums;color:var(--tile-sub);flex:none;
}
.tile-icon{font-size:clamp(9px,2cqw,17px);line-height:1;color:var(--tile-sub);flex:none}
.tile.corner{background:var(--tile-2)}
.tile.corner .tile-name{font-size:clamp(6px,1.35cqw,11px);color:var(--ink)}
.tile.corner .tile-icon{font-size:clamp(11px,2.6cqw,22px)}

/* Ownership reads twice: a solid bar on the outer rim, and a wash of the
   owner's colour across the whole face. The bar alone was too small to
   attribute at phone sizes — this is the same information at a glance. */
.tile.is-owned{background:color-mix(in srgb,var(--oc) 13%,var(--tile))}
.tile.is-owned.is-here{background:color-mix(in srgb,var(--oc) 20%,var(--tile-2))}
button.tile.is-owned:hover{background:color-mix(in srgb,var(--oc) 20%,var(--tile-2))}

.tile-owner{position:absolute;background:var(--oc)}
.tile.bottom .tile-owner,.tile.corner .tile-owner{inset:auto 0 0 0;height:4px}
.tile.top    .tile-owner{inset:0 0 auto 0;height:4px}
.tile.left   .tile-owner{inset:0 auto 0 0;width:4px}
.tile.right  .tile-owner{inset:0 0 0 auto;width:4px}

.tile-mortgaged::after{
  content:"MTG";
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) rotate(-16deg);
  font-size:clamp(5px,1.05cqw,8px);font-weight:700;letter-spacing:.06em;
  color:var(--danger);border:1px solid var(--danger);
  border-radius:2px;padding:0 3px;background:var(--surface);
}
.tile-build{display:flex;gap:1px;align-items:center;justify-content:center;min-height:5px}
.tile-house{width:4px;height:6px;border-radius:1px;background:var(--positive)}
.tile-hotel{width:11px;height:6px;border-radius:1px;background:var(--gold)}

/* The current player stands here. This used to be the same value as :hover,
   so the square you were pointing at looked exactly like the square someone
   was standing on. It now reads as a lit tile rather than a hovered one. */
.tile.is-here{background:var(--tile-2);box-shadow:inset 0 0 0 1px var(--city-accent)}
.tile.is-here .tile-name{color:var(--ink)}
/* the one district you are inspecting — the only outline on the board */
.tile.is-selected{border-color:var(--info);box-shadow:inset 0 0 0 1px var(--info)}

/* ---- pawns --------------------------------------------------------------
   Tokens live in one absolutely-positioned layer above the grid rather than
   inside each tile. Moving a pawn is then a single transform, so a token can
   walk the board without the board being rebuilt underneath it.
   ------------------------------------------------------------------------ */
.pawn-layer{position:absolute;inset:0;pointer-events:none;z-index:2}
.pawn{
  position:absolute;top:0;left:0;
  border-radius:50%;
  background:var(--pc);
  border:1.5px solid var(--surface);
  will-change:transform;
}
.pawn.ready{transition:opacity 220ms var(--ease),box-shadow var(--dur) var(--ease)}
/* A transform transition is only ever wanted while a token is walking the
   perimeter. Left on permanently it also animated teleports, cancels and
   resizes — which drew the token diagonally across the middle of the board. */
.pawn-layer.walking .pawn.ready{transition:transform var(--step,120ms) linear,opacity 220ms var(--ease)}
.pawn.is-turn{border-color:var(--ink);z-index:3}
/* the piece actually in motion: lifted clear of the pile it is crossing */
.pawn.is-travelling{
  z-index:5;
  border-color:var(--ink);
  box-shadow:0 0 0 2px var(--bg),0 3px 6px rgba(0,0,0,.5);
}
.pawn.is-jailed{border-radius:3px}
.pawn.is-out{opacity:0}
/* teleport: the token leaves the board rather than sliding across it */
.pawn.is-lifting{animation:pawn-lift 260ms var(--ease) forwards}
.pawn.landed{animation:pawn-land 380ms var(--ease)}
@keyframes pawn-lift{
  0%{opacity:1;filter:none}
  100%{opacity:0;filter:brightness(1.6)}
}
@keyframes pawn-land{
  0%{opacity:0;box-shadow:0 0 0 7px color-mix(in srgb,var(--pc) 55%,transparent)}
  35%{opacity:1}
  100%{opacity:1;box-shadow:0 0 0 0 transparent}
}

/* ---- board centre -------------------------------------------------------
   Whose turn it is, what they are expected to do, and the dice. Nothing that
   is already legible somewhere else on screen.
   ------------------------------------------------------------------------ */
.board-center{
  grid-area:2/2/10/10;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:5cqw;
  padding:4cqw;
  background:var(--centre);
  border-radius:var(--r-lg);
  overflow:hidden;
  text-align:center;
}
.center-status{display:flex;align-items:center;gap:var(--s3);min-width:0;max-width:100%}
.center-status .avatar{width:clamp(30px,6.4cqw,56px);height:clamp(30px,6.4cqw,56px);border-radius:var(--r)}
.center-status .copy{min-width:0;text-align:left;line-height:1.25}
.center-status small{
  display:block;font-size:clamp(8px,1.55cqw,13px);letter-spacing:.11em;
  text-transform:uppercase;color:var(--ink-3);font-weight:700;
}
.center-status strong{
  display:block;font-size:clamp(12px,2.8cqw,24px);font-weight:600;
  text-wrap:balance;line-height:1.2;
}
.center-status.is-you small{color:var(--positive)}

.center-dice{display:flex;align-items:center;gap:var(--s3)}
.dice{display:flex;gap:var(--s2)}
.die{
  width:clamp(28px,7cqw,60px);height:clamp(28px,7cqw,60px);flex:none;
  display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);
  gap:2px;padding:13%;
  background:var(--surface-2);
  border:1px solid var(--line);
  border-radius:var(--r);
}
.die i{border-radius:50%;background:transparent}
.die i.on{background:var(--ink)}
.dice-total{line-height:1.1;text-align:left}
.dice-total strong{display:block;font-family:var(--font-display);font-size:clamp(15px,4cqw,34px);font-variant-numeric:tabular-nums}
.dice-total small{display:block;font-size:clamp(8px,1.45cqw,12px);color:var(--ink-3);letter-spacing:.08em;text-transform:uppercase}
.dice-total.is-idle strong{color:var(--ink-3)}
@keyframes shake{
  0%{transform:translateY(0) rotate(0)}
  25%{transform:translateY(-5px) rotate(-8deg)}
  50%{transform:translateY(0) rotate(6deg)}
  75%{transform:translateY(-3px) rotate(-4deg)}
  100%{transform:translateY(0) rotate(0)}
}
.die.rolling{animation:shake 380ms var(--ease) infinite}
body[data-dice="fast"] .die.rolling{animation-duration:220ms}
body[data-dice="slow"] .die.rolling{animation-duration:520ms}

/* the move the game is waiting for, in the middle of the board */
.center-action{width:min(78%,300px)}
.center-action .btn{
  height:clamp(38px,6.4cqw,54px);
  font-size:clamp(12px,2.1cqw,17px);
  border-radius:var(--r-lg);
  box-shadow:var(--e2);
}
/* the rail keeps a copy for widths with no room for a board centre */
.act-primary{display:none}

.center-note{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;justify-content:center}
.pot{
  display:inline-flex;align-items:baseline;gap:6px;
  padding:3px 9px;border-radius:var(--r-pill);
  background:var(--surface);border:1px solid color-mix(in srgb,var(--gold) 40%,transparent);
}
.pot small{font-size:clamp(8px,1.4cqw,13px);color:var(--ink-3);letter-spacing:.06em;text-transform:uppercase}
.pot strong{font-family:var(--font-display);font-size:clamp(11px,2.2cqw,18px);color:var(--gold);font-variant-numeric:tabular-nums}
.bank-note{font-size:clamp(8px,1.4cqw,13px);color:var(--ink-3)}

/* a tiny board hides the words and keeps the dice */
@container (max-width:340px){
  .center-status .copy{display:none}
  .center-note{display:none}
  .center-action{display:none}
}

/* ---- set control strip --------------------------------------------------
   Replaces the old legend: it teaches the colour code *and* answers "who has
   locked up which set", which is the whole strategy of the game.
   ------------------------------------------------------------------------ */
.set-strip{display:flex;flex-wrap:wrap;gap:var(--s1);flex:none;padding-top:var(--s1)}
.set-pill{
  display:inline-flex;align-items:center;gap:5px;min-width:0;flex:1 1 auto;
  padding:3px 7px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  font-size:var(--t-xs);
}
.set-pill i{width:7px;height:7px;border-radius:2px;flex:none}
.set-pill span{color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.set-pill b{color:var(--ink-2);font-family:var(--font-display);font-variant-numeric:tabular-nums;margin-left:auto;max-width:70px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.set-pill.is-owned{border-color:color-mix(in srgb,var(--gold) 50%,transparent)}
.set-pill.is-owned b{color:var(--gold)}

/* =========================================================================
   CONTROL RAIL — flat sections, one primary action, never a card in a card
   ========================================================================= */
.tabs{display:flex;gap:2px;padding:var(--s2);border-bottom:1px solid var(--line-soft);flex:none}
.tab{
  flex:1;height:30px;border-radius:var(--r-sm);
  display:flex;align-items:center;justify-content:center;gap:5px;
  font-size:var(--t-sm);font-weight:600;color:var(--ink-3);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
  position:relative;
}
.tab:hover{color:var(--ink)}
.tab[aria-selected="true"]{background:var(--surface-2);color:var(--ink)}
.tab .badge{
  min-width:15px;height:15px;padding:0 4px;border-radius:var(--r-pill);
  background:var(--danger);color:var(--on-accent);
  font-size:9px;font-weight:700;line-height:15px;text-align:center;
}
.tab-panel{display:none;flex-direction:column;overflow-y:auto;min-height:0;flex:1}
.tab-panel.active{display:flex}

/* a flat section inside the rail */
.sec{padding:var(--s3);border-bottom:1px solid var(--line-soft)}
.sec:last-child{border-bottom:0}
.sec-pad{padding:var(--s3)}

/* whose turn it is + your wallet, always at the top, never scrolled away */
.turnbar{
  display:flex;align-items:center;gap:var(--s2);
  padding:var(--s3);
  border-bottom:1px solid var(--line-soft);
  border-left:3px solid var(--pc,transparent);
  flex:none;
}
.turnbar .copy{min-width:0;flex:1;line-height:1.2}
.turnbar small{display:block;font-size:var(--t-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:700}
.turnbar strong{display:block;font-size:var(--t-md);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.turnbar.is-you small{color:var(--positive)}
.wallet{text-align:right;line-height:1.15;flex:none}
.wallet b{display:block;font-family:var(--font-display);font-size:var(--t-lg);font-variant-numeric:tabular-nums}
.wallet small{display:block;font-size:var(--t-xs);color:var(--ink-3);letter-spacing:0;text-transform:none;font-weight:400}

/* the district you are looking at, and what you can do about it */
.inspect{display:flex;flex-direction:column;gap:var(--s3);padding:var(--s3);border-bottom:1px solid var(--line-soft)}
.inspect-head{display:flex;align-items:stretch;gap:var(--s2)}
.inspect-swatch{width:4px;border-radius:2px;background:var(--sc,var(--surface-3));flex:none}
.inspect-title{min-width:0;flex:1;line-height:1.25}
.inspect-title strong{display:block;font-size:var(--t-md);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inspect-title small{display:block;font-size:var(--t-xs);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inspect-eyebrow{font-size:var(--t-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:700}

/* flat facts divided by hairlines — never a grid of little boxes */
.facts{display:flex;gap:0}
.fact{flex:1 1 0;min-width:0;line-height:1.2;padding:0 var(--s2)}
.fact:first-child{padding-left:0}
.fact:last-child{padding-right:0}
.fact + .fact{border-left:1px solid var(--line-soft)}
.fact small{display:block;font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.03em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fact strong{display:block;font-family:var(--font-display);font-size:var(--t-sm);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.act{display:flex;flex-direction:column;gap:var(--s2)}
.act-row{display:flex;gap:var(--s2)}
.act-row > .btn{flex:1;min-width:0}
.act-why{font-size:var(--t-xs);color:var(--ink-3);text-wrap:pretty;line-height:1.35}

/* portfolio */
.assets-tools{position:relative}
.search-box{position:relative}
.search-box .ic{position:absolute;left:var(--s2);top:50%;transform:translateY(-50%);color:var(--ink-3);pointer-events:none}
.search-box .input{padding-left:30px}
.search-results{display:flex;flex-direction:column;gap:2px;margin-top:var(--s2)}
.search-results .chip{width:100%;justify-content:flex-start}
.recent-row{display:flex;flex-wrap:wrap;gap:var(--s1);margin-top:var(--s2)}

.set-group + .set-group{margin-top:var(--s3)}
.set-group-head{
  display:flex;align-items:center;gap:6px;
  font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.06em;text-transform:uppercase;font-weight:700;
  padding-bottom:4px;border-bottom:1px solid var(--line-soft);margin-bottom:2px;
}
.set-group-head i{width:8px;height:8px;border-radius:2px;background:var(--sc);flex:none}
.holding{
  display:grid;grid-template-columns:4px 1fr auto;align-items:center;gap:var(--s2);
  width:100%;text-align:left;
  padding:6px 0;
  transition:background var(--dur) var(--ease);
}
.holding + .holding{border-top:1px solid var(--line-soft)}
.holding:hover{background:var(--surface-2)}
.holding .swatch{width:4px;height:24px;border-radius:2px;background:var(--sc,var(--surface-3))}
.holding .copy{min-width:0;line-height:1.25}
.holding strong{display:block;font-size:var(--t-sm);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.holding small{font-size:var(--t-xs);color:var(--ink-3)}
.holding .num{font-size:var(--t-sm);color:var(--ink-3)}

/* trade offers */
.offer{display:flex;flex-direction:column;gap:5px;padding:var(--s3) 0}
.offer + .offer{border-top:1px solid var(--line-soft)}
.offer-line{font-size:var(--t-sm);color:var(--ink-3)}
.offer-line b{color:var(--ink-2);font-weight:600}

/* chat */
.chat-log{display:flex;flex-direction:column;gap:var(--s2);overflow-y:auto;flex:1;min-height:0;padding:var(--s3)}
.chat-msg{display:flex;gap:var(--s2);align-items:flex-start}
.chat-msg .copy{min-width:0}
.chat-msg strong{display:block;font-size:var(--t-xs);color:var(--ink-3)}
.chat-msg p{font-size:var(--t-sm);word-break:break-word;color:var(--ink-2)}
.chat-compose{flex:none;padding:var(--s2) var(--s3) var(--s3);border-top:1px solid var(--line-soft);display:flex;flex-direction:column;gap:var(--s2)}
.chat-form{display:flex;gap:var(--s2)}
.emote-row{display:flex;gap:var(--s1);flex-wrap:wrap}
.emote{
  width:30px;height:30px;border-radius:var(--r-sm);
  background:var(--surface-2);border:1px solid var(--line);
  font-size:15px;line-height:1;
  display:grid;place-items:center;
  transition:background var(--dur) var(--ease);
}
.emote:hover{background:var(--surface-3)}
.emote:active{transform:translateY(1px)}

/* chips */
.chip{
  display:inline-flex;align-items:center;gap:5px;
  height:28px;padding:0 var(--s3);
  border-radius:var(--r-pill);
  background:var(--surface-2);border:1px solid var(--line);
  font-size:var(--t-xs);font-weight:600;color:var(--ink-2);
  max-width:100%;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.chip > span,.chip > small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chip:hover:not(:disabled){background:var(--surface-3)}
.chip:active:not(:disabled){transform:translateY(1px)}
.chip:disabled{opacity:.35}
.chip i{width:7px;height:7px;border-radius:2px;background:var(--sc,var(--surface-3));flex:none}
.chip[aria-pressed="true"]{background:var(--info);border-color:transparent;color:var(--on-accent)}
.chip[aria-pressed="true"] i{background:var(--on-accent);opacity:.6}
.chip-grid{display:flex;flex-wrap:wrap;gap:var(--s1);max-height:150px;overflow-y:auto}

/* =========================================================================
   MODALS — small and direct. Everything inside is flat.
   ========================================================================= */
dialog.modal{
  padding:0;border:0;background:transparent;
  max-width:min(100vw - 24px,var(--mw,520px));
  width:100%;
  max-height:calc(100dvh - 32px);
  color:var(--ink);
  overflow:visible;
}
dialog.modal::backdrop{background:rgba(6,8,12,.7)}
.modal-card{
  position:relative;
  display:flex;flex-direction:column;
  max-height:calc(100dvh - 32px);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--r-xl);
  box-shadow:var(--e3);
  overflow:hidden;
}
.modal-card:focus{outline:none}
/* the one place a set colour is allowed outside the board */
.modal-accent{display:block;height:3px;background:var(--sc,var(--info));flex:none}
.modal-accent-danger{background:var(--danger)}
.modal-accent-gold{background:var(--gold)}
.modal-head{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s3);
  border-bottom:1px solid var(--line-soft);
  flex:none;
}
.modal-head h2{font-family:var(--font-display);font-size:var(--t-lg);font-weight:700;line-height:1.2}
.modal-head small{display:block;font-size:var(--t-xs);color:var(--ink-3);text-wrap:pretty}
.modal-body{padding:var(--s3);overflow-y:auto;min-height:0;display:flex;flex-direction:column;gap:var(--s3)}
.modal-body > p{font-size:var(--t-sm);color:var(--ink-2);text-wrap:pretty}
.modal-foot{
  display:flex;align-items:center;justify-content:flex-end;gap:var(--s2);flex-wrap:wrap;
  padding:var(--s3);
  border-top:1px solid var(--line-soft);
  flex:none;
}
.modal-foot .grow{flex:1;font-size:var(--t-sm)}
@media (prefers-reduced-motion:no-preference){
  dialog.modal[open]{animation:modal-in 180ms var(--ease)}
}
@keyframes modal-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ---- title deed --------------------------------------------------------- */
.rent-table{width:100%;border-collapse:collapse;font-size:var(--t-sm)}
.rent-table th{
  text-align:left;font-size:var(--t-xs);letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3);font-weight:700;padding:0 0 5px;
}
.rent-table td{padding:5px 0;border-top:1px solid var(--line-soft);color:var(--ink-2)}
.rent-table td:last-child{text-align:right;font-family:var(--font-display);font-variant-numeric:tabular-nums}
.rent-table tr.active td{color:var(--ink);font-weight:700}
.rent-table tr.active td:first-child{position:relative;padding-left:9px}
.rent-table tr.active td:first-child::before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:2px;border-radius:2px;background:var(--info)}
.rent-table tr.hotel td:first-child{color:var(--gold)}

.set-strip-list{display:flex;flex-direction:column}
.set-strip-item{
  display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--s2);
  padding:5px 0;font-size:var(--t-sm);color:var(--ink-2);width:100%;text-align:left;
}
.set-strip-item + .set-strip-item{border-top:1px solid var(--line-soft)}
.set-strip-item.is-this{color:var(--ink);font-weight:600}
.set-strip-item span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
button.set-strip-item:hover{background:var(--surface-2)}
.owner-dot{width:9px;height:9px;border-radius:50%;background:var(--oc,var(--surface-3));flex:none}

/* divided facts, used in deeds, assets, debt, profile and the dossier */
.deed-stats{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(68px,1fr));
  gap:1px;background:var(--line-soft);
  border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft);
}
.deed-stat{background:var(--surface);padding:var(--s2) var(--s3);line-height:1.25;min-width:0}
.deed-stat small{display:block;font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.03em;text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.deed-stat strong{font-family:var(--font-display);font-size:var(--t-md);font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
/* inside the rail the surface is the same, so the hairlines still read */
.tab-panel .deed-stats{border-left:0;border-right:0}

/* ---- auction ------------------------------------------------------------ */
.auction-bid{display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap}
.auction-amount{font-family:var(--font-display);font-size:var(--t-2xl);color:var(--gold);line-height:1}
.auction-leader{display:inline-flex;align-items:center;gap:5px;font-size:var(--t-sm);color:var(--ink-2)}
.auction-ladder{display:flex;flex-direction:column}
.auction-row{
  display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--s2);
  padding:4px 0;font-size:var(--t-sm);color:var(--ink-3);
}
.auction-row + .auction-row{border-top:1px solid var(--line-soft)}
.auction-row.is-lead{color:var(--ink)}
.auction-row.is-lead b{color:var(--gold)}
.auction-actions{display:flex;gap:var(--s2);width:100%}
.auction-actions .input{flex:1;min-width:0}
.auction-live{
  display:flex;align-items:center;gap:var(--s2);width:100%;text-align:left;
  padding:var(--s2) var(--s3);
  background:var(--surface-2);border-left:3px solid var(--gold);border-radius:var(--r);
  font-size:var(--t-sm);
}
.auction-live .copy{flex:1;min-width:0;line-height:1.25}
.auction-live strong{display:block;font-size:var(--t-sm)}
.auction-live small{display:block;font-size:var(--t-xs);color:var(--ink-3)}

/* ---- trade builder ------------------------------------------------------ */
.trade-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3)}
.trade-side{display:flex;flex-direction:column;gap:var(--s2);min-width:0}
.trade-side-head{display:flex;align-items:center;gap:var(--s2);padding-bottom:5px;border-bottom:1px solid var(--line-soft)}
.trade-side-head strong{font-size:var(--t-sm)}
.trade-summary{
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--s3);
  padding:var(--s2) 0;border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft);
  text-align:center;
}
.trade-summary .num{font-size:var(--t-lg);display:block}
.trade-summary small{font-size:var(--t-xs);color:var(--ink-3);letter-spacing:.04em;text-transform:uppercase}
.trade-summary .ic{color:var(--ink-3);margin:0 auto}

/* ---- rules -------------------------------------------------------------- */
.rules-body{display:flex;flex-direction:column;counter-reset:step}
.rule-step{
  position:relative;
  padding:var(--s3) 0 var(--s3) 30px;
  font-size:var(--t-sm);color:var(--ink-2);text-wrap:pretty;line-height:1.5;
}
.rule-step + .rule-step{border-top:1px solid var(--line-soft)}
.rule-step b{color:var(--ink);font-weight:700}
.rule-step em{font-style:normal;color:var(--ink);font-weight:600}
.rule-step::before{
  counter-increment:step;content:counter(step);
  position:absolute;left:0;top:var(--s3);
  width:20px;height:20px;border-radius:var(--r-sm);
  background:var(--surface-2);
  display:grid;place-items:center;
  font-family:var(--font-display);font-size:var(--t-xs);font-weight:700;color:var(--info);
}

/* ---- settings ----------------------------------------------------------- */
.prefs-body{gap:var(--s4)}
.group{display:flex;flex-direction:column}
.group-head{
  font-size:var(--t-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);font-weight:700;
  padding-bottom:5px;border-bottom:1px solid var(--line-soft);margin-bottom:var(--s1);
}
.prefs-body .setting-row{grid-template-columns:1fr minmax(140px,190px)}
.slider-row{display:flex;align-items:center;gap:var(--s2)}
.slider-row .num{min-width:36px;text-align:right;font-size:var(--t-sm)}
.input.range{
  appearance:none;-webkit-appearance:none;
  height:4px;padding:0;border-radius:var(--r-pill);
  background:var(--surface-3);border:0;cursor:pointer;
}
.input.range::-webkit-slider-thumb{
  appearance:none;-webkit-appearance:none;
  width:14px;height:14px;border-radius:50%;
  background:var(--info);border:2px solid var(--surface);cursor:pointer;
}
.input.range::-moz-range-thumb{
  width:12px;height:12px;border-radius:50%;
  background:var(--info);border:2px solid var(--surface);cursor:pointer;
}

/* ---- profile + end of match --------------------------------------------- */
.profile-head{display:flex;align-items:center;gap:var(--s3)}
.profile-head strong{display:block;font-family:var(--font-display);font-size:var(--t-lg)}
.profile-head small{color:var(--ink-3);font-size:var(--t-xs)}
.badge-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--s2)}
.badge-item{display:flex;align-items:center;gap:var(--s2);min-width:0}
.badge-item > span{font-size:var(--t-lg);flex:none}
.badge-item strong{display:block;font-size:var(--t-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.badge-item small{display:block;font-size:var(--t-xs);color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.history{display:flex;flex-direction:column}
.history-row{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--s2);padding:6px 0}
.history-row + .history-row{border-top:1px solid var(--line-soft)}
.history-row .copy{min-width:0;line-height:1.25}
.history-row strong{font-size:var(--t-sm)}
.history-row small{display:block;font-size:var(--t-xs);color:var(--ink-3)}
.history-tag{
  width:20px;height:20px;border-radius:var(--r-sm);
  display:grid;place-items:center;
  font-size:var(--t-xs);font-weight:700;color:var(--ink-3);
  background:var(--surface-2);
}
.history-tag.tag-positive{color:var(--positive);background:color-mix(in srgb,var(--positive) 14%,transparent)}

.standing{display:grid;grid-template-columns:auto auto 1fr auto;align-items:center;gap:var(--s2);padding:6px 0;font-size:var(--t-sm)}
.standing + .standing{border-top:1px solid var(--line-soft)}
.standing .place{font-family:var(--font-display);color:var(--ink-3);min-width:16px}
.standing.is-winner .place,.standing.is-winner strong{color:var(--gold)}
.standing span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.stats-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);flex-wrap:wrap}
.stats-table{display:flex;flex-direction:column}
.stat-row{padding:var(--s3) 0}
.stat-row + .stat-row{border-top:1px solid var(--line-soft)}
.stat-main{display:flex;align-items:center;gap:var(--s2);margin-bottom:var(--s2)}
/* :not(.avatar) matters — the avatar is a <span> too, and flex:1 would stretch
   it into a smear across the row */
.stat-main > span:not(.avatar){min-width:0;flex:1;line-height:1.25}
.stat-main strong{font-size:var(--t-sm)}
.stat-main small{display:block;font-size:var(--t-xs);color:var(--ink-3)}
.stat-main b{font-size:var(--t-md);font-family:var(--font-display)}
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s2) var(--s3)}
.stat-cell{line-height:1.2;min-width:0}
.stat-cell small{display:block;font-size:9px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stat-cell strong{font-family:var(--font-display);font-size:var(--t-sm);font-variant-numeric:tabular-nums}
.stats-footnote{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s4);font-size:var(--t-xs);color:var(--ink-3)}

/* =========================================================================
   TOASTS
   ========================================================================= */
.toast-stack{
  position:fixed;right:var(--s3);bottom:var(--s3);
  z-index:var(--z-toast);
  display:flex;flex-direction:column;gap:6px;
  width:min(320px,calc(100vw - 24px));
  pointer-events:none;
}
.toast{
  display:flex;align-items:center;gap:var(--s2);
  padding:var(--s3);
  background:var(--surface);
  border:1px solid var(--line);
  border-left:3px solid var(--line);
  border-radius:var(--r-lg);
  box-shadow:var(--e3);
  font-size:var(--t-sm);color:var(--ink-2);
  /* Nothing in a toast is interactive, and on a phone the stack sits exactly
     where the turn button does — so an auto value meant the notification
     telling you what happened swallowed the tap that does the next thing. */
  pointer-events:none;
  text-wrap:pretty;
}
.toast-danger{border-left-color:var(--danger)}
.toast-positive{border-left-color:var(--positive)}
.toast-info{border-left-color:var(--info)}
.toast-gold{border-left-color:var(--gold)}
@media (prefers-reduced-motion:no-preference){
  .toast{animation:toast-in 180ms var(--ease)}
}
@keyframes toast-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* =========================================================================
   GAME EVENTS — the four moments that carry information
   ========================================================================= */
.tile-house.just-built,.tile-hotel.just-built{animation:build-pop 260ms var(--ease)}
@keyframes build-pop{0%{transform:scale(.2)}62%{transform:scale(1.3)}100%{transform:scale(1)}}

.event-card{
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-44%);
  width:min(300px,70%);
  padding:var(--s4);
  background:var(--surface);
  border:1px solid var(--line);
  border-top:3px solid var(--info);
  border-radius:var(--r-lg);
  box-shadow:var(--shadow-pop);
  text-align:center;
  opacity:0;pointer-events:none;z-index:5;
  transition:opacity 200ms var(--ease),transform 200ms var(--ease);
}
.event-card.in{opacity:1;transform:translate(-50%,-50%)}
.event-card-eyebrow{
  display:block;font-size:var(--t-xs);letter-spacing:.09em;text-transform:uppercase;
  color:var(--info);font-weight:700;margin-bottom:6px;
}
.event-card p{font-size:var(--t-sm);color:var(--ink);text-wrap:pretty}

.cash-delta{
  position:absolute;right:var(--s3);top:50%;
  font-family:var(--font-display);font-variant-numeric:tabular-nums;
  font-size:var(--t-xs);font-weight:700;
  pointer-events:none;
  animation:cash-float 1050ms var(--ease) forwards;
}
.cash-delta.up{color:var(--positive)}
.cash-delta.down{color:var(--danger)}
@keyframes cash-float{
  0%{opacity:0;transform:translateY(2px)}
  18%{opacity:1;transform:translateY(-2px)}
  100%{opacity:0;transform:translateY(-20px)}
}

/* behind the dialog's own content, so it celebrates without hiding the result */
.confetti{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.modal-card > .modal-head,.modal-card > .modal-body,.modal-card > .modal-foot,.modal-card > .modal-accent{position:relative;z-index:1}
.confetti i{position:absolute;top:-10px;width:6px;height:9px;border-radius:1px;animation:confetti-fall linear forwards}
@keyframes confetti-fall{
  0%{transform:translate(0,-10px) rotate(0);opacity:1}
  100%{transform:translate(var(--dx,60px),320px) rotate(var(--rot,360deg));opacity:0}
}

/* =========================================================================
   RESPONSIVE
   ========================================================================= */
@media (max-width:1240px){
  :root{--side:212px;--rail:300px}
}
/* narrow rails buy the board the width it needs before the layout stacks */
@media (max-width:1100px){
  :root{--side:190px;--rail:274px}
}

@media (max-width:1000px){
  /* Stacked. The board comes first, then the thing you do about it, then the
     rest of the table — reading order matches the order you need them in. */
  .game-body{
    grid-template-columns:minmax(0,1fr);
    grid-auto-rows:max-content;
    align-items:start;
    overflow-y:auto;
  }
  .col{min-height:auto}
  .col-board{order:1}
  .col-control{order:2}
  .col-side{order:3}
  .board-wrap{flex:none;container-type:inline-size}
  .board{width:100cqw;height:auto;aspect-ratio:1;container-type:inline-size}
  /* the middle of the board is too small to hold a button here */
  .center-action{display:none}
  /* The one control the game is waiting for must not be reachable only by
     scrolling. The tab panel stops being its own scroller so the page one
     takes over, and the primary action pins to the bottom of the viewport. */
  .tab-panel{overflow:visible}
  .act-primary{
    display:block;
    position:sticky;bottom:var(--s2);z-index:6;
  }
  .act-primary .btn{box-shadow:var(--e3)}
  /* and the toasts move out of its way — they sat directly on top of it */
  .toast-stack{top:calc(var(--nav) + var(--s2));bottom:auto;flex-direction:column-reverse}
  .control-panel{flex:none}
  .tab-panel{max-height:none}
  .players-panel,.feed-panel{flex:none}
  .feed{max-height:220px}
  .roster{max-height:none}
  .lobby-grid{grid-template-columns:minmax(0,1fr)}
  .city-panel{grid-column:auto}
  .prefs-body .setting-row{grid-template-columns:1fr}
  .stat-grid{grid-template-columns:repeat(3,1fr)}
  .skeleton{grid-template-columns:minmax(0,1fr)}
  .skeleton .sk-side{display:none}
}

@media (max-width:720px){
  /* Four destinations, a coin chip, an account button and a settings icon do
     not fit one 375px row — scrolling them was hiding half the product behind
     a gesture with no affordance. The links get their own full-width row and
     share it evenly, which is what a phone expects anyway. */
  .nav{flex-wrap:wrap;height:auto;padding:6px var(--s2)}
  .nav-links{order:5;flex:1 0 100%;overflow:visible;gap:4px;margin-top:4px}
  .nav-link{flex:1 1 0;justify-content:center;padding:0 6px}
  .nav-brand .brand-name{display:none}

  .topbar{gap:6px;padding:6px var(--s2)}
  .brand-name,.topbar-title{display:none}
  .topbar .btn-sm{padding:0 7px}
  .match-meta small{font-size:10px}
  .game-body{padding:var(--s2);gap:var(--s2)}
  .lobby{padding:var(--s3) var(--s3) var(--s4)}
  .lobby-bar{padding:var(--s2) var(--s3)}
  .home{padding:var(--s4) var(--s3)}
  .trade-grid{grid-template-columns:1fr}
  .trade-summary{grid-template-columns:1fr;gap:var(--s2)}
  .modal-body,.modal-head,.modal-foot{padding:var(--s3)}
  .modal-foot .btn{flex:1}
  /* one scrollable line beats three stacked rows of pills */
  .set-strip{flex-wrap:nowrap;overflow-x:auto;padding-bottom:var(--s1)}
  .set-pill{flex:0 0 auto}
  /* the brief drops under the cards it describes */
  .city-body{grid-template-columns:minmax(0,1fr);gap:var(--s3)}
  .city-brief{border-left:0;padding-left:0;border-top:1px solid var(--line-soft);padding-top:var(--s3)}
  /* two lines per seat: who they are, then what they are */
  .seat{
    grid-template-columns:3px auto minmax(0,1fr) auto;
    grid-template-areas:"r a b d" "r a c d";row-gap:4px;
  }
  .seat .seat-color{grid-area:r}
  .seat .avatar{grid-area:a}
  .seat .seat-name{grid-area:b}
  .seat select.input{grid-area:c;width:100%}
  .seat .seat-actions{grid-area:d}
  .lobby-bar-inner{gap:var(--s2)}
  /* the city takes the first line rather than dangling a separator */
  .lobby-summary{row-gap:0}
  .lobby-summary .lobby-city{flex-basis:100%;font-size:var(--t-sm)}
  .lobby-summary .sep:first-of-type{display:none}
  /* the state of a closed group drops under its name rather than squeezing */
  .rule-sum{grid-template-columns:minmax(0,1fr) 16px;row-gap:1px}
  .rule-state{grid-column:1;text-align:left}
  .rule-caret{grid-row:1 / span 2;grid-column:2}
  .toast-stack{left:var(--s2);right:var(--s2);width:auto}
  .stat-grid{grid-template-columns:repeat(2,1fr)}
}

/* Under ~420px a tile is barely 34px across; no legible size fits a name like
   "Verdant". The board becomes a positional map — set colour, owner,
   buildings and tokens still read, corners keep their landmark labels, and
   tapping any tile opens its full card. Names stay in title/aria-label. */
@media (max-width:420px){
  .tile-price{display:none}
  .tile:not(.corner) .tile-name{display:none}
}

/* Landscape phones are short, not narrow: keep the rail beside the board. */
/* Landscape phones are short, not narrow. The board is height-bound here, so
   it only wants ~330px of an 844px viewport — the old branch spent the other
   500px on nothing and hid the players list and the feed to do it, which left
   no way to see anyone's cash or inspect a rival at all. Three columns fit. */
@media (max-height:560px) and (orientation:landscape){
  .topbar{padding:4px var(--s2)}
  .game-body{
    grid-template-columns:minmax(150px,190px) minmax(0,1fr) minmax(240px,280px);
    grid-auto-rows:auto;overflow:hidden;align-items:stretch;
    gap:var(--s2);padding:var(--s2);
  }
  .col-side{order:1;min-height:0;display:flex}
  .col-board{order:2;min-height:0}
  .col-control{order:3;min-height:0}
  .players-panel{flex:0 1 auto;min-height:0}
  .feed-panel{flex:1 1 auto;min-height:0}
  .control-panel{flex:1}
  .board-wrap{flex:1;container-type:size}
  .board{width:min(100cqw,100cqh);height:min(100cqw,100cqh);container-type:size}
  .center-action{display:block}
  .act-primary{display:none}
  /* the strip is the one thing that genuinely has no room in 390px of height */
  .set-strip{display:none}
}
/* Below this there is not enough width for three, so the players list rejoins
   the rail rather than vanishing. */
@media (max-height:560px) and (orientation:landscape) and (max-width:700px){
  .game-body{grid-template-columns:minmax(0,1fr) minmax(230px,270px)}
  .col-side{display:none}
}

/* =========================================================================
   TOUCH — 44px is the smallest target that is reliably hittable
   ========================================================================= */
@media (pointer:coarse){
  /* This block was headed "44px is the smallest target that is reliably
     hittable" and then set everything to 32-42. Every number below now
     actually reaches 44, and the controls that were never in here at all —
     the nav, the text links, the chips — are in. */
  .btn{height:44px;padding:0 var(--s4)}
  .btn-sm{height:44px;padding:0 var(--s3)}
  .btn-lg{height:52px}
  .btn-icon{width:44px}
  .btn-icon.btn-sm{width:44px}
  .tab{height:44px}
  .input,select.input{height:44px}
  .setting-row .input{height:44px}
  .emote{width:44px;height:44px;font-size:19px}
  .chip{height:44px;padding:0 var(--s3)}
  /* text-only actions were the worst on the site at ~20px tall */
  .linkish{min-height:44px;display:inline-flex;align-items:center}
  .nav-link{height:44px}
  .nav-account,.coin-chip{height:44px}
  .nav-brand{min-height:44px}
  .nav{height:auto;min-height:56px;padding-block:4px}
  .switch{padding:var(--s3) 0}
  .switch .track{width:44px;height:24px}
  .switch .track::after{width:18px;height:18px}
  .switch input:checked + .track::after{transform:translateX(20px)}
  .roster-item{padding:var(--s3) var(--s3) var(--s3) calc(var(--s3) - 3px)}
  .toast-stack{bottom:calc(var(--s3) + env(safe-area-inset-bottom,0px))}
}

/* =========================================================================
   THEMES — LIGHT
   Same four accents, same contrast contract.
   ========================================================================= */
body.theme-light{
  --bg:#eef1f7;
  --surface:#ffffff;
  --surface-2:#eaeef5;
  --surface-3:#dbe1ec;
  --line:#ccd4e1;
  --line-soft:#e4e9f1;
  --ink:#141a26;
  --ink-2:#4a5568;
  --ink-3:#6f7b90;
  --brand:#2f62d8;
  --info:#2f62d8;
  --positive:#11844c;
  --danger:#c62431;
  --gold:#946200;
  --on-accent:#ffffff;
  --e1:0 1px 2px rgba(22,32,60,.07);
  --e2:0 2px 8px rgba(22,32,60,.10),0 1px 2px rgba(22,32,60,.06);
  --e3:0 20px 48px rgba(22,32,60,.18),0 3px 10px rgba(22,32,60,.10);
  --shadow-pop:var(--e3);
}
body.theme-light .btn-primary{background:var(--ink);color:#fff}
body.theme-light .btn-primary:hover:not(:disabled){background:#000;color:#fff}
body.theme-light .tile-mortgaged::after{background:var(--tile)}
body.theme-light .die i.on{background:var(--ink)}
/* board surfaces come from styles/cities.css, which carries its own light
   overrides per city — nothing city-specific belongs here any more */
body.theme-light dialog.modal::backdrop{background:rgba(23,29,41,.4)}

/* =========================================================================
   ACCESSIBILITY — colour-blind filters, text scale, contrast, no-anim
   ========================================================================= */
/* The dialogs and the toast stack are siblings of .app, not children — so
   filtering only .app left the deed card, the auction, the trade builder and
   every toast unfiltered, which is precisely where set colour is doing the
   most work. A filter on <dialog> would also catch ::backdrop, so each
   surface is named instead. */
body[data-cb="protanopia"] .app,
body[data-cb="protanopia"] .toast-stack,
body[data-cb="protanopia"] .modal-card{filter:url(#cb-protanopia)}
body[data-cb="deuteranopia"] .app,
body[data-cb="deuteranopia"] .toast-stack,
body[data-cb="deuteranopia"] .modal-card{filter:url(#cb-deuteranopia)}
body[data-cb="tritanopia"] .app,
body[data-cb="tritanopia"] .toast-stack,
body[data-cb="tritanopia"] .modal-card{filter:url(#cb-tritanopia)}
body.text-lg{--t-xs:12.5px;--t-sm:14.5px;--t-md:16px;--t-lg:18px;--t-xl:23px;--t-2xl:30px}
body.text-sm{--t-xs:10px;--t-sm:11.5px;--t-md:13px;--t-lg:15px;--t-xl:18px;--t-2xl:24px}

body.contrast{
  --line:var(--ink-2);
  --line-soft:var(--ink-3);
  --ink-2:var(--ink);
  --ink-3:var(--ink);
  --surface-2:var(--bg);
  --surface-3:var(--surface);
}
body.contrast .btn,body.contrast .input,body.contrast .tag,body.contrast .panel,body.contrast .tile,body.contrast .mode{border-width:2px}
body.contrast .tile{border-color:var(--line-soft)}
body.contrast :focus-visible{outline-width:3px}
body.contrast .feed p,body.contrast .empty p{color:var(--ink)}
body.contrast .pawn{border-width:2px;border-color:var(--ink)}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  .btn:active,.chip:active,.emote:active,button.tile:active,.mode:active{transform:none}
}
body.no-anim *,body.no-anim *::before,body.no-anim *::after{
  animation:none !important;
  transition:none !important;
}
body.no-anim .btn:active,body.no-anim .chip:active,body.no-anim .emote:active,body.no-anim .mode:active{transform:none}
