/* style.css — Mojo Dojo Ranking. Black + fire, gold rows, heavy uppercase type. */
:root {
  --bg: #0b0a08;
  --gold: #f6c243;
  --gold-deep: #e0a52c;
  --gold-row: #f8c94e;
  --gold-row-2: #f2bb35;
  --cream: #fbe7a2;
  --cream-2: #fdedb6;
  --ink: #241a4d;          /* dark purple-navy text on gold, like the poster */
  --ink-soft: #4a3f75;
  --red: #e03448;
  --red-hot: #ff3b30;
  --green: #1fae4b;
  --gray: #9a9a9a;
  --card: #171410;
  --card-border: #2c2620;
  --text: #f3ead2;
  --shadow: 0 10px 26px rgba(0,0,0,.55);
  --radius: 18px;
  /* Gold rows are milled bullion: an evenly lit mirror face, a bright machined
     rim, a bronze edge with real thickness, and a sheen that travels across the
     plate when you point at one. Kept to four background layers — every extra
     blended layer is paint work on every row. */
  --row-edge: #c9962f;      /* the lit face of the milled edge */
  --row-edge-deep: #8a5c14; /* where that edge turns away from the light */
  --row-face:
    inset 0 1px 0 rgba(255,251,232,.62),
    inset 0 -1px 0 rgba(255,228,158,.28),  /* warm light bouncing back up off the page */
    inset 0 -2px 0 rgba(116,70,4,.3),
    inset 1px 0 0 rgba(255,243,206,.2),
    inset -1px 0 0 rgba(116,70,4,.26);
  /* One whisper-quiet noise screen (sRGB so the maths land where they look): the
     micro tooth that keeps polished metal from reading as plastic and stops the
     gradient banding. Squeezed to a hair of contrast — this is jewellery, not
     weathering. Rows offset it by rank so no tiling shows. */
  --metal-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.95' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='.2' intercept='.4'/%3E%3CfeFuncG type='linear' slope='.2' intercept='.4'/%3E%3CfeFuncB type='linear' slope='.2' intercept='.4'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23g)'/%3E%3C/svg%3E");
  /* the edge layer is written at each point of use: a var() nested inside another
     custom property resolves against :root, so it could never go dark on .lower */
  /* a thin plate, not a slab: the milled edge reads at 1-2px and the shadow stays
     close to the page so the rows sit on it rather than hover above it */
  --row-lift: 0 2px 2px -1px rgba(0,0,0,.42), 0 9px 16px -10px rgba(0,0,0,.72);
  --row-lift-hi: 0 5px 4px -3px rgba(0,0,0,.42), 0 15px 24px -12px rgba(0,0,0,.78);
  --row-press: 0 1px 1px -1px rgba(0,0,0,.5), 0 5px 10px -8px rgba(0,0,0,.66);
  /* the crew's own display face (declared further down, served from /fonts) —
     Arial Black stays behind it as the metric-ish fallback while it loads */
  --font-head: 'PP Monument Extended', 'Arial Black', 'Avenir Next Condensed', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Avenir Next', 'Helvetica Neue', Arial, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  min-height: 100vh;
  overflow-x: hidden;
  /* Sticky footer: the footer's margin-top:auto pushes it to the bottom on short pages,
     while sitting right below the board on tall ones. */
  display: flex;
  flex-direction: column;
}
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
img { max-width: 100%; }

/* ---------- page base (solid dark; fire now lives in the footer image) ---------- */
.fire-bg {
  position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background: linear-gradient(180deg, #060505 0%, #0b0a08 55%, #0b0a08 100%);
}
/* Header banner: a gold halftone screen printed behind the logo (drawn by
   halftone.js — see there for the water). Full-bleed, masked so the print melts
   into the page before the board starts. */
.header-bg {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  /* bounded: past this the halo stops growing and only costs pixels to redraw */
  width: min(100%, 1600px);
  height: clamp(340px, 36vw, 560px);
  z-index: -1; pointer-events: none;
  opacity: .5;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 32%, transparent 86%);
  mask-image: linear-gradient(180deg, #000 0%, #000 32%, transparent 86%);
}

/* ---------- top bar: menu strip pinned to the very top, logo below ---------- */
.topbar {
  display: block; padding: 16px 40px 10px; max-width: 1100px; margin: 0 auto; width: 100%;
}
.topstrip { display: flex; align-items: center; gap: 8px; position: relative; }
/* Always pinned to the far right, independent of the nav — margin-left:auto
   works whether the nav is inline (desktop) or collapsed to nothing (mobile). */
.nav-utils { display: flex; align-items: center; gap: 8px; margin-left: auto; flex: 0 0 auto; }
.nav-mojos:empty { display: none; }
/* Logo block: perfectly centered, with symmetric air above and below. */
.topbar-logo {
  display: flex; align-items: center; justify-content: center;
  width: clamp(190px, 24vw, 280px); margin: 34px auto 14px;
}
.topbar-logo .logo-img {
  display: block; width: 100%; height: auto; user-select: none;
  filter: drop-shadow(0 14px 30px rgba(0,0,0,.65));
}

/* ---------- nav (always one inline row — collapses behind a burger button on
   phones instead of wrapping; see the mobile breakpoint below) ---------- */
.mainnav {
  display: flex; gap: 2px; justify-content: center; flex-wrap: nowrap;
  padding: 4px 8px; max-width: 980px; min-width: 0;
  white-space: nowrap;
  /* Belt-and-braces: at the sizing below this fits every item at every width above
     the burger breakpoint, but if a future item ever tips it over, it scrolls inside
     its own box instead of overlapping the burger/mojos or overflowing the page. */
  overflow-x: auto; scrollbar-width: none;
}
.mainnav::-webkit-scrollbar { display: none; }
.mainnav a, .mainnav button {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  letter-spacing: .01em; font-size: 8.5px; border-radius: 8px;
  padding: 5px 6px; border: 2px solid transparent; background: transparent; color: var(--text);
  flex: none;
}
/* Exclude the active item from hover: otherwise :hover (higher specificity) repaints the
   label gold on the gold active background — invisible until the touch :hover state clears. */
.mainnav a:not(.active):hover, .mainnav button:not(.active):hover { border-color: var(--gold); color: var(--gold); }
.mainnav .active { background: var(--gold); color: #14100a; }
.mainnav .nav-me { border-color: var(--card-border); display: inline-flex; gap: 6px; align-items: center; }
/* The language toggle rides along as a regular menu item; a hairline border sets
   it apart from the route links without a whole separate visual language. */
.mainnav .nav-lang { border-color: rgba(246,194,67,.5); color: var(--gold); }
.mainnav .nav-lang:hover { background: var(--gold); color: #14100a; border-color: var(--gold); }

/* Burger toggle: hidden above the mobile breakpoint, where the nav is always inline. */
.nav-burger {
  display: none; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; width: 34px; height: 34px; padding: 0; flex: 0 0 auto;
  background: transparent; border: 1.5px solid rgba(246,194,67,.5); border-radius: 8px;
}
.nav-burger-bar {
  display: block; width: 17px; height: 2px; background: var(--gold); border-radius: 1px;
  transition: transform .2s ease, opacity .2s ease;
}
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
.dotava {
  width: 16px; height: 16px; border-radius: 50%; overflow: hidden; flex: 0 0 16px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 10px;
}
.dotava img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- layout ---------- */
/* The board hugs its own content width (see the .app comment below) rather than
   always filling to 1080 — so the season strip can't just center itself
   independently at the same max-width, that would only coincidentally line up.
   This wrapper is the flex item instead (margin:auto in a flex column = shrink to
   fit, up to max-width), and its two children each simply take 100% of whatever
   width it resolves to — guaranteeing they always share the same left/right edges. */
.pagecol { max-width: 1080px; margin: 0 auto; }
.app { width: 100%; padding: 12px 20px 6px; }
/* Footer: the crew's fire artwork (img/footer.png) starting right below the board,
   with a short fade so it melts into the page. */
/* Footer: a quiet brand coda in the seal aesthetic — hairline-and-diamond
   divider, the crew emblem, name, tagline, credit. No fire: the warmth comes
   from a gold halftone field rising out of the floor (echoing the header) over
   a soft gold gradient wash. Flats + gradients + halftone, on brand. */
.footer {
  position: relative; margin-top: auto; padding: 0 20px; overflow: hidden;
  background: radial-gradient(150% 120% at 50% 140%, rgba(246,194,67,.14), transparent 62%);
}
/* halftone dot field, densest at the bottom-centre and fading up and out */
.footer::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(circle, rgba(246,194,67,.6) 1.1px, transparent 1.7px);
  background-size: 14px 14px; background-position: center bottom;
  -webkit-mask-image: radial-gradient(120% 122% at 50% 126%, #000 22%, transparent 70%);
  mask-image: radial-gradient(120% 122% at 50% 126%, #000 22%, transparent 70%);
  opacity: .7;
}
.ft-inner {
  position: relative; z-index: 1; max-width: 620px; margin: 0 auto;
  padding: 52px 0 36px; display: flex; flex-direction: column; align-items: center; text-align: center;
}
.ft-seal {
  width: 44px; height: 44px; object-fit: contain; margin-bottom: 16px;
  filter: drop-shadow(0 0 13px rgba(246,194,67,.4)) drop-shadow(0 3px 5px rgba(0,0,0,.55));
}
.ft-crew {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(14px, 2.8vw, 16px); letter-spacing: .26em; margin-left: .26em;
  color: var(--cream); text-shadow: 0 1px 8px rgba(0,0,0,.6);
}
/* tagline + credit share one line, sized so the pair stays narrower than the
   crew name above — a tidy centred stack */
.ft-sub {
  margin-top: 9px; display: flex; align-items: center; justify-content: center;
  gap: 6px; flex-wrap: nowrap; white-space: nowrap;
}
.ft-tag {
  font-family: var(--font-body); font-style: italic;
  font-size: 10.5px; letter-spacing: .01em; color: #b9a877; opacity: .85;
}
.ft-mid { color: var(--gold); opacity: .5; font-size: 8px; }
.ft-credit {
  color: #8a7f66; font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 8px; letter-spacing: .14em;
  display: inline-flex; align-items: center; gap: 4px; transition: color .15s ease;
}
.ft-credit span { color: var(--gold); }
.footer-link { color: var(--gold); transition: color .15s ease; }
.footer-link:hover, .ft-credit:hover { color: var(--cream); }
/* small ✕ delete buttons in the admin panel */
.btn.sm.del { padding: 6px 9px; color: #c98; border-color: #4a3b32; }
.btn.sm.del:hover { color: #fff; border-color: var(--red); background: rgba(224,52,72,.15); }

/* ---------- season strip: the era the board is being fought in ----------
   Reads like the header of a printed table: the era's name struck at the left over
   a hairline that runs the full width, and at the right one wordless button — the
   stacked plates — that opens every season the crew has played.

   It lives in its own host in the page chrome (see index.html), right below the logo
   and above the board — the menu now lives up in the topbar itself, so this always
   reads as the board's own header, on every screen size. */
.seasonhost:empty { display: none; }
/* Shares .pagecol with the board (see the .app comment above), so it's always the
   exact same width and left edge as the table it heads — never independent. */
.seasonhost { width: 100%; padding: 10px 20px 0; }
.seasonbar {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 0 3px 10px; margin-top: 2px;
}
.seasontitle { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex-wrap: wrap; }
.seasonname {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(15px, 3.2vw, 20px); letter-spacing: .09em; color: var(--cream);
  text-shadow: 0 1px 10px rgba(0,0,0,.6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.seasonbar.past .seasonname { color: #b9a877; }
.seasonchip {
  font-family: var(--font-head); font-weight: 900; font-size: 9px;
  letter-spacing: .18em; text-transform: uppercase;
  color: #8d7f5c; background: #221d15; border: 1px solid #3a332a;
  border-radius: 999px; padding: 3px 8px;
}
/* the board is open but the ladder isn't — gold, because this is a live state the
   crew is meant to act on, not the grey of a board that has stopped */
.seasonchip.signup { color: var(--gold); background: rgba(246,194,67,.12); border-color: rgba(246,194,67,.45); }
/* SIN ESPERA — the house has lifted the 24h door between two fighters who just
   played. Cyan, the same "the rules are relaxed right now" colour quickplay uses,
   so it never gets read as a Purge (violet) or as a stopped board (grey). It
   breathes, because it is a temporary state somebody flipped on and will flip off. */
.seasonchip.nocd {
  color: var(--qp-on); background: rgba(34,211,238,.12); border-color: rgba(34,211,238,.5);
  animation: nocd-breathe 2.6s ease-in-out infinite;
}
@keyframes nocd-breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(34,211,238,0); }
  50% { box-shadow: 0 0 10px 0 rgba(34,211,238,.35); }
}
@media (prefers-reduced-motion: reduce) { .seasonchip.nocd { animation: none; } }
/* Joining a board: the ask sits right next to its name, so the invitation reads as
   part of the title rather than as another control in a row of controls. */
.subbtn {
  display: inline-flex; align-items: center; justify-content: center; min-height: 32px;
  font-family: var(--font-head); font-weight: 900; font-size: 9px;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold); background: transparent; border: 1.5px solid rgba(246,194,67,.55);
  border-radius: 999px; padding: 3px 10px; white-space: nowrap;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.subbtn:hover { background: var(--gold); color: #14100a; border-color: var(--gold); }
.subbtn.pending { color: #b9a877; border-color: #55472e; }
.subbtn.billing { text-decoration: none; color: #74d896; border-color: rgba(78,208,124,.5); }
.subbtn.billing:hover { background: #4ed07c; border-color: #4ed07c; color: #08210f; }
.subbtn.billing.attention { color: #ff8b94; border-color: rgba(219,47,66,.6); }
.subbtn.billing.attention:hover { background: #db2f42; color: #fff; border-color: #db2f42; }
/* The owner's queue nags gently in green until it's dealt with. */
.subbtn.queue { color: #4ed07c; border-color: rgba(31,174,75,.55); }
.subbtn.queue:hover { background: #4ed07c; color: #08210f; border-color: #4ed07c; }
.subchip {
  font-family: var(--font-head); font-weight: 900; font-size: 9px;
  letter-spacing: .18em; text-transform: uppercase;
  border-radius: 999px; padding: 3px 9px;
  color: #8d7f5c; background: #221d15; border: 1px solid #3a332a;
}
.subchip.pending { color: var(--gold); border-color: rgba(246,194,67,.4); }
.stchip.pending { background: rgba(246,194,67,.14); color: var(--gold); border: 1px solid rgba(246,194,67,.45); }
.ownmark { color: var(--gold); font-size: 11px; }
/* the request queue inside the modal */
.modal-sub { font-size: 12px; color: #8d7f5c; margin: -4px 0 12px; line-height: 1.45; }
.qlist { display: flex; flex-direction: column; gap: 8px; text-align: left; }
.qrow {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: #17130e; border: 1px solid #332b21; border-radius: 12px; padding: 10px 12px;
}
.qwho { display: flex; align-items: center; gap: 10px; min-width: 0; }
.qwho .ava.sm { width: 30px; height: 30px; flex: 0 0 30px; border-radius: 50%; overflow: hidden; display: inline-flex; }
.qwho b { font-family: var(--font-head); font-size: 13px; letter-spacing: .04em; display: block; }
.qsub { font-size: 11px; color: #8d7f5c; }
.qbtns { display: flex; gap: 6px; flex: none; }
/* opening your own board, and the wall in front of it */
.seamake { display: flex; gap: 8px; margin-top: 14px; }
.seamake input {
  flex: 1 1 auto; min-width: 0; padding: 9px 12px; border-radius: 10px;
  border: 1px solid #3a332a; background: #0f0d0a; color: var(--text);
  font-size: 14px; font-family: inherit; box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
}
.seamake input::placeholder { color: #7d7361; }
.seamake input:focus {
  outline: none; border-color: var(--gold);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5), 0 0 0 3px rgba(246,194,67,.22);
}
.seapay {
  margin-top: 14px; padding: 12px 14px; border-radius: 12px; text-align: left;
  background: #17130e; border: 1px dashed #46381b;
}
.seapay b {
  display: block; font-family: var(--font-head); text-transform: uppercase;
  font-size: 12px; letter-spacing: .06em; color: var(--gold); margin-bottom: 4px;
}
.seapay span { font-size: 12px; color: #8d7f5c; }
.seapay.action { border-style: solid; display: flex; justify-content: center; }
/* the board you're currently looking at, in the switcher */
.searow.here { border-color: var(--gold); background: #1d1811; }

/* ---------- seasons directory: one card per ladder ---------- */
/* .pagecol is fit-content everywhere else (see the board); here it takes the full
   column so the grid has room for a second card. */
body.on-seasons .pagecol { width: 100%; min-width: 0; }
.sea-page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.sea-page-head > .btn { flex: none; margin-top: 2px; }
.sea-lede { color: #8d7f5c; font-size: 13px; line-height: 1.5; margin: -8px 0 20px; max-width: 62ch; }
.seagrid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.seacard {
  display: flex; flex-direction: column; gap: 12px;
  background: #17130e; border: 1px solid #332b21; border-radius: 14px; padding: 16px;
  transition: border-color .12s ease;
}
.seacard:hover { border-color: #4a3f2e; }
.seacard.mine { border-color: rgba(246,194,67,.42); }
.seacard.closed { opacity: .82; }
.seahead { display: flex; flex-direction: column; gap: 5px; }
.seaname { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.seaname b {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 15px; letter-spacing: .05em; color: var(--cream);
}
.seameta { font-size: 11.5px; color: #8d7f5c; }
.seameta b { color: #b9a877; font-weight: 700; }
.seadates {
  display: flex; gap: 16px; flex-wrap: wrap;
  font-size: 11px; color: #8d7f5c;
  padding: 9px 0; border-top: 1px solid #262019; border-bottom: 1px solid #262019;
}
.seadates i {
  font-style: normal; font-family: var(--font-head); font-weight: 900;
  font-size: 8.5px; letter-spacing: .2em; text-transform: uppercase; color: #6d6250;
  display: block; margin-bottom: 2px;
}
/* the podium row — the crew's DIOSES band, shrunk to a card */
.seagodline { display: flex; flex-direction: column; gap: 7px; }
.godlabel {
  font-family: var(--font-head); font-weight: 900; font-size: 8.5px;
  letter-spacing: .3em; text-transform: uppercase; color: var(--gold);
}
.sgods { display: flex; gap: 12px; flex-wrap: wrap; }
.sgods.empty { font-size: 11.5px; color: #6d6250; font-style: italic; }
.sgod { display: inline-flex; align-items: center; gap: 5px; min-width: 0; }
.sgod .medal { width: 20px; height: 23px; }
.sgod .ava.sm {
  width: 22px; height: 22px; flex: 0 0 22px; border-radius: 50%;
  overflow: hidden; display: inline-flex; align-items: center; justify-content: center;
}
.sgod .ava.sm img { width: 100%; height: 100%; object-fit: cover; }
.sgod b {
  font-family: var(--font-head); font-weight: 900; font-size: 11px;
  letter-spacing: .03em; color: var(--cream);
  max-width: 11ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.seaactions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; align-items: center; }
/* the owner's stage switch: REGISTRO | TABLA ABIERTA, current state lit. Two halves
   of one control rather than a button that acts, so the board's state is legible
   without reading the verb on it. */
.stageseg {
  display: inline-flex; flex: none; border-radius: 9px; overflow: hidden;
  border: 1px solid #3a332a; background: #14100a;
}
.stageseg button {
  appearance: none; border: none; cursor: pointer; background: none;
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 8.5px; letter-spacing: .14em; color: #7d7361;
  padding: 7px 10px; transition: background .12s ease, color .12s ease;
}
.stageseg button + button { border-left: 1px solid #3a332a; }
.stageseg button:hover:not(.on) { background: #1d1811; color: #b9a877; }
.stageseg button.on { background: rgba(246,194,67,.16); color: var(--gold); cursor: default; }
.stageseg button:last-child.on { background: rgba(31,174,75,.2); color: #4ed07c; }
@media (max-width: 560px) {
  .seagrid { grid-template-columns: 1fr; }
  .sea-page-head { flex-direction: column; }
  .sea-page-head > .btn { margin: -8px 0 18px; }
}

/* ---------- monthly season creator offer / billing management ---------- */
.billing-page { overflow: hidden; }
.seasonoffer {
  display: grid; grid-template-columns: minmax(0,1.25fr) minmax(280px,.75fr); gap: 24px;
  align-items: stretch;
}
.offer-copy, .offer-price, .billing-manage, .billing-wait {
  border-radius: 16px; border: 1px solid #332b21; background: #17130e;
}
.offer-copy { padding: clamp(24px,4vw,46px); position: relative; overflow: hidden; }
.offer-copy::after {
  content: ''; position: absolute; width: 260px; height: 260px; border-radius: 50%;
  right: -120px; top: -140px; background: rgba(246,194,67,.08); pointer-events: none;
}
.offer-kicker {
  display: block; font-family: var(--font-head); font-weight: 900; font-size: 9px;
  letter-spacing: .28em; color: var(--gold); text-transform: uppercase; margin-bottom: 14px;
}
.offer-copy h1, .billing-head h1, .billing-wait h1 {
  font-family: var(--font-head); text-transform: uppercase; color: var(--cream);
  font-size: clamp(28px,5vw,52px); line-height: .98; letter-spacing: -.025em; margin: 0 0 14px;
}
.offer-copy > p { color: #b3a58a; font-size: 15px; line-height: 1.65; max-width: 58ch; }
.offer-copy ul { display: grid; gap: 10px; list-style: none; margin: 24px 0 0; }
.offer-copy li { color: var(--cream); font-size: 13px; padding-left: 22px; position: relative; }
.offer-copy li::before { content: '✓'; position: absolute; left: 0; color: var(--gold); font-weight: 900; }
.offer-price { padding: 25px; display: flex; flex-direction: column; justify-content: center; }
.offer-price form { width: 100%; }
.offer-price > span {
  font-family: var(--font-head); font-size: 9px; letter-spacing: .18em;
  text-transform: uppercase; color: #8d7f5c;
}
.offer-trial-badge {
  display: inline-block; align-self: flex-start; margin-bottom: 10px;
  padding: 5px 11px; border-radius: 999px; border: 1.5px solid var(--gold);
  background: rgba(246,194,67,.12); color: var(--gold);
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 10px; letter-spacing: .08em;
}
.offer-price > b { font-family: var(--font-head); font-size: clamp(50px,8vw,76px); line-height: 1; color: var(--gold); margin: 8px 0 2px; }
.offer-price > b small { font-size: 18px; letter-spacing: .02em; margin-right: 5px; }
.offer-price > em { color: #8d7f5c; font-size: 12px; font-style: normal; margin-bottom: 24px; }
.offer-price .field { margin-bottom: 12px; }
.offer-price .btn[disabled] { opacity: .45; cursor: not-allowed; }
.billing-fine { color: #9a8d74; font-size: 12px; line-height: 1.55; margin: 11px 2px 0; }
.seasonoffer.comp { grid-template-columns: minmax(0,1fr) minmax(280px,.65fr); }
.billing-manage { padding: clamp(20px,4vw,36px); }
.billing-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; margin-bottom: 20px; }
.billing-head h1 { font-size: clamp(26px,4vw,42px); margin-bottom: 8px; }
.billing-head h1 { overflow-wrap: anywhere; word-break: break-word; }
.billing-head p { color: #9a8d74; font-size: 13px; }
.billnotice {
  display: flex; flex-direction: column; gap: 3px; margin-bottom: 16px; padding: 12px 14px;
  border-radius: 11px; border: 1px solid #3a332a; background: #1d1811; color: #b9aa8b;
  font-size: 12px; line-height: 1.45;
}
.billnotice b { font-family: var(--font-head); text-transform: uppercase; font-size: 10px; letter-spacing: .08em; }
.billnotice.good { border-color: rgba(78,208,124,.45); color: #82dca0; }
.billnotice.gold { border-color: rgba(246,194,67,.48); color: #e0c16d; }
.billnotice.bad { border-color: rgba(219,47,66,.55); color: #ed969e; }
.billnotice.neutral { margin-bottom: 18px; }
.renewal-choice { border: 0; border-top: 1px solid #30281f; padding: 20px 0 0; margin: 0; min-width: 0; }
.renewal-choice legend {
  font-family: var(--font-head); text-transform: uppercase; font-size: 12px;
  letter-spacing: .06em; color: var(--cream); margin: 0 0 11px; padding: 0;
}
.renew-option {
  display: flex; gap: 11px; align-items: flex-start; padding: 13px 14px; margin-bottom: 8px;
  border: 1px solid #3a332a; border-radius: 12px; cursor: pointer; transition: border-color .12s, background .12s;
}
.renew-option.selected { border-color: rgba(246,194,67,.62); background: rgba(246,194,67,.055); }
.renew-option input { margin-top: 3px; accent-color: var(--gold); }
.renew-option b { display: block; color: var(--cream); font-size: 13px; }
.renew-option small { display: block; color: #8d7f5c; font-size: 11.5px; line-height: 1.45; margin-top: 2px; }
.renewal-name { margin: 14px 0; }
.renewal-name.hidden { display: none; }
.billing-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.billing-actions.center { justify-content: center; }
.billing-wait { padding: 44px; text-align: center; }
.billing-wait h1 { font-size: 28px; }
.billing-wait p { color: #8d7f5c; margin: 8px auto 20px; max-width: 48ch; }
@media (max-width: 760px) {
  .seasonoffer, .seasonoffer.comp { grid-template-columns: 1fr; }
  .billing-head { flex-direction: column; }
  .billing-actions .btn { flex: 1 1 auto; text-align: center; }
}
.seasonbtn {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 10px;
  background: transparent; border: 1.5px solid rgba(246,194,67,.45); color: var(--gold);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.seasonbtn svg { width: 17px; height: 17px; display: block; }
.seasonbtn:hover { background: var(--gold); color: #14100a; border-color: var(--gold); }
/* The MOJOS balance: a gem button in the season strip's own corner, badged with the
   count so the number is visible without a tap — the tap is for buying more. */
.mojobtn {
  position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 10px;
  background: transparent; border: 1.5px solid rgba(246,194,67,.45); color: var(--gold);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.mojobtn svg { width: 16px; height: 16px; display: block; }
.mojobtn:hover { background: var(--gold); color: #14100a; border-color: var(--gold); }
.mojobtn .mojocount {
  position: absolute; bottom: -6px; right: -6px; min-width: 16px; height: 16px; padding: 0 3px;
  display: flex; align-items: center; justify-content: center; border-radius: 999px;
  background: var(--gold); color: #14100a; border: 1.5px solid #14100a;
  font-family: var(--font-head); font-weight: 900; font-size: 9px; line-height: 1;
}
/* ---------- sponsors: the banner over a board ----------
   Sits between the season strip and the board itself. Restrained but never dimmed:
   being seen in their own colours is the entire thing a sponsor bought, so no
   greyscale and no half-opacity — the strip earns its quiet from being short and
   sitting on a muted plate, not from hiding the logos on it. */
.sponsorstrip {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  margin: 10px 3px 0; padding: 14px 18px;
  background: rgba(23, 20, 16, .55);
  border: 1px solid rgba(201, 169, 79, .18); border-radius: 12px;
}
/* The marks and nothing else. The label that used to sit here ("PATROCINADO POR")
   was the one thing on the strip a sponsor hadn't paid for, and it pushed the logos
   off centre; a rail of marks on its own plate says "sponsor" without being told to.
   Generous air between them instead — the separation IS the design. */
.sponsorlist {
  display: flex; align-items: center; justify-content: center;
  gap: 30px; flex-wrap: wrap; min-width: 0;
}
.sponsor {
  display: inline-flex; align-items: center; justify-content: center;
  max-width: 160px;
  transition: transform .14s ease, filter .14s ease;
}
/* A dark logo on a dark strip would vanish, and most brand marks are built for white.
   A whisper of lift behind the mark keeps any of them legible without framing them
   in a box or bleaching the ones that are already bright. */
/* Normalized by HEIGHT, capped on width: a rail of logos reads as one row only when
   every mark shares an optical height, whatever aspect the brand hands over — a square
   badge and a long wordmark both land on the same baseline. */
.sponsor img {
  display: block; max-height: 38px; width: auto; max-width: 160px; object-fit: contain;
  filter: drop-shadow(0 0 6px rgba(255, 248, 224, .18));
}
.sponsor .sponsor-name {
  font-family: var(--font-head); font-weight: 900; font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--cream);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
a.sponsor:hover { transform: translateY(-1px); }
a.sponsor:hover img { filter: drop-shadow(0 0 9px rgba(255, 248, 224, .34)); }
/* The joiner between two houses on one bill. Deliberately tiny and dim — it is
   punctuation, not a third mark, and it must never compete with what it separates.
   The air around it is doing most of the work; the × just tells you the gap is
   meaningful rather than a layout accident. */
.sponsor-x {
  flex: none; align-self: center;
  font-family: var(--font-body); font-size: 9px; line-height: 1;
  color: rgba(201, 169, 79, .34); user-select: none;
}
@media (max-width: 560px) {
  .sponsorstrip { padding: 11px 12px; }
  .sponsorlist { gap: 18px; }
  .sponsor img { max-height: 26px; }
  .sponsor { max-width: 120px; }
  .sponsor-x { font-size: 8px; }
}

/* the house's sponsor desk, inside the modal */
.splist { display: flex; flex-direction: column; gap: 8px; margin: 10px 0 4px; text-align: left; }
.sprow {
  display: flex; align-items: center; gap: 10px;
  background: #17130e; border: 1px solid #332b21; border-radius: 12px; padding: 9px 11px;
}
.spthumb {
  flex: none; width: 54px; height: 34px; border-radius: 7px;
  background: #0f0d0a; border: 1px solid #2c2620;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.spthumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.spnologo { font-size: 7.5px; letter-spacing: .1em; text-transform: uppercase; color: #6f6350; text-align: center; }
.spinfo { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.spinfo b { font-family: var(--font-head); font-size: 12px; letter-spacing: .04em; }
.spsub { font-size: 10.5px; color: #8d7f5c; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spmove { display: flex; gap: 4px; flex: none; }
.spmove .btn { padding: 5px 8px; font-size: 11px; line-height: 1; }
.spform { margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(201, 169, 79, .16); }
.spform input[type="file"] { font-size: 12px; color: #8d7f5c; }
.sppreview:not(:empty) {
  margin-top: 8px; padding: 8px; border-radius: 8px;
  background: #0f0d0a; border: 1px solid #2c2620;
  display: flex; align-items: center; justify-content: center;
}
.sppreview img { max-height: 46px; max-width: 100%; object-fit: contain; }

/* the marketing opt-in, in the profile editor */
.optrow {
  display: flex; align-items: flex-start; gap: 9px; margin-top: 4px;
  font-size: 12px; line-height: 1.45; color: #a99e85; cursor: pointer; user-select: none;
}
.optrow input {
  appearance: none; -webkit-appearance: none; flex: none; margin-top: 1px;
  width: 16px; height: 16px; border-radius: 4px;
  border: 1.5px solid #4a4132; background: #0f0d0a; cursor: pointer;
  display: grid; place-content: center;
  transition: border-color .12s ease, background .12s ease;
}
.optrow input::after {
  content: ''; width: 8px; height: 8px; border-radius: 2px;
  transform: scale(0); background: var(--ink); transition: transform .12s ease;
}
.optrow input:checked { background: var(--gold); border-color: var(--gold); }
.optrow input:checked::after { transform: scale(1); }
.optrow input:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.seasonnote {
  margin: 12px 3px 0; font-size: 12px; color: #8d7f5c;
  font-family: var(--font-body); font-style: italic;
}
.seasonback { margin: 18px 0 4px; text-align: center; }
/* print the record — offered under a closed board, for anyone reading it */
.boardshots {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px;
  margin: 20px 0 2px; padding-top: 16px; border-top: 1px solid rgba(201,169,79,.18);
}
.boardshots .bshot-label {
  display: inline-flex; align-items: center; gap: 7px; margin-right: 4px;
  font-family: var(--font-head); font-weight: 900; font-size: 10px;
  letter-spacing: .18em; text-transform: uppercase; color: #8d7f5c;
}
.boardshots .bshot-label svg { width: 15px; height: 15px; }
/* the archive list inside the modal */
.sealist { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; text-align: left; }
.searow {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: #17130e; border: 1px solid #332b21; border-radius: 12px;
  padding: 11px 13px; color: var(--text); text-align: left; width: 100%;
  transition: border-color .12s ease, background .12s ease;
}
.searow:hover { border-color: var(--gold); background: #1d1811; }
.searow.live { border-color: rgba(246,194,67,.55); }
.seainfo { display: flex; flex-direction: column; min-width: 0; }
.seainfo b { font-family: var(--font-head); text-transform: uppercase; font-size: 13px; letter-spacing: .05em; }
.seasub { font-size: 11.5px; color: #8d7f5c; margin-top: 3px; }
/* admin: the "start a new season" box */
.seasonbox { align-items: flex-start; }
.seasonbox > div:first-child { flex: 1 1 300px; }
.seasonform { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; flex: 1 1 260px; }
.seasonform input {
  padding: 9px 12px; border-radius: 10px; border: 1px solid #3a332a;
  background: #0f0d0a; color: var(--text); font-size: 14px; font-family: inherit;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5); flex: 1 1 200px; min-width: 0;
}
.seasonform input::placeholder { color: #7d7361; }
.seasonform input:focus {
  outline: none; border-color: var(--gold);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5), 0 0 0 3px rgba(246,194,67,.22);
}
/* Phones: the menu now lives in the topbar itself, so it's always first — no
   reordering needed. */
@media (max-width: 640px) {
  .app { padding-top: 4px; }
}

/* ---------- ranking board ---------- */
.board { display: flex; flex-direction: column; gap: 14px; margin-top: 12px; position: relative; }
/* A closed season's board is a record, not a ladder: nothing to press, nothing to win. */
.board.frozen .rankrow { cursor: default; }
.board.frozen .rankrow:hover { transform: none; box-shadow: var(--row-lift), var(--row-face); }
.board.frozen .rankrow:active { transform: none; }
.board.frozen .rankrow[data-go] { cursor: pointer; }

/* Zone bands: the crew's own name for each stretch of the ladder, set as a tiny
   caption with a hairline running off to the right. Brightest at the top. */
.tierband {
  display: flex; align-items: center; gap: 10px;
  margin: 12px 3px -5px;
  font-family: var(--font-head); font-weight: 900;
  font-size: 9px; letter-spacing: .34em; text-transform: uppercase;
  color: var(--gold); line-height: 1;
}
.tierband::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, currentColor, transparent);
  opacity: .4;
}
.tierband:first-child { margin-top: 0; }
.tierband.tops { color: #c9ab6c; }
.tierband.pit { color: #8a7d63; }

.rankrow {
  display: grid;
  /* Movement first, then the spot: the arrow is the thing you scan DOWN the board
     for, so it sits on the edge you read from rather than trailing the row.
     The painting's track is added by .board.has-art below, NOT here — on a board
     where nobody has bought an arte yet (every board, on day one) a permanent
     empty column at the end of every row reads as a layout bug, and a frozen
     board never carries art at all. The track appears with the first painting. */
  /* 15px, not 19: the badge is flex-END aligned (see .rankrow .delta below), so
     this track being narrower than the 19px badge it holds doesn't clip anything
     — the icon simply bleeds 4px into the row's own left padding, which has no
     background of its own to interrupt. That 4px is exactly (row-pad-x - the
     grid's own column-gap), which is what makes the visible arrow-to-number gap
     (pure column-gap) equal the visible row-edge-to-arrow gap: the two things
     the request actually asked to match. */
  grid-template-columns: 15px 40px minmax(0,1fr) 118px 150px;
  gap: 12px; align-items: center;
  /* Polished bullion, from the top down: micro grain, shaded side bevels, then
     the mirror itself — bright crown falling evenly to a deeper heel. The rim
     light and the bounce light are insets (see --row-face), not layers. */
  background:
    var(--metal-grain) calc(var(--n, 0) * 23px) calc(var(--n, 0) * 17px) / 120px 120px repeat,
    linear-gradient(90deg, rgba(116,70,4,.14), rgba(116,70,4,0) 3%, rgba(116,70,4,0) 97%, rgba(116,70,4,.16)) no-repeat,
    linear-gradient(180deg, #fff5d0 0%, #ffe093 8%, #fbd062 32%, #f7c649 58%, #f0b839 84%, #e5ab2e 100%) no-repeat;
  background-blend-mode: soft-light, multiply, normal;
  isolation: isolate;         /* so the sheen below can slot between plate and content */
  border-radius: var(--row-radius);
  /* Kept as variables because .rowart bleeds THROUGH this padding to reach the
     plate's edge, and the phone and the split both re-pad the row. One place to
     change per breakpoint instead of two that can silently drift apart.
     --row-radius is here for the same reason: the split mills a squarer plate
     (8px), and an .rowart still rounding itself to the global 18px left a visible
     mismatch where the two corners met. */
  --row-radius: var(--radius);
  --row-pad-y: 14px; --row-pad-x: 18px;
  padding: var(--row-pad-y) var(--row-pad-x);
  box-shadow: var(--row-lift), var(--row-face);
  color: var(--ink);
  position: relative;
  transition: transform .12s ease, box-shadow .12s ease;
  cursor: pointer;
}
/* Somebody on this board owns an arte → every row gets the extra track, so the
   ones who don't own one see the gap where theirs would hang. That is the point. */
.board.has-art .rankrow { grid-template-columns: 15px 40px minmax(0,1fr) 118px 150px 116px; }

/* The travelling specular. The band is the pseudo-element's own background and it
   is the BACKGROUND that slides, not the element — so the light is clipped to the
   plate (rounded corners included) and never paints out over the page. z-index -1
   inside the row's own stacking context puts it over the metal but under the text. */
.rankrow::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: inherit;
  background:
    linear-gradient(102deg, rgba(255,255,255,0) 32%, rgba(255,255,255,.32) 46%, rgba(255,255,255,.06) 53%, rgba(255,255,255,0) 67%)
    132% 0 / 240% 100% no-repeat;
  transition: background-position .8s cubic-bezier(.36,0,.2,1);
}
/* desktop: pointing at it. touch: the first tap, which is what .reveal marks. */
.rankrow:hover::after, .rankrow.reveal::after { background-position: -32% 0; }
.rankrow:hover { transform: translateY(-1px) scale(1.004); box-shadow: var(--row-lift-hi), var(--row-face); }
/* pressing a plate pushes it down onto its own edge */
.rankrow:active { transform: translateY(1px) scale(.998); box-shadow: var(--row-press), var(--row-face); transition-duration: .06s; }
/* Open zone (spot 11 and below): the same plate milled from black stock — polished
   graphite with a warm hairline, so it reads as the same hardware, not the same metal. */
.rankrow.lower {
  --row-edge: #2b241b;
  --row-edge-deep: #0a0806;
  --row-face:
    inset 0 1px 0 rgba(255,240,205,.16),
    inset 0 -1px 0 rgba(0,0,0,.6),
    inset 1px 0 0 rgba(255,240,205,.06),
    inset -1px 0 0 rgba(0,0,0,.45);
  background: linear-gradient(180deg, #262019 0%, #1c1813 52%, #161209 100%) no-repeat;
  border: 1px solid #322b21;
  box-shadow: var(--row-lift), var(--row-face);
  color: var(--text);
}
/* the same sweep, dialled down to what black stock would actually catch */
.rankrow.lower::after { background: linear-gradient(102deg, rgba(255,238,196,0) 34%, rgba(255,238,196,.14) 47%, rgba(255,238,196,.03) 53%, rgba(255,238,196,0) 66%); }
.rankrow.lower .tag { text-shadow: 0 1px 0 rgba(0,0,0,.7), 0 -1px 0 rgba(255,240,205,.09); }
.rankrow.lower .crewtag { color: #b9a877; }
.rankrow.lower .lock { color: #b9a877; }
.rankrow .pos {
  font-family: var(--font-head); font-weight: 900; font-size: 26px; text-align: right;
  /* flex-END: the number/medal hugs the RIGHT of its track, snug against the
     name — the pair that actually reads as one unit ("#7 JULES") — rather than
     snug against the arrow. Centering was the original bug (a single-digit "7"
     left most of its track's slack on one side or the other depending on
     content width); this picks WHICH side deliberately gets that leftover
     space: before the number, toward the arrow, never after it. So "1", "10"
     and a medal all sit the same fixed distance from .who — which never moves
     anyway, since its track start is fixed by column geometry, not by where a
     neighbor's content happens to end — at the cost of the arrow-to-number gap
     varying with digit count instead. */
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  /* the number reads as struck into the plate */
  text-shadow: 0 1px 0 rgba(255,250,226,.55), 0 -1px 0 rgba(88,50,0,.2);
}
.rankrow.lower .pos { text-shadow: 0 1px 0 rgba(0,0,0,.7), 0 -1px 0 rgba(255,240,205,.08); }
/* .medal's shared rule (also used by share cards, where centering is correct) carries
   `margin: 0 auto` — and a flex item's own auto margins win over the container's
   justify-content entirely, on whichever axis they're set. So top-3 rows kept
   centering their medal no matter what .pos's justify-content was told to do, while
   spots 4+ (a plain number, no auto margin) correctly obeyed it. Fixing the BOX
   alignment (margin:0) was step one — but the drawn "1/2/3" doesn't sit at the edge
   of its own artwork, it sits at the artwork's own horizontal CENTER (measured
   directly off Icons/1st|2nd|3rd.png: the numeral's center is at 49-50% of the image
   width, with the shield+crown themselves spanning ~18%-82%). object-fit:contain
   renders that artwork at exactly the box's own declared width here (40/30/32px
   across breakpoints — checked: it's always the constraining dimension), so with the
   box merely flush-right, the numeral still lands ~18% of the box's width short of
   where a right-aligned digit's own glyph sits. A negative margin-right pulls the
   WHOLE image — box and artwork together — right by that same 18%, so the artwork's
   own edge (not the transparent margin baked into the PNG) reaches exactly where a
   digit's edge already does. That's the ceiling on how close a shield-shaped icon and
   a bare digit can land: the shield still frames the numeral, so its OWN visual
   center sits a few px left of a flush digit's — but the two numerals now read as
   the same column instead of two different ones. */
.rankrow .pos .medal { margin: 0 -6px 0 0; }
.rankrow .pos .locknum { display: inline-flex; align-items: center; gap: 5px; }
.rankrow .lock { font-size: 15px; opacity: .85; }
.rankrow .who { display: flex; align-items: center; gap: 12px; min-width: 0; }
.rankrow .ava {
  width: 42px; height: 42px; border-radius: 50%; flex: 0 0 42px;
  display: flex; align-items: center; justify-content: center; font-size: 22px;
  border: 2px solid rgba(0,0,0,.25); overflow: hidden; background: #333;
}
.rankrow .ava img { width: 100%; height: 100%; object-fit: cover; }
/* presence light rides the avatar's lower-right, ringed in the plate's dark ink
   so the green reads cleanly against the gold row */
.rankrow .ava-wrap { position: relative; flex: none; display: inline-flex; line-height: 0; }
.rankrow .ava-dot {
  position: absolute; right: -1px; bottom: -1px; width: 12px; height: 12px;
  border: 1.5px solid rgba(20,14,6,.7); box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.rankrow .ava-dot.on {
  box-shadow: 0 0 7px rgba(43,216,95,.9), 0 1px 2px rgba(0,0,0,.45);
}
.rankrow .tagline { min-width: 0; }
.rankrow .tag {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  /* the brand face is an extended one and carries its own width — no extra tracking */
  font-size: clamp(14px, 2.4vw, 19px); letter-spacing: 0; line-height: 1.05;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* struck into the metal rather than dropped on it: a hairline of light along
     the lower edge of each letter, a whisper of shadow above */
  text-shadow: 0 1px 0 rgba(255,250,226,.6), 0 -1px 0 rgba(88,50,0,.22);
}
/* the crew line sits under the name in the brand face's Regular cut — light and
   wide against the Black name above it, so the two never compete */
.rankrow .crewtag {
  font-family: var(--font-head); font-weight: 400;
  font-size: 9px; letter-spacing: .2em; color: var(--ink-soft);
}
.rankrow .mains { display: flex; gap: 6px; font-size: 18px; justify-content: flex-end; }
/* just the character picture — no circle behind it */
.rankrow .mains .m {
  width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
}
.rankrow .paps {
  font-family: var(--font-head); font-weight: 900; font-size: clamp(9px, 1.5vw, 11px);
  letter-spacing: .08em; text-align: right; white-space: nowrap;
}
.rankrow .delta {
  /* flex-END: the arrow hugs the RIGHT of its track — the boundary it shares
     with the number — instead of floating in the middle of a track sized for
     it. Its own left/right slack no longer varies with anything, so it stops
     contributing to the arrow-number gap at all; only the grid's own column
     gap does, which is now the same fixed value in either direction. */
  display: flex; align-items: center; gap: 8px; justify-content: flex-end; padding: 0;
}

/* ---- the sliver of painting ------------------------------------------------
   The last arte a player bought, hung on the right end of their own plate. It is
   CROPPED on purpose: a 9:16 painting poured into a short, wide slot shows a band
   out of its middle — enough that you can tell it is a real picture and want to
   see the rest, never enough to actually see it. The point is the wanting.

   It bleeds through the row's padding to the plate's own rounded corner so it
   reads as part of the hardware rather than a thumbnail dropped on top, and the
   left edge is masked to nothing so the picture emerges out of the metal instead
   of starting at a hard seam.

   z-index 0 keeps it above the plate but under .rowactions (share / challenge /
   the challenger pill), which float over this same corner on hover. */
.rankrow .rowart {
  position: relative; z-index: 0;
  align-self: stretch;
  /* cancel the row's own padding on three sides, whatever it currently is */
  margin: calc(var(--row-pad-y) * -1) calc(var(--row-pad-x) * -1) calc(var(--row-pad-y) * -1) 0;
  border-radius: 0 var(--row-radius) var(--row-radius) 0;
  overflow: hidden;
  pointer-events: none;                 /* the whole row is the click target */
}
/* ABSOLUTE, not in flow. A 1536x2752 painting poured into a 106px-wide slot has an
   intrinsic height of ~190px, and an in-flow image would hand that height straight
   to the row — the ladder grew from 48px bars to 190px slabs the first time. Out of
   flow it can only ever fill the height the row already decided on. */
.rankrow .rowart img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Fades to nothing on the left, and eases off at the very top and bottom so the
     crop doesn't cut hard against the plate's bevel. */
  /* Dissolved on ALL FOUR sides. The right used to run flush into the plate's own
     rounded corner, which put a hard edge and a corner seam exactly where the eye
     lands; now the picture peaks in the middle of its slot and is gone before it
     reaches the edge, so it never has a corner to match in the first place. */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0%, rgba(0,0,0,.5) 20%, #000 46%, #000 72%, transparent 96%),
    linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-image:
    linear-gradient(90deg, transparent 0%, rgba(0,0,0,.5) 20%, #000 46%, #000 72%, transparent 96%),
    linear-gradient(180deg, transparent 0%, #000 12%, #000 88%, transparent 100%);
  /* Held back so the plate reads THROUGH the paint — the gold (or the graphite)
     comes up under it and the sliver looks set into the metal like something
     glassy, rather than a photograph laid on top of it. */
  opacity: .74;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* Nobody has painted anything yet: the track stays, empty. Reserving it rather
   than collapsing it keeps every row on the same column grid whether or not the
   player owns an arte — a board where one person has art must not be a board with
   one differently-shaped row. */
.rankrow .rowart.empty { background: none; }
/* Black stock gives the paint nothing to shine through, so it needs a little more
   of itself to survive — still short of solid, or the crystal effect is lost. */
.rankrow.lower .rowart img { opacity: .86; }
.recentwin {
  font-family: var(--font-head); font-style: italic;
  color: var(--red-hot); font-weight: 900; font-size: 17px;
  transform: rotate(-6deg); text-shadow: 1px 1px 0 rgba(0,0,0,.15);
}
.movebadge {
  width: 26px; height: 26px; flex: 0 0 26px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 900;
}
/* Movement is a bare triangle now, no plate behind it — the color alone carries
   the meaning (climbed / dropped / adjusted), and a naked glyph reads lighter on
   a row that's already carrying a lot of gold. */
.movebadge.up { color: var(--green); filter: drop-shadow(0 1px 1px rgba(0,0,0,.4)); }
.movebadge.down { color: var(--red); filter: drop-shadow(0 1px 1px rgba(0,0,0,.4)); }
.movebadge.adj { color: var(--gray); filter: drop-shadow(0 1px 1px rgba(0,0,0,.4)); }   /* moved without fighting (adjustment) */
/* The new-player star keeps its plate: it's a badge, not a movement arrow. */
.movebadge.new {
  border-radius: 50%; background: var(--ink); color: #fff; font-size: 10px;
  box-shadow: 0 3px 6px rgba(0,0,0,.35);
}

/* crown-shield medals for top 3 (Icons/1st|2nd|3rd.png) */
.medal { width: 40px; height: 46px; display: block; margin: 0 auto; object-fit: contain; filter: drop-shadow(0 3px 3px rgba(0,0,0,.35)); }

/* ---------- row hardware ----------
   The controls fitted to a plate, built in the plate's own language: a lit top
   face, one milled edge beneath, a hairline rim — just at button scale. They
   press into the row rather than sitting on it as stickers. */
/* z-index 2 puts the row's controls above .rowart. Both are positioned children of
   the same isolated row, so without it the painting — later in the DOM — would paint
   over the share and challenge buttons, which live in that same top-right corner. */
.rowactions { position: absolute; z-index: 2; right: 16px; top: -8px; display: flex; gap: 5px; align-items: center; }
.dot {
  width: 10px; height: 10px; border-radius: 50%; background: #6d675c;
  border: 1.5px solid #17120b;
  box-shadow: 0 1px 2px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.3);
}
.dot.on { background: #2bd85f; box-shadow: 0 0 7px rgba(43,216,95,.7), inset 0 1px 0 rgba(255,255,255,.45); }
.challenge-mini {
  font-family: var(--font-head); font-weight: 900; font-size: 8.5px; letter-spacing: .12em;
  text-transform: uppercase; color: #fff;
  background: linear-gradient(180deg, #f2596b 0%, var(--red) 46%, #c22132 100%);
  border: 0; border-radius: 6px; padding: 5px 10px 4px;
  text-shadow: 0 1px 0 rgba(94,10,20,.45);
  box-shadow:
    0 1px 0 #8d1522, 0 2px 4px rgba(0,0,0,.45),
    inset 0 1px 0 rgba(255,255,255,.36), inset 0 -1px 0 rgba(0,0,0,.24);
  transition: filter .1s ease, transform .08s ease, box-shadow .08s ease;
}
.challenge-mini:hover { filter: brightness(1.09); }
.challenge-mini:active {
  transform: translateY(1px);
  box-shadow: 0 0 0 #8d1522, 0 1px 2px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.18);
}
/* purge challenge buttons: violet, matching the purge pill and the purge backdrop */
.challenge-mini.risk {
  background: linear-gradient(180deg, #9b46e8 0%, #7d1fd6 46%, #55119b 100%);
  box-shadow: 0 1px 0 #3a0a69, 0 2px 4px rgba(0,0,0,.45),
    inset 0 1px 0 rgba(255,255,255,.3), inset 0 -1px 0 rgba(0,0,0,.26);
  text-shadow: 0 1px 0 rgba(40,6,72,.5);
}
.challenge-mini.risk:hover { filter: brightness(1.12); }
.btn.purgebtn {
  background: linear-gradient(180deg, #9b46e8 0%, #7d1fd6 46%, #55119b 100%);
  color: #fff; text-shadow: 0 1px 0 rgba(40,6,72,.5);
  box-shadow: 0 1px 0 #3a0a69, 0 2px 5px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.3), inset 0 -1px 0 rgba(0,0,0,.26);
}
/* wildcard challenge buttons: electric teal, matching the wildcard row */
.challenge-mini.wild {
  background: linear-gradient(180deg, #6ee7fb 0%, #22d3ee 46%, #0b8fb0 100%);
  color: #04303c;
  text-shadow: 0 1px 0 rgba(255,255,255,.28);
  box-shadow: 0 1px 0 #05586e, 0 2px 4px rgba(0,0,0,.45),
    inset 0 1px 0 rgba(255,255,255,.5), inset 0 -1px 0 rgba(0,0,0,.18);
}
.challenge-mini.wild:hover { filter: brightness(1.1); }
.btn.wildbtn {
  background: linear-gradient(180deg, #6ee7fb 0%, #22d3ee 46%, #0b8fb0 100%);
  color: #04303c; text-shadow: 0 1px 0 rgba(255,255,255,.28);
  box-shadow: 0 1px 0 #05586e, 0 2px 5px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.5), inset 0 -1px 0 rgba(0,0,0,.18);
}
/* crossed-swords marker: this player is already the target of a challenge.
   On hover it expands into a pill (like the challenge button) with the challenger + time left. */
.chbadge {
  height: 19px; min-width: 19px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center; overflow: hidden;
  background: linear-gradient(180deg, #241017, #150a0d);
  border: 1px solid var(--red); color: #ffb3ba;
  box-shadow: 0 1px 0 rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.08);
  cursor: default;
  transition: min-width .12s ease, padding .12s ease;
}
.chbadge .chswords { display: inline-flex; }
.chbadge .chswords .swordsicon { width: 13px; height: 13px; display: block; object-fit: contain; }
.chbadge .chpill {
  display: none; white-space: nowrap; padding: 0 8px;
  font-family: var(--font-head); font-weight: 900; font-size: 9px; letter-spacing: .04em;
  text-transform: uppercase; color: #fff;
}
/* the time inside the pill is plain text — not the dark .chtime chip from the panel */
.chbadge .chpill .chtime {
  background: none; border: none; padding: 0; border-radius: 0;
  color: #fff; font-size: inherit; letter-spacing: inherit;
}
/* Purge-born challenge: violet burn instead of the red swords — different stakes, different fire. */
.chbadge.purge {
  background: #16081f; border-color: #a34bff; color: #c99aff;
  box-shadow: 0 0 8px rgba(163, 75, 255, .55), 0 2px 5px rgba(0,0,0,.4);
  animation: purgeburn 1.6s ease-in-out infinite;
}
.chbadge.purge .streakflame { color: #b76bff; width: 12px; height: 12px; }
@keyframes purgeburn {
  0%, 100% { box-shadow: 0 0 5px rgba(163, 75, 255, .45), 0 2px 5px rgba(0,0,0,.4); }
  50%      { box-shadow: 0 0 12px rgba(163, 75, 255, .85), 0 2px 5px rgba(0,0,0,.4); }
}
/* Hover-capable devices reveal on hover; touch reveals via .reveal (first row tap).
   The :hover reveals live behind (hover: hover) so iOS never emulates them on tap —
   emulated hover that changes visibility makes Safari swallow the first click. */
@media (hover: hover) {
  .chbadge:hover { padding: 0; background: var(--red); border-color: var(--red); }
  .chbadge:hover .chswords { display: none; }
  .chbadge:hover .chpill { display: inline-block; }
  .rankrow:hover .sharebtn { display: inline-flex; }
}
.rankrow.reveal .chbadge { padding: 0; background: var(--red); border-color: var(--red); }
.rankrow.reveal .chbadge .chswords { display: none; }
.rankrow.reveal .chbadge .chpill { display: inline-block; }
/* expanded purge badge stays violet, not red */
@media (hover: hover) {
  .chbadge.purge:hover { background: #7d1fd6; border-color: #a34bff; }
}
.rankrow.reveal .chbadge.purge { background: #7d1fd6; border-color: #a34bff; }

/* share button — appears on row hover (desktop) or on the first row tap (touch: .reveal) */
.sharebtn {
  width: 21px; height: 21px; border-radius: 6px; flex: 0 0 21px; padding: 0;
  display: none; align-items: center; justify-content: center;
  background: linear-gradient(180deg, #241d15, #16110a);
  border: 1px solid #4a4034; color: #e9dcb8;
  box-shadow: 0 1px 0 rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.08);
  transition: border-color .1s ease, color .1s ease, transform .08s ease;
}
.sharebtn svg { width: 11px; height: 11px; display: block; }
.sharebtn:hover { border-color: var(--gold); color: var(--gold); }
.sharebtn:active { transform: translateY(1px); }
.rankrow.reveal .sharebtn { display: inline-flex; }
/* first-tap feedback on touch: the row lifts exactly like the desktop hover */
.rankrow.reveal { transform: translateY(-1px) scale(1.004); box-shadow: var(--row-lift-hi), var(--row-face); }

/* off-screen share card captured to an image */
/* Board poster — rebuilt in the new seal aesthetic: dark field with soft gold
   glows (no fire), a titled header, bullion rows, and a Gooby footer. Everything
   is html2canvas-safe: gradients + borders + text only, no box-shadow/blend. */
/* The frame is pinned to exactly 9:16 (660 × 1173) so the raster lands on
   1080×1920 with nothing letterboxed, and the body flexes to whatever the
   header and footer leave behind. */
.sharecard {
  position: fixed; left: -99999px; top: 0; width: 660px; height: 1173.33px; padding: 0; overflow: hidden;
  display: flex; flex-direction: column;
  background: #0b0a08; color: var(--text); font-family: var(--font-body);
}
/* head and foot keep their natural height come what may — left shrinkable they
   quietly absorb an oversized board, which hides the overrun instead of showing
   it. The body takes exactly what is left, and clips if the maths is ever off. */
.sharecard .sc-head, .sharecard .sc-foot { flex: none; }
.sharecard .sc-body {
  flex: 1 1 0; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
}
.sharecard .sc-glow {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(95% 34% at 50% 0%, rgba(246,194,67,.16), transparent 62%),
    radial-gradient(120% 40% at 50% 100%, rgba(246,194,67,.15), transparent 60%);
}
.sharecard > *:not(.sc-glow) { position: relative; z-index: 1; }
/* header */
/* --void makes the crest's margins describe visible air, so the padding here
   IS the gap you see above the crest (the PNG carries 14.07% empty pixels). */
.sharecard .sc-head { padding: 40px 34px 0; text-align: center; }
/* Ranking_Logo.png is a 1080×1080 square carrying ~14% empty pixels above and
   below the crest, so its layout box is much taller than the art you actually
   see and the crest reads as riding high. --void cancels that dead space, which
   makes the margins here describe the air you can really see — equal top and
   bottom, so the crest sits centred in the header. */
/* The crest is the mark, not the headline — it steps back so the board's name
   can lead. --void cancels the PNG's own empty top/bottom pixels (see above),
   so these margins describe air you can actually see. */
.sharecard .sc-logo {
  width: 148px; height: auto; display: block;
  --void: 20.8px;                       /* 14.07% of 148px */
  margin: calc(0px - var(--void)) auto calc(20px - var(--void));
}
/* rows — the plate height and everything scaled off it are handed down from
   cards.js as --g-h/--g-ava/--g-fs/--g-num, so ten rows and a folded pozo can
   share one frame without either being clipped. */
.sharecard .sc-rows { display: flex; flex-direction: column; gap: 9px; padding: 26px 30px 0; }
.sharecard .screrow {
  display: grid; grid-template-columns: 52px minmax(0,1fr) auto auto; gap: 13px; align-items: center;
  background: linear-gradient(180deg, #fff5d0 0%, #ffe093 9%, #f8c94e 40%, #f0b839 100%);
  border: 1px solid rgba(116,70,4,.4); border-radius: 13px; color: var(--ink);
  height: var(--g-h, 62px); padding: 0 18px;
}
.sharecard .screrow.me { background: linear-gradient(180deg, var(--cream-2), var(--cream)); }
.sharecard .screrow.lower {
  background: linear-gradient(180deg, #241f19, #191510); color: #f3ead2; border: 1px solid #34302a;
}
.sharecard .screrow.lower.me {
  background: linear-gradient(180deg, #37312a, #2a241e); color: #f3ead2; border: 1px solid #4a4237;
}
.sharecard .scpos { font-family: var(--font-head); font-weight: 900; font-size: var(--g-num, 26px); text-align: center; }
.sharecard .scpos .medal { width: calc(var(--g-ava, 42px) * .86); height: calc(var(--g-ava, 42px) * 1.01); }
.sharecard .scwho { display: flex; align-items: center; gap: 11px; min-width: 0; }
.sharecard .scwho .ava {
  width: var(--g-ava, 42px); height: var(--g-ava, 42px); flex: 0 0 var(--g-ava, 42px);
  border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center; border: 2px solid rgba(0,0,0,.28);
}
.sharecard .scwho .ava img { width: 100%; height: 100%; object-fit: cover; }
.sharecard .sctag { font-family: var(--font-head); font-weight: 900; text-transform: uppercase; font-size: var(--g-fs, 23px); line-height: 1; }
.sharecard .sccrew { font-size: 10px; font-weight: 800; letter-spacing: .2em; color: var(--ink-soft); margin-top: 2px; }
.sharecard .screrow.lower .sccrew { color: #8d7f5c; }
.sharecard .scmains { display: flex; gap: 5px; justify-content: flex-end; }
.sharecard .scm { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; }
.sharecard .scm .micon { width: 32px; height: 32px; }
/* wins as a compact stacked stat so it never wraps awkwardly */
.sharecard .scpaps { font-family: var(--font-head); text-align: right; line-height: 1; min-width: 58px; }
.sharecard .scpaps b { display: block; font-weight: 900; font-size: var(--g-num, 27px); }
.sharecard .scpaps span { display: block; font-size: 8.5px; font-weight: 900; letter-spacing: .14em; opacity: .72; margin-top: 3px; }
/* ---- the ladder running off the edge (my-spot card) ----------------------
   A plate cut off by the frame and dissolved into the field: the window keeps
   going, we just stopped printing. The row is laid absolutely inside a short
   clipped box so exactly PEEK of it shows, and a gradient in the card's own
   ground colour dissolves it toward the edge. Gradient over content, never a
   mask — html2canvas does not draw masks. */
.sharecard .sc-peek {
  position: relative; flex: none; overflow: hidden;
  height: calc(var(--g-h, 62px) * .45);
}
.sharecard .sc-peek .screrow { position: absolute; left: 0; right: 0; }
.sharecard .sc-peek.up .screrow { bottom: 0; }     /* the tail of the row above */
.sharecard .sc-peek.down .screrow { top: 0; }      /* the head of the row below */
.sharecard .sc-peek::after {
  content: ''; position: absolute; inset: -1px 0; pointer-events: none;
}
.sharecard .sc-peek.up::after { background: linear-gradient(to top, rgba(11,10,8,0) 4%, #0b0a08 86%); }
.sharecard .sc-peek.down::after { background: linear-gradient(to bottom, rgba(11,10,8,0) 4%, #0b0a08 86%); }

/* footer: Gooby + url + slogan on a soft glow, no fire */
.sharecard .sc-foot { text-align: center; padding: 22px 20px 26px; }
.sharecard .sc-seal { width: 56px; height: 56px; object-fit: contain; display: block; margin: 0 auto 10px; }
.sharecard .sc-url {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  letter-spacing: .22em; font-size: 15px; color: var(--cream); margin-left: .22em;
}
.sharecard .sc-slogan { font-family: var(--font-body); font-style: italic; font-size: 13px; color: #b9a877; margin-top: 8px; }

/* ---- the record block: mark, headline, ruled band, caption ----------------
   The board's NAME is the headline — the crest is the mark above it, not its
   rival. Below it a ruled band states the one thing the board can't say for
   itself (that it is closed), and a caption rule carries the facts with the
   dates on one end and the tallies on the other, so the block resolves on a
   different axis than it opened on. */
.sharecard .sc-band {
  display: flex; align-items: center; gap: 13px;
  font-family: var(--font-head); font-weight: 900; letter-spacing: .3em; text-transform: uppercase;
}
/* the rules point INTO the word rather than fading at both ends */
.sharecard .sc-band::before, .sharecard .sc-band::after { content: ''; flex: 1; height: 1px; }
.sharecard .sc-band::before { background: linear-gradient(90deg, transparent, rgba(201,169,79,.6)); }
.sharecard .sc-band::after { background: linear-gradient(90deg, rgba(201,169,79,.6), transparent); }

.sharecard .sc-title { text-align: center; }
/* line-height carries the tilde: OTOÑO, CAMPEÓN and friends set an accent above
   the cap line, and `overflow: hidden` (needed so fitText can measure the width)
   would shear it clean off at line-height 1. */
.sharecard .sc-sname {
  display: inline-block; max-width: 100%;
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 40px; line-height: 1.18; letter-spacing: -.005em; color: var(--cream);
  white-space: nowrap; overflow: hidden;
}
.sharecard .sc-status { margin: 14px 0 0; font-size: 12px; color: #d3b45f; }
.sharecard .sc-caption {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  margin-top: 13px; font-family: var(--font-head); font-weight: 900;
  font-size: 11px; letter-spacing: .17em; text-transform: uppercase; color: rgba(246,224,163,.42);
}
.sharecard .sc-caption span:last-child { text-align: right; }

/* ==========================================================================
   FULL BOARD — every spot in one frame. The gold zone keeps its bullion rows
   (just tighter), and the pozo folds into two columns whose row height is
   handed down from cards.js as --pz-h/--pz-fs/--pz-ava. The grid rows are
   1fr-inside-flex, so whatever the header really leaves is what they take —
   the JS figures only pick the type size, they can never clip the board.
   ========================================================================== */
.sharecard.full .sc-head { padding: 30px 30px 0; }
.sharecard.full .sc-logo { width: 104px; --void: 14.6px; margin: calc(0px - var(--void)) auto calc(13px - var(--void)); }
.sharecard.full .sc-sname { font-size: 32px; }
.sharecard.full .sc-status { margin-top: 10px; font-size: 11px; }
.sharecard.full .sc-caption { margin-top: 9px; font-size: 10px; }
.sharecard.full .sc-rows { gap: 5px; padding: 20px 26px 0; }
.sharecard.full .screrow {
  grid-template-columns: 40px minmax(0,1fr) auto auto; gap: 10px;
  height: var(--g-h, 46px); padding: 0 14px; border-radius: 10px;
}
.sharecard.full .scpos { font-size: var(--g-num, 21px); }
.sharecard.full .scpos .medal { width: calc(var(--g-ava, 32px) * .86); height: calc(var(--g-ava, 32px) * 1.01); }
.sharecard.full .scwho { gap: 9px; }
.sharecard.full .scwho .ava {
  width: var(--g-ava, 32px); height: var(--g-ava, 32px); flex: 0 0 var(--g-ava, 32px); border-width: 1.5px;
}
.sharecard.full .sctag { font-size: var(--g-fs, 19px); }
.sharecard.full .sccrew { font-size: 8.5px; margin-top: 1px; }
.sharecard.full .scm, .sharecard.full .scm .micon { width: calc(var(--g-ava, 32px) * .75); height: calc(var(--g-ava, 32px) * .75); }
.sharecard.full .scmains { gap: 4px; }
.sharecard.full .scpaps { min-width: 46px; }
.sharecard.full .scpaps b { font-size: var(--g-num, 21px); }
.sharecard.full .scpaps span { font-size: 7px; margin-top: 2px; }

/* the band that opens the pit — the same device as the header's status band */
.sharecard .sc-pozohead { margin: 13px 26px 8px; font-size: 12px; color: #c9a94f; }
/* Two columns filled DOWN the first, then the second — 11,12,13 reads
   top-to-bottom exactly as the board does. */
/* Inset well past the gold zone's margins, with a wide channel between the two
   columns: with no plate to contain it, a full-width row leaves a gulf between
   the tag and its count. Narrower columns close that gulf, and the indent says
   the pit is the lesser half of the board without spending any ink saying it. */
.sharecard .sc-pozo {
  flex: 1; min-height: 0; display: grid; gap: 6px 46px; padding: 0 46px;
  grid-auto-flow: column; grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(var(--pz-rows, 6), minmax(0, 1fr));
  max-height: calc(var(--pz-rows, 6) * (var(--pz-h, 30px) + 6px));
}
/* No plate behind a pozo row. Twenty-odd boxes stacked two-wide read as a wall;
   set naked on the dark field they read as a list, and the contrast against the
   bullion above becomes the point — the gold zone is struck metal, the pit is
   just names waiting to climb. Alignment carries the structure instead: number,
   face, tag, count, on a shared grid down each column. */
.sharecard .pzrow {
  display: grid; grid-template-columns: var(--pz-num-col, 26px) auto minmax(0,1fr) auto;
  align-items: center; gap: 9px; min-width: 0; overflow: hidden;
  padding: 0 4px; color: #cdbfa0;
}
/* Your own row is found by weight and colour, not by a box around it. */
.sharecard .pzrow.me { color: var(--cream); }
.sharecard .pzrow.me .pznum, .sharecard .pzrow.me .pzw { color: #f6c243; }
.sharecard .pznum {
  font-family: var(--font-head); font-weight: 900; font-size: var(--pz-num, 13px);
  color: #7d7259; text-align: right;
}
.sharecard .pzrow .pzava {
  width: var(--pz-ava, 22px); height: var(--pz-ava, 22px); flex: none;
  border-radius: 50%; overflow: hidden; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(0,0,0,.35);
}
.sharecard .pzrow .pzava img { width: 100%; height: 100%; object-fit: cover; }
/* line-height 1.2, not 1: NIÑO RATA and MUÑECOTRONIC set a tilde above the cap
   line and `overflow: hidden` would shear it off (same fix as .sc-sname). */
.sharecard .pztag {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: var(--pz-fs, 14px); line-height: 1.2; white-space: nowrap; overflow: hidden;
}
.sharecard .pzw {
  font-family: var(--font-head); font-weight: 900; font-size: var(--pz-fs, 14px);
  color: #9c8a5f; text-align: right;
}
.sharecard .sc-more {
  font-family: var(--font-head); font-weight: 900; font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: rgba(255,255,255,.42); text-align: center; margin-top: 8px;
}
.sharecard.full .sc-foot { padding: 14px 20px 20px; }
.sharecard.full .sc-seal { width: 44px; height: 44px; margin-bottom: 8px; }
.sharecard.full .sc-url { font-size: 13px; }
.sharecard.full .sc-slogan { font-size: 11px; margin-top: 5px; }

.board-hint {
  text-align: center; color: #cdb372; font-size: 13px; padding: 8px;
}

/* ---------- wildcard power: teal electric-blue row until the fight happens ----------
   The same milled plate, struck in polished chrome-teal so the power reads as rare. */
.rankrow.wildcard {
  --row-edge: #12a3c2;
  --row-edge-deep: #05485a;
  background:
    var(--metal-grain) calc(var(--n, 0) * 23px) calc(var(--n, 0) * 17px) / 120px 120px repeat,
    linear-gradient(180deg, #b6f6ff 0%, #56ddf5 9%, #22d3ee 34%, #17bcdd 62%, #109fc4 86%, #0a8fb3 100%) no-repeat;
  background-blend-mode: soft-light, normal;
  box-shadow: var(--row-lift), 0 0 22px rgba(34,211,238,.55);
  color: #06303a;
  animation: wildpulse 1.8s ease-in-out infinite;
}
.rankrow.wildcard .tag { text-shadow: 0 1px 0 rgba(233,254,255,.6), 0 -1px 0 rgba(3,60,76,.25); }
.rankrow.wildcard .crewtag { color: #0a4a58; }
@keyframes wildpulse {
  0%,100% { box-shadow: var(--row-lift), 0 0 18px rgba(34,211,238,.45); }
  50%     { box-shadow: var(--row-lift), 0 0 30px rgba(34,211,238,.8); }
}

/* ---------- Purge mode: no imagery (no animals, no flames) — deep purge purple ---------- */
body.purge-on .fire-bg { background: #2a0a45; }
body.purge-on .header-bg { display: none; }
body.purge-on .footer { background: none; }

/* ---------- Voyeur: spectate + bet ---------- */
/* hidden until the row is hovered (desktop) or first-tapped (touch: .reveal), like .sharebtn */
.vypill {
  display: none; align-items: center; height: 19px; border-radius: 6px; padding: 0 8px; cursor: pointer;
  font-family: var(--font-head); font-weight: 900; font-size: 8px; letter-spacing: .14em;
  background: linear-gradient(180deg, #2b1642, #180d26);
  border: 1px solid #8850c9; color: #dcbcff;
  box-shadow: 0 1px 0 rgba(0,0,0,.5), 0 2px 4px rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.09);
  transition: background .1s ease, color .1s ease, border-color .1s ease, transform .08s ease;
}
.vypill:hover { background: linear-gradient(180deg, #8b2fe0, #6415ac); color: #fff; border-color: #b76bff; }
.vypill:active { transform: translateY(1px); }
@media (hover: hover) { .rankrow:hover .vypill { display: inline-flex; } }
.rankrow.reveal .vypill { display: inline-flex; }
.voy-wrap { max-width: 880px; margin: 12px auto; }
.voy-head {
  display: grid; grid-template-columns: auto minmax(0,1fr) auto minmax(0,1fr) auto;
  gap: 12px; align-items: center; margin-top: 10px;
}
/* the big set score sits centered against the name + bet-pills block */
.voy-score {
  font-family: var(--font-head); font-weight: 900; font-size: 60px; line-height: 1;
  color: #fff; min-width: 52px; text-align: center; align-self: center;
}
.voy-vs { font-family: var(--font-head); font-weight: 900; font-size: 18px; color: var(--red); }
.voy-side { display: flex; flex-direction: column; gap: 6px; align-items: center; text-align: center; min-width: 0; }
.voy-name {
  display: flex; gap: 8px; align-items: center; justify-content: center;
  max-width: 100%; min-width: 0;
  font-family: var(--font-head); font-weight: 900; font-size: 18px;
}
.voy-name small { color: #8d7f5c; flex: none; }
.voy-name .dotava { flex: none; }
/* the tag is the one part that gives: it truncates so the row can't overrun its column */
.voy-tag { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* not in the ring yet: greyed out until they come online */
.voy-name.off { color: #6d6f74; }
.voy-name.off .dotava { filter: grayscale(1); opacity: .6; }
/* bets row: tiny pills inline with the running pot total, mirrored per side
   (left = pills…total, right = total…pills) */
.voy-bets { display: flex; gap: 4px; justify-content: center; align-items: center; }
.voy-pot {
  font-family: var(--font-head); font-weight: 900; font-size: 13px; line-height: 1;
  color: var(--gold); padding: 0 3px;
}
.betpill {
  border: 1px solid var(--gold); background: #14100a; color: var(--gold);
  border-radius: 999px; padding: 0 5px; cursor: pointer; line-height: 1.6;
  font-family: var(--font-head); font-weight: 900; font-size: 8px;
}
.betpill:hover:not(:disabled) { background: var(--gold); color: #14100a; }
.betpill:disabled { opacity: .35; cursor: default; }
.betpill.sel { background: var(--gold); color: #14100a; opacity: 1; }
.voy-note { text-align: center; color: #b8ab84; font-size: 13px; margin: 10px 0; }
.voy-banner {
  text-align: center; margin: 16px 0 6px;
  font-family: var(--font-head); font-weight: 900; font-size: 26px; color: var(--gold);
}
.voy-final {
  text-align: center; margin: 0 0 14px;
  font-family: var(--font-head); font-weight: 900; font-size: 34px; color: #fff;
}
.voy-games { display: flex; gap: 8px; justify-content: center; margin-top: 10px; flex-wrap: wrap; }
.voy-g {
  border: 1px solid #3a332a; border-radius: 6px; padding: 3px 8px;
  font-size: 11px; color: #d8cba0;
}
@media (max-width: 700px) {
  /* Keep the single-row matchup (score · fighter · VS · fighter · score) — just scale it
     down so it fits a phone. minmax(0,1fr) lets the fighter columns shrink instead of
     shoving the right side onto its own line. */
  .voy-head { grid-template-columns: auto minmax(0,1fr) auto minmax(0,1fr) auto; gap: 5px; }
  .voy-score { font-size: 34px; min-width: 22px; }
  .voy-vs { font-size: 13px; }
  .voy-side { min-width: 0; gap: 4px; }
  .voy-name { font-size: 12px; gap: 3px; flex-wrap: wrap; justify-content: center; line-height: 1.15; }
  .voy-name small { font-size: 10px; }
  .voy-name .dotava { width: 15px; height: 15px; flex: 0 0 15px; }
  .voy-pot { font-size: 10px; padding: 0 2px; }
  .voy-bets { gap: 2px; flex-wrap: wrap; }
  .betpill { font-size: 7px; padding: 0 4px; }
}
/* Very narrow phones: trim a touch more so nothing clips. */
@media (max-width: 380px) {
  .voy-head { gap: 3px; }
  .voy-score { font-size: 30px; min-width: 18px; }
  .voy-name { font-size: 11px; }
  .betpill { padding: 0 3px; }
}

/* ---------- streak / racha ---------- */
/* .streakflame is the flame icon (an img) in streak contexts, and the SVG flame
   in Purge contexts — both size off the surrounding type. */
.streakflame {
  color: #ff7a1a; display: inline-block; vertical-align: middle;
  width: 1.7em; height: 1.7em; object-fit: contain; margin-right: -.16em;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));
}
/* In the streak lockups the flame is sized to the digit (not towering over it)
   and nudged up a hair so its mass optically centres on the number's cap height. */
.rnum .streakflame, .ps-num .streakflame {
  width: .87em; height: .87em; margin-right: 0; transform: translateY(-.03em);
}
/* Racha badge beside the profile name: color when they played today, grey + tiny note otherwise. */
.ptag-streak {
  display: inline-flex; align-items: center; gap: 7px; vertical-align: middle;
  margin-left: 12px; transform: translateY(-2px);
}
.ptag-streak .ps-num {
  display: inline-flex; align-items: center; gap: 0;
  font-family: var(--font-head); font-weight: 900; font-size: 22px; line-height: 1;
}
.ptag-streak.on .ps-num { color: var(--gold); }
/* the crest is a picture now, so a dead streak greys it out instead of recolouring */
.ptag-streak.off .ps-num { color: #6d6f74; }
.ptag-streak.off .streakflame { filter: grayscale(1); opacity: .45; }
.ptag-streak .ps-note {
  font-family: var(--font-body); font-size: 8.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: #8b8f96; line-height: 1.2; text-align: left; white-space: nowrap;
}
/* On phones the streak drops to its own tidy line under the name instead of
   wrapping cramped against it (the note stays on one line). */
@media (max-width: 560px) {
  .profile-id .ptag { row-gap: 8px; }
  .ptag-streak { flex-basis: 100%; margin-left: 0; margin-top: 2px; transform: none; }
}
/* header logo <-> racha crossfade */
.topbar-logo { position: relative; }
.topbar-logo .logo-img, .topbar-logo .racha { transition: opacity .6s ease; }
.topbar-logo .racha {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; opacity: 0; pointer-events: none; color: #9aa0a6;
}
.topbar-logo.show-racha .logo-img { opacity: 0; }
.topbar-logo.show-racha .racha { opacity: 1; }
.topbar-logo .racha .rnum {
  font-family: var(--font-head); font-weight: 900; font-size: clamp(38px, 8vw, 58px); line-height: 1;
  display: inline-flex; align-items: center; gap: 0; color: #b8bcc2;
}
/* dead streak: the crest goes cold rather than changing colour (it is an image) */
.topbar-logo .racha .rnum .streakflame { color: #8b8f96; filter: grayscale(1); opacity: .5; }
.topbar-logo .racha .rprompt {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase; letter-spacing: .04em;
  font-size: 11px; color: #8b8f96; max-width: 240px;
}
/* already fought today → the streak burns in color */
.topbar-logo .racha.alive .rnum { color: var(--gold); }
.topbar-logo .racha.alive .rnum .streakflame {
  color: #ff7a1a; filter: none; opacity: 1;
  /* a live streak throws a little heat */
  filter: drop-shadow(0 0 7px rgba(246,194,67,.55));
}
/* hovering the logo also reveals the racha */
.topbar-logo:has(.racha):hover .logo-img { opacity: 0; }
.topbar-logo:has(.racha):hover .racha { opacity: 1; }

/* Brand display font — the whole UI's heading face (--font-head) and the share
   posters. Black covers the 700-900 headings; Bold gives the lighter labels
   (nav, kickers, the zone bands) their own cut instead of faking one. */
@font-face {
  font-family: 'PP Monument Extended';
  src: url('/fonts/PPMonumentExtended-Black.otf') format('opentype');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Monument Extended';
  src: url('/fonts/PPMonumentExtended-Bold.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PP Monument Extended';
  src: url('/fonts/PPMonumentExtended-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- "Retado" challenge poster — CSS-built to match the board card, with a
   red battle-glow. Names are fitted in JS. html2canvas-safe (gradients/borders/text). */
.retadocard {
  position: fixed; left: -99999px; top: 0; width: 660px; overflow: hidden;
  background: #0b0a08; color: #fff; font-family: var(--font-head);
}
/* gold at the crown, red heat rising from the floor — the challenge's tension */
.retadocard .sc-glow {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(90% 30% at 50% 0%, rgba(246,194,67,.15), transparent 60%),
    radial-gradient(125% 46% at 50% 100%, rgba(224,52,72,.24), transparent 62%);
}
.retadocard .rt-inner {
  position: relative; z-index: 1; min-height: 1180px;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 34px 44px 40px;
}
.retadocard .sc-strip {
  width: 100%; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  font-weight: 900; letter-spacing: .2em; font-size: 13px;
  color: rgba(255,255,255,.78); text-transform: uppercase;
}
.retadocard .sc-strip span:first-child { text-align: left; }
.retadocard .sc-strip span:last-child { text-align: right; }
/* the challenge block, vertically centred between strip and footer */
.retadocard .rt-mid { margin: auto 0; width: 100%; display: flex; flex-direction: column; align-items: center; }
.retadocard .rt-swords { width: 82px; height: 82px; color: var(--red); margin-bottom: 26px; }
.retadocard .rt-swords svg { width: 100%; height: 100%; filter: drop-shadow(0 0 14px rgba(224,52,72,.5)); }
.retadocard .rt-target {
  max-width: 100%; font-weight: 900; font-size: 50px; letter-spacing: -0.01em; line-height: 1;
  font-family: 'PP Monument Extended', var(--font-head);
  text-transform: uppercase; color: var(--cream); white-space: nowrap; overflow: hidden;
}
.retadocard .rt-line {
  font-family: 'PP Monument Extended', var(--font-head); font-weight: 400;
  font-size: 15px; letter-spacing: .16em; text-transform: uppercase; color: #b9a877;
  margin: 20px 0; white-space: nowrap;
}
.retadocard .rt-challenger {
  max-width: 100%; font-weight: 900; font-size: 92px; letter-spacing: -0.02em; line-height: .95;
  font-family: 'PP Monument Extended', var(--font-head);
  text-transform: uppercase; color: #fff; white-space: nowrap; overflow: hidden;
  text-shadow: 0 0 34px rgba(246,194,67,.16);
}
.retadocard .rt-chips { display: flex; justify-content: center; gap: 12px; margin-top: 30px; }
.retadocard .rt-chips span {
  border: 2px solid var(--red); border-radius: 9px; padding: 7px 14px;
  font-weight: 900; font-size: 15px; letter-spacing: .04em; text-transform: uppercase;
  color: #fff; background: rgba(224,52,72,.1); white-space: nowrap;
}
.retadocard .rt-foot { text-align: center; }
.retadocard .rt-url {
  font-weight: 900; text-transform: uppercase; letter-spacing: .22em; font-size: 15px;
  color: var(--cream); margin-left: .22em;
}
.retadocard .rt-slogan {
  font-family: var(--font-body); font-style: italic; font-size: 13px; color: #b9a877; margin-top: 8px;
}

/* ---------- out-of-top-10: blacked-out profile accents (contrast-safe) ---------- */
/* The figure strip is gold-on-dark for everyone, so open-zone only cools the crew
   chip and headings — the numbers stay the brand accent. */
.card.rank-open .crewchip { background: #14100a; color: #f3ead2; border: 1px solid #3a332a; box-shadow: none; }
.card.rank-open h2, .card.rank-open .section-title { color: #d8cba0; }
.card.rank-open .mainwr { color: #d8cba0; }
.card.rank-open .profile-ava { border-color: #3a332a; }

/* share: two-button choice (top 10 / my spot) */
.sharemenu { display: inline-flex; gap: 4px; }
/* while the three-way share menu is open it owns the row's action strip — the
   challenge button and the challenged marker would push it off a phone screen */
.rowactions.menu-open > :not(.sharemenu) { display: none; }
.sharebtn2 {
  font-family: var(--font-head); font-weight: 900; font-size: 9px; letter-spacing: .04em;
  background: #14100a; color: var(--gold); border: 2px solid var(--gold); border-radius: 8px;
  padding: 3px 8px; text-transform: uppercase; white-space: nowrap;
}
.sharebtn2:hover { background: var(--gold); color: #14100a; }

/* ---------- cards / forms ---------- */
.card {
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: var(--radius); padding: 26px; box-shadow: var(--shadow);
  max-width: 520px; margin: 22px auto;
}
.card.wide { max-width: 980px; }
.card h2 {
  font-family: var(--font-head); text-transform: uppercase; letter-spacing: .04em;
  color: var(--gold); margin-bottom: 18px; font-size: 24px;
}
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: #b9a877; margin-bottom: 5px; font-weight: 700; }
.field input {
  width: 100%; padding: 11px 13px; border-radius: 10px; border: 1px solid #3a332a;
  background: #0f0d0a; color: var(--text); font-size: 15px; font-family: inherit;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.field input::placeholder { color: #7d7361; }
.field input:focus {
  outline: none; border-color: var(--gold);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5), 0 0 0 3px rgba(246,194,67,.22);
}
/* Buttons are the row hardware at full size: a lit face, one milled edge, a
   hairline rim, and a real press. Default is dark stock; .gold is a struck plate. */
.btn {
  display: inline-block; border: none; border-radius: 10px; padding: 12px 22px;
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  letter-spacing: .1em; font-size: 12.5px;
  background: linear-gradient(180deg, #2c251b, #1a150e);
  color: var(--text);
  box-shadow:
    0 1px 0 #0a0806, 0 2px 5px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,240,205,.13), inset 0 -1px 0 rgba(0,0,0,.4);
  transition: filter .1s ease, transform .08s ease, box-shadow .08s ease, border-color .1s ease, color .1s ease;
}
.btn:hover:not(:disabled) { filter: brightness(1.14); }
.btn:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: 0 0 0 #0a0806, 0 1px 2px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,240,205,.08);
}
.btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* the primary action is a small bullion plate, same face as the board rows */
.btn.gold {
  background: linear-gradient(180deg, #fff5d0 0%, #ffe093 8%, #fbd062 32%, #f7c649 58%, #f0b839 84%, #e5ab2e 100%);
  color: var(--ink);
  text-shadow: 0 1px 0 rgba(255,250,226,.5);
  box-shadow:
    0 1px 0 var(--row-edge), 0 2px 0 var(--row-edge-deep), 0 3px 6px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,251,232,.6), inset 0 -1px 0 rgba(116,70,4,.3);
}
.btn.gold:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: 0 0 0 var(--row-edge), 0 1px 0 var(--row-edge-deep), 0 1px 3px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,251,232,.4);
}
.btn.red {
  background: linear-gradient(180deg, #f2596b 0%, var(--red) 46%, #c22132 100%);
  color: #fff; text-shadow: 0 1px 0 rgba(94,10,20,.45);
  box-shadow: 0 1px 0 #8d1522, 0 2px 5px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.34), inset 0 -1px 0 rgba(0,0,0,.26);
}
.btn.green {
  background: linear-gradient(180deg, #4ad47a 0%, var(--green) 46%, #157a35 100%);
  color: #06240f; text-shadow: 0 1px 0 rgba(255,255,255,.22);
  box-shadow: 0 1px 0 #0d5323, 0 2px 5px rgba(0,0,0,.5),
    inset 0 1px 0 rgba(255,255,255,.4), inset 0 -1px 0 rgba(0,0,0,.2);
}
.btn.ghost {
  background: transparent; border: 1px solid #4a4034; color: var(--text);
  box-shadow: none;
}
.btn.ghost:hover:not(:disabled) { border-color: var(--gold); color: var(--gold); filter: none; }
.btn.block { width: 100%; text-align: center; }
/* leaving a season is real, but it isn't a peer of VER RANKING or ADMINISTRAR PLAN —
   tiny, flat, greyed, and pushed to the far end of the row so it never competes with
   the buttons a player actually came here to press. */
.btn.leave-season {
  margin-left: auto; order: 99;
  font-size: 8px; padding: 4px 9px; letter-spacing: .1em; border-radius: 999px;
  background: none; box-shadow: none;
  color: #6b6558; border: 1px solid rgba(120,113,96,.3); opacity: .7;
}
.btn.leave-season:hover:not(:disabled) {
  opacity: 1; color: #cfc9ba; border-color: rgba(120,113,96,.6); filter: none;
}
.btn:disabled { opacity: .45; cursor: not-allowed; }
.form-error { color: #ff7b6e; font-size: 13px; margin: 8px 0; min-height: 17px; }
.form-alt { margin-top: 14px; font-size: 13px; color: #b9a877; text-align: center; }
.form-alt a { color: var(--gold); font-weight: 700; }

/* avatar picker */
.avagrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(52px, 1fr)); gap: 8px; margin: 8px 0; }
.avagrid .opt {
  width: 100%; aspect-ratio: 1; border-radius: 50%; border: 3px solid transparent;
  display: flex; align-items: center; justify-content: center; font-size: 24px;
  background: #222; overflow: hidden;
}
.avagrid .opt.sel { border-color: var(--gold); box-shadow: 0 0 12px rgba(246,194,67,.5); }
.upload-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; font-size: 13px; color: #b9a877; flex-wrap: wrap; }
.upload-preview { width: 52px; height: 52px; border-radius: 50%; object-fit: cover; border: 3px solid var(--gold); display: none; }

/* ---------- profile ----------
   Same material system as the board: the identity block sits on dark stock, the
   record reads on struck plates, and the history is one sheet with hairlines
   rather than a stack of outlined boxes. */
.profile-head {
  display: flex; gap: 22px; align-items: center; flex-wrap: wrap;
  padding-bottom: 22px; border-bottom: 1px solid #262019;
}
.profile-ava {
  width: 92px; height: 92px; border-radius: 50%; overflow: hidden; flex: 0 0 92px;
  display: flex; align-items: center; justify-content: center; font-size: 50px;
  background: #222;
  /* a machined bezel instead of a blunt 4px ring */
  border: 1px solid rgba(246,194,67,.55);
  box-shadow: 0 0 0 4px #14110c, 0 6px 16px -6px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,.14);
}
.profile-ava img { width: 100%; height: 100%; object-fit: cover; }
/* presence light rides the lower-right of the avatar, punched out with a ring
   in the avatar's own bezel colour so it reads as a badge, not a sticker */
.pava-wrap { position: relative; flex: 0 0 92px; align-self: center; }
.pres {
  position: absolute; right: 3px; bottom: 5px; width: 20px; height: 20px;
  border-radius: 50%; background: #6d675c; border: 3px solid #14110c;
  box-shadow: 0 1px 3px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.25);
}
.pres.on {
  background: #2bd85f;
  box-shadow: 0 0 11px rgba(43,216,95,.75), 0 1px 3px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.4);
}
.pstatus { text-transform: uppercase; letter-spacing: .1em; font-weight: 700; }
.pstatus.on { color: #2bd85f; }
.pstatus.off { color: #8a7f66; }
.profile-ava > span {
  width: 100%; height: 100%; display: flex; align-items: center;
  justify-content: center; font-size: 50px;
}
.profile-id { min-width: 0; }
.profile-id .ptag {
  font-family: var(--font-head); font-size: clamp(22px, 3.4vw, 30px);
  text-transform: uppercase; color: #fff; line-height: 1.05; letter-spacing: 0;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.profile-id .pname { color: #b9a877; margin-top: 7px; font-size: 14px; }
.crewchip {
  display: inline-block; background: linear-gradient(180deg, #fbd062, #e5ab2e);
  color: var(--ink); border-radius: 6px;
  font-family: var(--font-head); font-weight: 900; font-size: 9px; padding: 4px 8px;
  letter-spacing: .2em; vertical-align: middle;
  box-shadow: 0 1px 0 var(--row-edge-deep), inset 0 1px 0 rgba(255,251,232,.6);
}
/* The record: no boxes. A broadcast-style figure strip — big gold numerals ruled
   off by hairlines, rank featured — then a slim win-rate meter that folds the two
   redundant percentages into one bar. */
.statline {
  display: flex; align-items: stretch; margin: 22px 0 4px;
  border-top: 1px solid #262019; border-bottom: 1px solid #262019;
}
.fig {
  flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 7px; padding: 18px 8px; text-align: center;
  border-left: 1px solid #211c15;
}
.fig:first-child { border-left: 0; }
/* the featured rank needs room for a leading # plus two digits without crowding */
.fig.lead { flex: 1.4; }
.fig .v {
  font-family: var(--font-head); font-weight: 900; line-height: 1; color: var(--gold);
  font-size: clamp(25px, 4vw, 33px); font-variant-numeric: tabular-nums; letter-spacing: -.01em;
  white-space: nowrap;
}
.fig.lead .v { font-size: clamp(32px, 5vw, 42px); color: #ffd76d; }
.fig .k {
  font-family: var(--font-head); font-weight: 400; font-size: 8.5px; letter-spacing: .2em;
  text-transform: uppercase; color: #8d7f5c;
}
.fig .k .ksub { display: block; font-size: 7px; letter-spacing: .04em; text-transform: none; opacity: .75; margin-top: 2px; }

.winmeter { margin: 20px 0 4px; }
.wm-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 9px; }
.wm-head .k {
  font-family: var(--font-head); font-weight: 400; font-size: 8.5px; letter-spacing: .2em;
  text-transform: uppercase; color: #8d7f5c;
}
.wm-val {
  font-family: var(--font-head); font-weight: 900; font-size: 17px; color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.wm-track {
  height: 7px; border-radius: 999px; background: #0f0d0a; overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.7);
}
.wm-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #e5ab2e, #f6c243 60%, #ffd76d);
  box-shadow: 0 0 8px rgba(246,194,67,.4), inset 0 1px 0 rgba(255,255,255,.35);
}
@media (prefers-reduced-motion: no-preference) {
  .wm-fill { animation: wmfill .9s cubic-bezier(.16,1,.3,1) both; }
  @keyframes wmfill { from { width: 0; } }
}
/* Narrow screens: a 4-across strip crowds a 4-digit aura, so fold it into a neat
   2x2 block (rank stays featured, top-left) with hairline grid rules. */
@media (max-width: 560px) {
  .statline { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid #262019; border-radius: 12px; }
  .fig { border-left: 1px solid #211c15; border-top: 1px solid #211c15; padding: 16px 10px; }
  .fig:nth-child(1), .fig:nth-child(2) { border-top: 0; }
  .fig:nth-child(odd) { border-left: 0; }
  .fig.lead .v { font-size: 36px; }
}
.mainschips { display: flex; gap: 8px; flex-wrap: wrap; }
.mainchip {
  background: linear-gradient(180deg, #2a231a, #1a150e); border: 1px solid #453b2c;
  padding: 7px 12px; border-radius: 8px;
  display: inline-flex; gap: 8px; align-items: center; font-weight: 600; font-size: 13px;
  box-shadow: 0 1px 0 rgba(0,0,0,.5), inset 0 1px 0 rgba(255,240,205,.08);
}
/* one sheet, hairline-ruled, so a long record stays calm */
.history {
  margin-top: 10px; background: #14110d; border: 1px solid #262019; border-radius: 12px;
  overflow: hidden;
}
.hrow {
  display: flex; gap: 12px; align-items: center; padding: 11px 15px; font-size: 14px; flex-wrap: wrap;
  border-top: 1px solid #221d16;
}
.hrow:first-child { border-top: 0; }
.hrow .res {
  font-family: var(--font-head); font-weight: 900; font-size: 9px; letter-spacing: .14em;
  width: auto; min-width: 62px; padding: 4px 8px; border-radius: 5px; text-align: center;
}
.hrow .res.w { color: #7ff0a6; background: rgba(31,174,75,.16); box-shadow: inset 0 0 0 1px rgba(31,174,75,.35); }
.hrow .res.l { color: #ffa3ae; background: rgba(224,52,72,.14); box-shadow: inset 0 0 0 1px rgba(224,52,72,.32); }
.hrow .score { font-family: var(--font-head); font-weight: 900; font-variant-numeric: tabular-nums; }
.hrow .score i { font-style: normal; color: #7d7361; margin: 0 3px; }   /* score separator, not a dash glyph */
.hrow .date { margin-left: auto; color: #8d7f5c; font-size: 11px; letter-spacing: .04em; }
.hshare { border: 1px solid var(--card-border); background: transparent; color: #8d7f5c;
  border-radius: 7px; width: 27px; height: 27px; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.hshare svg { width: 13px; height: 13px; }
.hshare:hover { color: var(--gold); border-color: var(--gold); }
.hshare:active { transform: translateY(1px); }
/* section headings echo the board's zone bands */
.section-title {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-head); font-weight: 700; text-transform: uppercase; color: var(--gold);
  letter-spacing: .24em; margin: 28px 0 12px; font-size: 10px;
}
.section-title::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, currentColor, transparent); opacity: .35;
}

/* ---------- players list ---------- */
.playerlist { display: flex; flex-direction: column; gap: 8px; }
.prow {
  display: flex; align-items: center; gap: 12px; background: #14110d;
  border: 1px solid #262019; border-radius: 12px; padding: 10px 14px;
}
.prow .ava { width: 36px; height: 36px; border-radius: 50%; overflow: hidden; display: flex; align-items: center; justify-content: center; font-size: 18px; background: #333; flex: 0 0 36px; }
.prow .ava img { width: 100%; height: 100%; object-fit: cover; }
.prow .nm { font-family: var(--font-head); font-weight: 900; text-transform: uppercase; }
.prow .st { font-size: 12px; color: #8d7f5c; margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* ---------- match screen ---------- */
.match-wrap { display: grid; grid-template-columns: 1.6fr 1fr; gap: 16px; margin-top: 10px; }
@media (max-width: 840px) { .match-wrap { grid-template-columns: 1fr; } }
.match-main, .match-chat {
  background: var(--card); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 20px; box-shadow: var(--shadow);
}
.match-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.match-vs { display: flex; align-items: center; gap: 12px; font-family: var(--font-head); font-weight: 900; font-size: clamp(16px, 3vw, 22px); text-transform: uppercase; }
.match-vs .sc { background: var(--gold); color: #14100a; border-radius: 10px; padding: 4px 12px; font-size: clamp(16px, 3vw, 22px); }
.match-vs .pn.me { color: var(--gold); }
.phase-banner {
  background: linear-gradient(180deg, var(--gold-row), var(--gold-row-2)); color: var(--ink);
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase; letter-spacing: .05em;
  padding: 10px 16px; border-radius: 12px; margin-bottom: 14px; font-size: 15px;
  display: flex; justify-content: space-between; gap: 8px; align-items: center; flex-wrap: wrap;
}
.phase-sub { font-size: 12px; font-weight: 700; color: var(--ink-soft); letter-spacing: .02em; text-transform: none; }
.stagegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.stagecard {
  position: relative; overflow: hidden; border: 2px solid #3a332a; border-radius: 14px;
  padding: 0; min-height: 104px; background-color: #14110d;
  background-size: cover; background-position: center;
  transition: transform .12s ease, border-color .12s ease, box-shadow .12s ease;
}
.stagecard .scrim {
  position: absolute; inset: 0; background: rgba(0,0,0,.5);
  transition: background .12s ease;
}
.stagecard .sname {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #fff; font-family: var(--font-head); font-weight: 900; font-size: 15px;
  text-transform: uppercase; letter-spacing: .04em; text-align: center; padding: 8px;
  text-shadow: 0 2px 8px rgba(0,0,0,.8);
}
.stagecard:not(:disabled):hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: 0 8px 18px rgba(0,0,0,.5); }
.stagecard:not(:disabled):hover .scrim { background: rgba(0,0,0,.32); }
.stagecard.struck { cursor: not-allowed; border-color: rgba(224,52,72,.7); }
.stagecard.struck .scrim { background: rgba(0,0,0,.78); }
.stagecard.struck .sname { text-decoration: line-through; color: rgba(255,255,255,.45); }
.stagecard.struck::after {
  content: '✕'; position: absolute; top: 6px; right: 10px; color: var(--red);
  font-weight: 900; font-size: 15px; z-index: 2;
}
.stagecard.dsr { cursor: not-allowed; border-style: dashed; }
.stagecard.dsr .scrim { background: rgba(0,0,0,.72); }
.stagecard.dsr .sname { color: rgba(255,255,255,.5); }
.stagecard.chosen { border-color: var(--green); box-shadow: 0 0 14px rgba(31,174,75,.4); }
.stagecard .cpb {
  position: absolute; top: 7px; left: 9px; z-index: 2; font-size: 8px; font-weight: 900;
  color: #ffd75e; letter-spacing: .14em; text-shadow: 0 1px 3px rgba(0,0,0,.9);
}
.charsearch {
  width: 100%; padding: 10px 13px; border-radius: 10px; border: 1.5px solid #3a332a;
  background: #0f0d0a; color: var(--text); font-size: 14px; margin-bottom: 10px; font-family: inherit;
}
.charsearch:focus { outline: none; border-color: var(--gold); }
.chargrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; max-height: 380px; overflow-y: auto; padding: 4px; }
.charcard {
  border: 2px solid #3a332a; border-radius: 10px; padding: 9px 6px 7px; text-align: center;
  background: #14110d; color: var(--text); font-size: 11px; font-weight: 600; line-height: 1.15;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  transition: border-color .12s ease, background .12s ease;
}
.charcard .cicon { width: 38px; height: 38px; object-fit: contain; }
.charcard .cname { display: block; }
.charcard:not(:disabled):hover { border-color: var(--gold); background: #1a1610; }
.charcard.sel { border-color: var(--green); background: #17251a; }
.charcard:disabled { opacity: .45; cursor: not-allowed; }
/* locked characters shown above the stage strike/ban/counterpick grids */
.stagechars {
  display: flex; gap: 10px; align-items: center; justify-content: center;
  flex-wrap: wrap; margin-bottom: 14px;
}
.stagechars .scvs {
  font-family: var(--font-head); font-weight: 900; color: var(--red);
  font-size: 13px; letter-spacing: .06em;
}
.stagechars .pickpill small { color: #8d7f5c; font-weight: 600; }

.pickstatus { display: flex; gap: 12px; margin-top: 12px; flex-wrap: wrap; }
.pickpill {
  background: #14110d; border: 1.5px solid #3a332a; border-radius: 12px; padding: 8px 14px;
  font-size: 13px; display: inline-flex; gap: 8px; align-items: center;
}
.pickpill.locked { border-color: var(--green); }

/* character lock button under the grid */
.lockrow { margin-top: 12px; text-align: center; }
.lockrow .btn { max-width: 340px; }

/* report-result matchup card: stage photo bg + 50% scrim, players inline, stage below */
.matchcard {
  position: relative; overflow: hidden; border-radius: 16px; margin: 6px 0 16px;
  min-height: 120px; background-color: #14110d; background-size: cover; background-position: center;
  border: 2px solid #3a332a;
}
.matchcard-scrim { position: absolute; inset: 0; background: rgba(0,0,0,.5); }
.matchcard-inner {
  position: relative; z-index: 1; padding: 18px 14px; text-align: center; min-height: 120px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
}
.mc-vs {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  white-space: nowrap; max-width: 100%;
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(14px, 3.4vw, 26px); color: #fff; text-shadow: 0 2px 8px rgba(0,0,0,.85);
}
.mc-vs .mc-side { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.mc-vs .mc-name { overflow: hidden; text-overflow: ellipsis; }
.mc-vs .mc-x { color: var(--red); }
.mc-vs .vsicon { width: clamp(26px, 5vw, 40px); height: clamp(26px, 5vw, 40px); flex: 0 0 auto; }
/* stage as a tight subtitle right under the players — small, one line, never wraps */
.mc-stage {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(10px, 2vw, 13px); color: var(--gold); text-shadow: 0 2px 8px rgba(0,0,0,.9);
  letter-spacing: .06em; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}

/* rematch offer on the result screen */
.rematchbox {
  margin: 16px auto 4px; padding: 12px 14px; max-width: 360px;
  background: #1a1610; border: 1.5px solid #46381b; border-radius: 12px;
  /* the "available" state is just a bare .btn (inline-block, no wrapper) —
     without this it sits flush left instead of centred in the box */
  text-align: center;
}
.rematchbox .btns { display: flex; gap: 10px; justify-content: center; margin-top: 10px; }
.mojo-balance-line {
  display: flex; flex-direction: column; gap: 2px; margin-top: 9px;
  color: #b9aa8b; font-size: 11px; line-height: 1.35; text-align: center;
}
.mojo-balance-line b {
  color: var(--cream); font-family: var(--font-head); font-size: 10px;
  letter-spacing: .04em; text-transform: uppercase;
}
.mojo-pack {
  display: flex; flex-direction: column; align-items: center; margin-top: 18px;
  padding: 18px; border: 1px solid #46381b; border-radius: 13px; background: #17130e;
  text-align: center;
}
.mojo-pack-label {
  color: var(--cream); font-family: var(--font-head); font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase;
}
.mojo-pack-price {
  margin-top: 5px; color: var(--gold); font-family: var(--font-head);
  font-size: 44px; line-height: 1;
}
.mojo-pack-price small { margin-right: 4px; font-size: 15px; }
.mojo-pack-usd { margin: 4px 0 15px; color: #9a8d74; font-size: 12px; }
.mojo-pack-cancel { margin-top: 8px; }
.mojo-pack-note { margin: 10px 0 0; color: #9a8d74; font-size: 11px; line-height: 1.45; }
.mojo-pack .btn[disabled] { opacity: .45; cursor: not-allowed; }

/* THE PLAN — what the MOJOS pay for. Lives in the MOJOS sheet and in the support
   prompt that comes around every fourth visit. Left-aligned inside a centred modal
   on purpose: it is a list to read down, not a headline. */
.mojo-shop-help {
  margin: 10px 0 0; color: #b9aa8b; font-size: 12.5px; line-height: 1.55; text-align: center;
}
.mojo-plan { margin-top: 18px; text-align: left; }
.mojo-plan-title {
  margin: 0 0 11px; color: var(--gold); font-family: var(--font-head); font-size: 10px;
  letter-spacing: .09em; text-transform: uppercase; text-align: center;
}
/* the second half — the team, not the bills — gets a rule of its own so the two
   groups never read as one long shopping list */
.mojo-plan ul + .mojo-plan-title {
  margin-top: 17px; padding-top: 15px; border-top: 1px solid #2a2318;
}
.mojo-plan-lede {
  margin: -4px 0 11px; color: #b9aa8b; font-size: 12px; line-height: 1.45; text-align: center;
}
.mojo-plan ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.mojo-plan li { display: flex; gap: 10px; align-items: flex-start; }
/* the same cut gem as the header badge, shrunk to a bullet */
.mojo-plan-gem { flex: 0 0 auto; margin-top: 2px; color: var(--gold); }
.mojo-plan-gem svg { width: 13px; height: 13px; display: block; }
.mojo-plan-text { display: flex; flex-direction: column; gap: 2px; }
.mojo-plan-text b {
  color: var(--cream); font-family: var(--font-head); font-size: 10px;
  letter-spacing: .05em; text-transform: uppercase;
}
.mojo-plan-text span { color: #9a8d74; font-size: 12px; line-height: 1.45; }
.mojo-plan-free {
  margin: 13px 0 0; padding-top: 11px; border-top: 1px solid #2a2318;
  color: #b9aa8b; font-size: 11.5px; line-height: 1.45; text-align: center;
}
/* the one-screen version: no group headings to separate anything, so the three lines
   carry themselves and everything tightens up around them */
/* ================= THE ASK ==================================================
   This is the one modal that arrives uninvited, so it is the one modal allowed to
   show off. A gem that breathes over a halo, lines that rise in one after another,
   a price that catches the light, a sheen that runs across the button. Every bit of
   it is switched off under prefers-reduced-motion at the bottom of this block —
   flare is a gift for the people who want it, not a toll on the ones who don't.
   The greeting is the heading here (there is no gold display headline), so it is
   styled back down to prose. */
.modal:has(.ask) { padding: 22px 20px; }
.ask { text-align: center; }

@keyframes ask-pop { from { opacity: 0; transform: translateY(14px) scale(.97); } }
@keyframes ask-rise { from { opacity: 0; transform: translateY(9px); } }
@keyframes ask-float { 50% { transform: translateY(-5px); } }
@keyframes ask-halo { 50% { opacity: 1; transform: scale(1.14); } }
@keyframes ask-sheen { 0% { transform: translateX(-160%) skewX(-18deg); } 55%, 100% { transform: translateX(320%) skewX(-18deg); } }
@keyframes ask-breathe { 50% { box-shadow: 0 0 22px 2px rgba(246,194,67,.16); } }

.modal:has(.ask) { animation: ask-pop .38s cubic-bezier(.2,.85,.3,1) both; }
/* one after another, top to bottom — the eye is led down to the button */
.ask > * { animation: ask-rise .45s cubic-bezier(.2,.8,.3,1) both; }
.ask > *:nth-child(1) { animation-delay: .04s; }
.ask > *:nth-child(2) { animation-delay: .11s; }
.ask > *:nth-child(3) { animation-delay: .18s; }
.ask > *:nth-child(4) { animation-delay: .26s; }

/* the hero gem, floating over a halo that breathes on the same clock */
.ask-gem { position: relative; width: 52px; height: 52px; margin: 0 auto 13px; color: var(--gold); }
.ask-gem svg {
  position: relative; z-index: 1; width: 100%; height: 100%; display: block;
  filter: drop-shadow(0 0 9px rgba(246,194,67,.55));
  animation: ask-float 3.4s ease-in-out infinite .5s;
}
.ask-gem::before {
  content: ''; position: absolute; inset: -26%; border-radius: 50%; opacity: .55;
  background: radial-gradient(circle, rgba(246,194,67,.45), rgba(246,194,67,0) 68%);
  animation: ask-halo 3.4s ease-in-out infinite .5s;
}

.modal h3.ask-hello {
  margin: 0 0 3px; font-family: var(--font-body); font-weight: 600; text-transform: none;
  letter-spacing: 0; font-size: 14.5px; line-height: 1.4; color: var(--cream);
}
.ask .mojo-plan.compact { margin-top: 13px; }
.ask .mojo-plan.compact ul { gap: 9px; }
.ask .mojo-plan.compact .mojo-plan-free {
  margin-top: 11px; padding-top: 9px; color: var(--cream); letter-spacing: .04em;
  font-family: var(--font-head); font-size: 9.5px; text-transform: uppercase;
}

/* the pack: a slow gold breath around the box, and a sheen that crosses the button
   every few seconds. The price lives on the button here, so there is nothing above it
   to shimmer — the label and the button carry the box on their own. */
.ask .mojo-pack {
  position: relative; margin-top: 14px; padding: 15px 14px;
  animation: ask-breathe 3.6s ease-in-out infinite;
}
.ask .mojo-pack-label { font-size: 12px; letter-spacing: .1em; color: var(--gold); margin-bottom: 11px; }
.ask .mojo-pack .btn.gold { position: relative; overflow: hidden; }
.ask .mojo-pack .btn.gold::after {
  content: ''; position: absolute; top: -20%; bottom: -20%; left: 0; width: 32%;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.45), rgba(255,255,255,0));
  animation: ask-sheen 3.2s ease-in-out infinite 1.1s;
  pointer-events: none;
}

/* "Hoy no, gracias" — a way out, not an option competing with the button */
.ask-later {
  display: block; width: 100%; margin: 9px auto 0; padding: 4px;
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 10.5px; color: #7d735f;
  text-decoration: underline; text-underline-offset: 3px;
  transition: color .12s ease;
}
.ask-later:hover { color: #b9aa8b; }
.ask-later:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 6px; }

@media (prefers-reduced-motion: reduce) {
  .modal:has(.ask), .ask > *, .ask-gem svg, .ask-gem::before,
  .ask .mojo-pack, .ask .mojo-pack .btn.gold::after {
    animation: none;
  }
}
.mojo-plan.compact ul { gap: 9px; }
.mojo-plan.compact .mojo-plan-free { margin-top: 11px; padding-top: 9px; }

/* profile mains win% + admin event toggle */
.mainwr {
  font-family: var(--font-head); font-weight: 900; font-size: 11px; color: var(--gold);
  background: #14110d; border-radius: 8px; padding: 1px 6px; margin-left: 2px;
}
.eventbox {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  background: #1a1610; border: 1.5px solid #46381b; border-radius: 14px; padding: 14px 16px;
}
.eventbox.on { border-color: var(--red); box-shadow: 0 0 0 1px rgba(224,52,72,.4) inset; }
/* SIN ESPERA reads cyan when live, not the Purge's red: one is the house making the
   ladder MORE dangerous, the other is the house getting out of the crew's way. */
.nocdbox.on { border-color: var(--qp-on); box-shadow: 0 0 0 1px rgba(34,211,238,.32) inset; }
.nocdbox.on b { color: var(--qp-on); }
.eventbox b { font-family: var(--font-head); text-transform: uppercase; color: var(--gold); }
/* Gooby's tally: he sits in his own panel with the number, because a count of pozo
   fights beside a face reads as a running joke and a bare number reads as a metric. */
.goobybox { justify-content: flex-start; align-items: center; }
.goobybox .gb-face { width: 46px; height: 46px; flex: none; object-fit: contain; filter: saturate(.8); }
.goobybox .gb-body { min-width: 0; }
.goobybox .gb-body > b { display: block; font-size: 15px; letter-spacing: .05em; margin-bottom: 3px; }
.goobybox .gb-meta { margin-top: 5px; color: #6d6250; }
/* Which doorway he waits in. It lives under his tally rather than among the event
   switches because it stages something that already happens — it doesn't turn one on.
   Reuses .stageseg: same two-halves-of-one-control idea, so the current state is read
   rather than inferred from the verb on a button. */
.goobybox .gb-when {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid #2a251c;
}
/* His is a staging choice, not a go/stop one — the lit half stays gold on both sides
   instead of borrowing .stageseg's green "open" for the last child. */
.goobybox .gb-when .stageseg button:last-child.on {
  background: rgba(246,194,67,.16); color: var(--gold);
}

.playpanel { text-align: center; padding: 10px 0 4px; }
.playpanel .matchup {
  font-family: var(--font-head); font-weight: 900; font-size: clamp(17px, 3.4vw, 26px);
  text-transform: uppercase; margin: 10px 0 4px;
}
.playpanel .onstage { color: #b9a877; margin-bottom: 18px; font-size: 14px; }
.reportbtns { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 10px; }
.reportbtns .btn { font-size: 18px; padding: 16px 34px; }
.report-note { margin-top: 12px; color: #b9a877; font-size: 13px; }
.gamelog { margin-top: 16px; font-size: 12.5px; color: #8d7f5c; text-align: left; }
.gamelog div { padding: 2px 0; }
.match-tools { display: flex; gap: 8px; justify-content: center; margin-top: 16px; flex-wrap: wrap; }
.match-tools .btn { font-size: 11px; padding: 8px 12px; }

.coinbox { text-align: center; padding: 26px 0; }
.coin {
  width: 90px; height: 90px; border-radius: 50%; margin: 0 auto 16px;
  background: radial-gradient(circle at 32% 28%, #ffe9a3, var(--gold) 55%, #a8741a);
  display: flex; align-items: center; justify-content: center; font-size: 44px;
  animation: spin 1s ease-in-out; box-shadow: 0 8px 20px rgba(0,0,0,.5);
}
@keyframes spin { 0% { transform: rotateY(0); } 100% { transform: rotateY(1080deg); } }

/* chat */
.match-chat { display: flex; flex-direction: column; min-height: 420px; max-height: 560px; }
.chatlog { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 4px 2px; }
.chatmsg { background: #14110d; border-radius: 10px; padding: 8px 12px; font-size: 14px; max-width: 88%; }
.chatmsg.mine { align-self: flex-end; background: #2a2314; border: 1px solid #46381b; }
.chatmsg .cf { font-size: 10.5px; font-weight: 800; color: var(--gold); letter-spacing: .06em; text-transform: uppercase; margin-bottom: 2px; }
.chatform { display: flex; gap: 8px; margin-top: 12px; }
.chatform input {
  flex: 1; padding: 10px 12px; border-radius: 10px; border: 1.5px solid #3a332a;
  background: #0f0d0a; color: var(--text); font-size: 14px;
}
.chatform input:focus { outline: none; border-color: var(--gold); }

/* result screen */
.resultbox { text-align: center; padding: 30px 10px; }
.resultbox .big { font-family: var(--font-head); font-weight: 900; font-size: clamp(24px, 5vw, 40px); text-transform: uppercase; color: var(--gold); margin-bottom: 8px; }
.resultbox .paps { font-family: 'Comic Sans MS', 'Chalkboard SE', cursive; color: var(--red-hot); font-size: 26px; transform: rotate(-4deg); display: inline-block; margin: 8px 0; }
.resultbox .score { font-family: var(--font-head); font-size: 30px; margin: 12px 0; }

/* ---------- modals & toasts ---------- */
.modal-back {
  position: fixed; inset: 0; background: rgba(0,0,0,.72); z-index: 50;
  display: flex; align-items: center; justify-content: center; padding: 18px;
}
.modal {
  position: relative;   /* anchors the corner ✕ on modals that carry one */
  background: var(--card); border: 1.5px solid var(--gold); border-radius: var(--radius);
  padding: 26px; max-width: 420px; width: 100%; box-shadow: 0 20px 60px rgba(0,0,0,.7);
  text-align: center;
  /* Tall modals (edit profile on mobile) scroll inside themselves so the save
     button at the bottom is always reachable. dvh tracks the mobile URL bar. */
  max-height: calc(100vh - 36px);
  max-height: calc(100dvh - 36px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
/* generated share image shown in the preview modal */
.share-preview {
  display: block; margin: 10px auto 0; max-width: 100%; max-height: 46vh; max-height: 46dvh;
  width: auto; border-radius: 10px; border: 1px solid #3a332a;
}
.modal h3 { font-family: var(--font-head); text-transform: uppercase; color: var(--gold); margin-bottom: 12px; }
.modal .btns { display: flex; gap: 10px; justify-content: center; margin-top: 18px; flex-wrap: wrap; }
.toasts { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); z-index: 60; display: flex; flex-direction: column; gap: 8px; align-items: center; width: min(94vw, 480px); }
.toast {
  background: #211b12; border: 1.5px solid var(--gold); color: var(--text);
  padding: 12px 18px; border-radius: 12px; font-size: 14px; box-shadow: var(--shadow);
  animation: rise .25s ease; text-align: center; width: 100%;
}
.toast.err { border-color: var(--red); }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ---------- ready-check bar: "you're both online" cards, stacked, never a redirect ----------
   Lives at the top of the viewport so it never fights the bottom-centered toasts, and
   stacks one card per startable fight — a player can have more than one opponent
   online at once and gets to choose. */
.readybar {
  position: fixed; top: 14px; right: 14px; z-index: 65;
  display: flex; flex-direction: column; gap: 10px;
  width: min(92vw, 320px); pointer-events: none;
}
.readycard {
  pointer-events: auto;
  background: #211b12; border: 1.5px solid var(--gold); border-radius: 12px;
  padding: 14px 16px; box-shadow: var(--shadow); animation: rise .25s ease;
}
.readycard-msg {
  font-family: var(--font-head); font-weight: 900; font-size: 13px;
  letter-spacing: .02em; color: var(--cream); margin: 0;
}
.readycard-sub { font-size: 12px; color: #b9a877; margin: 4px 0 0; min-height: 15px; }
.readycard-btns { display: flex; gap: 8px; margin-top: 10px; }
.readycard-btns .btn { flex: 1; }
.readycard-btns .ready-go:disabled { opacity: .55; cursor: default; }
@media (max-width: 960px) {
  /* Below ~960px the centered header logo reaches far enough right that a
     top-right card would sit on top of it — pin to the bottom instead. */
  .readybar { top: auto; bottom: 18px; right: 8px; left: 8px; width: auto; }
}

/* rules */
.rules-body { line-height: 1.65; font-size: 15px; }
.rules-body h3 { color: var(--gold); font-family: var(--font-head); text-transform: uppercase; font-size: 15px; margin: 20px 0 8px; }
.rules-body ul, .rules-body ol { padding-left: 22px; margin: 6px 0; }
.rules-body li { margin: 4px 0; }
.rules-src { color: #8d7f5c; font-size: 13px; font-style: italic; }

/* active challenges panel (outgoing / incoming / transfer prompts) */
.chpanel { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.chrow {
  background: var(--card); border: 1.5px solid var(--gold);
  border-radius: 12px; padding: 10px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  font-size: 13px;
}
.chrow.confirm { border-color: var(--red-hot); }
/* Purge-born challenge row: violet edge + flame marker (matches the board's .chbadge.purge) */
.chrow.purge { border-color: #a34bff; box-shadow: 0 0 10px rgba(163, 75, 255, .28); }
.chrow .purgemark { display: inline-flex; vertical-align: middle; margin-right: 7px; }
.chrow .purgemark .streakflame { color: #b76bff; width: 13px; height: 13px; }
.chbtns { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.chtime {
  font-family: var(--font-head); font-weight: 900; font-size: 11px; letter-spacing: .06em;
  background: #221d15; border: 1px solid #3a332a; color: var(--gold);
  padding: 4px 9px; border-radius: 8px; white-space: nowrap;
}

/* ======================================================================
   ADMIN PANEL
   It used to be one long scroll of nine sections at equal weight, with the
   crew list — the reason root opens this page — parked at the bottom under
   the activity table. Now it is five tabs, and the crew is the one that
   opens first. Same sections, same controls, dealt out so each screen is
   about one job.
   ====================================================================== */
.adminpage > h2 { margin-bottom: 14px; }
/* The tab rail. Sticky, because the crew list is the one panel that still runs
   long and losing the tabs off the top of a 60-player board would put the scroll
   back exactly where it was. */
.admintabs {
  position: sticky; top: 0; z-index: 5;
  display: flex; gap: 6px; flex-wrap: wrap;
  margin: 0 -4px 18px; padding: 8px 4px;
  background: linear-gradient(180deg, var(--card) 72%, rgba(23,20,16,0));
  border-bottom: 1px solid var(--card-border);
}
.admintab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 14px; border-radius: 10px; cursor: pointer;
  background: #17130e; border: 1px solid #2c2620; color: #8d7f5c;
  font-family: var(--font-head); font-weight: 900; font-size: 10px;
  letter-spacing: .16em; text-transform: uppercase;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.admintab:hover { color: var(--cream); border-color: #46381b; }
.admintab.on {
  color: var(--ink); background: linear-gradient(180deg, var(--gold-row), var(--gold-row-2));
  border-color: var(--row-edge); box-shadow: var(--row-lift);
}
/* a queue somebody is waiting on, readable without opening the tab */
.at-n {
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--red); color: #fff; font-size: 9px; letter-spacing: 0;
}
.admintab.on .at-n { background: var(--ink); color: var(--gold-row); }
/* Panels stay in the DOM and hide — the wiring below the render is one flat pass
   of querySelectorAll, and the crew filter runs without a repaint. */
.adminpanel.off { display: none; }
/* the first title in a panel has the tab rail above it already */
.adminpanel > .section-title:first-child { margin-top: 4px; }
.titlenote {
  color: #8d7f5c; font-family: var(--font-body); text-transform: none;
  letter-spacing: 0; font-weight: 400;
}

/* ---- the crew filter -------------------------------------------------------
   The single biggest thing between root and getting something done: finding one
   player. Matches tag, real name or crew, live, with no round trip. */
.crewbar { gap: 12px; }
.crewsearch {
  flex: 1; min-width: 0; padding: 9px 12px; border-radius: 9px;
  background: #0f0d0a; border: 1px solid #3a332a; color: var(--text);
  font-family: var(--font-body); font-size: 14px;
}
.crewsearch::placeholder { color: #6b6152; }
.crewsearch:focus { outline: none; border-color: var(--gold); }
.crewcount { white-space: nowrap; }
.crewnone { margin-top: 14px; }
/* the spot, set apart from the tag so a number can be found by eye down the column */
.crewpos {
  display: inline-block; min-width: 2.4em; color: var(--gold);
  font-family: var(--font-head); font-weight: 900;
}
/* One key for the whole list rather than a label repeated on every row: five spelled
   out labels per player is what made the rows wrap in the first place, but icons with
   nothing to read them against is how a power ends up looking like it was never built.
   This costs one line for the entire crew. */
.crewkey {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin: 0 2px 10px; color: #6b6152;
  font-family: var(--font-head); font-weight: 900; font-size: 8.5px;
  letter-spacing: .13em; text-transform: uppercase;
}
.ck { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.ck svg { width: 12px; height: 12px; opacity: .8; }

/* Actions in their own cluster, and each one a square icon rather than a spelled-out
   label. Five labels plus the role select wrapped a player onto three lines, so ten
   players stopped fitting a screen — on a panel whose whole job is finding somebody.
   Folded to icons, a player is ONE line and the list scans down the left edge. The
   words are all still there, in title + aria-label. */
/* Sized so the WHOLE cluster still shares a line with the name at the narrowest the
   card gets: role select + five icons + gaps has to stay under what is left once the
   identity column has taken its share. Adding the always-drawn pit icon was what
   tipped it over the first time, and a row that wraps is a row you scroll past. */
.crewacts { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.crewact {
  width: 32px; height: 32px; padding: 0; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9px; cursor: pointer;
  background: #17130e; border: 1.5px solid #3a332a; color: #8d7f5c;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.crewact svg { width: 16px; height: 16px; display: block; }
.crewact:hover { color: var(--cream); border-color: #6a5324; background: #1f1a12; }
.crewact:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* Each power gets its own colour ON HOVER, so a hand moving down the row is told
   what it is about to do before it commits — and `.on` says the power is already
   held, which is what turns the same button into "take it back". */
.crewact.wild:hover, .crewact.wild.on { color: #22d3ee; border-color: #22d3ee; }
.crewact.sea:hover, .crewact.sea.on { color: var(--gold); border-color: var(--gold); }
.crewact.mojo:hover { color: var(--gold); border-color: var(--gold); }
/* the pit sits between a grant and an expulsion, and is coloured between them */
.crewact.pit:hover { color: #ffcf9a; border-color: #d59a5e; background: rgba(160,90,30,.22); }
.crewact.boot:hover { color: #fff; border-color: var(--red); background: rgba(224,52,72,.28); }
/* Nothing to do here — on this board, or from this spot. Still DRAWN, so the power
   is visibly one of the things root has, with the tooltip saying why it is asleep. */
.crewact[disabled] { opacity: .28; cursor: default; }
.crewact[disabled]:hover { color: #8d7f5c; border-color: #3a332a; background: #17130e; }
/* a held power stays lit without a pointer on it */
.crewact.on { background: rgba(34,211,238,.1); }
.crewact.sea.on { background: rgba(246,194,67,.1); }
/* the role select shrinks to the width of its three short options */
.crewacts .rolesel { padding: 6px 5px; font-size: 11px; max-width: 96px; }
/* A board row carries the same kind of cluster: chips, the placement rule and the
   three board actions, kept together on the right instead of wrapping one control
   at a time down the row. */
/* ---- the waiting-pairs list ------------------------------------------------
   One row per pair serving a 24h wait, each liftable on its own. While the blanket
   NO WAIT switch is on none of them are being enforced, so the list dims rather
   than disappearing — the rows are still the truth about who owes a wait, and they
   come back into force the moment the switch goes off. */
.cdrow .admininfo b { font-family: var(--font-head); font-size: 13px; letter-spacing: .04em; }
.cd-vs { color: #6b6152; font-weight: 400; margin: 0 2px; }
.cdlist.muted { opacity: .45; }
.cd-suspended {
  margin: -4px 0 10px; color: var(--qp-on);
  font-family: var(--font-head); font-weight: 900; font-size: 10px; letter-spacing: .12em;
}

.seaacts { gap: 6px; }
.placelabel { display: flex; align-items: center; gap: 5px; margin-top: 0; white-space: nowrap; }
.seaacts .placesel { font-size: 11px; padding: 6px 7px; }
/* broadcast box: was a stack of inline styles on the element itself */
.bcbox { flex-direction: column; align-items: stretch; gap: 10px; }
.bcbox textarea {
  width: 100%; resize: vertical; background: #14100a; border: 1px solid var(--card-border);
  border-radius: 10px; color: var(--text); font-family: var(--font-body);
  font-size: 14px; padding: 10px 12px;
}
.bcbox .btn { align-self: flex-end; }

.adminlist { display: flex; flex-direction: column; gap: 8px; }
/* a section's own toolbar: what's in it on the left, the bulk action on the right */
.adminbar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 8px; padding: 8px 12px;
  background: #17130e; border: 1px solid #46381b; border-radius: 11px;
}
.adminbar .adminsub { margin-top: 0; }
.adminrow {
  display: flex; gap: 10px; align-items: center; background: #14110d;
  border: 1px solid #262019; border-radius: 12px; padding: 10px 14px; flex-wrap: wrap;
}
.crewrow { gap: 8px; padding: 9px 12px; }
.crewrow[hidden] { display: none; }
.crewrow { align-items: center; }
.crewrow .admininfo { flex: 1 1 160px; }
.admininfo { display: flex; flex-direction: column; min-width: 0; margin-right: auto; }
.admininfo b { font-size: 14px; word-break: break-all; }
.adminsub { font-size: 11.5px; color: #8d7f5c; margin-top: 2px; }
.invtoken { font-family: monospace; letter-spacing: .04em; }
.btn.sm { font-size: 9px; padding: 7px 11px; border-radius: 7px; letter-spacing: .12em; }
.stchip {
  font-family: var(--font-head); font-weight: 900; font-size: 9.5px; letter-spacing: .1em;
  padding: 4px 9px; border-radius: 7px; white-space: nowrap;
}
.stchip.pending { background: var(--gold); color: #14100a; }
.stchip.approved, .stchip.open { background: rgba(31,174,75,.18); color: #4ed07c; border: 1px solid rgba(31,174,75,.5); }
.stchip.denied { background: rgba(224,52,72,.15); color: #ff8b98; border: 1px solid rgba(224,52,72,.5); }
.stchip.used { background: #221d15; color: #8d7f5c; border: 1px solid #3a332a; }
.rolechip {
  font-family: var(--font-head); font-weight: 900; font-size: 9.5px; letter-spacing: .1em;
  padding: 4px 9px; border-radius: 7px; text-transform: uppercase;
  background: #221d15; color: #b9a877; border: 1px solid #3a332a; white-space: nowrap;
}
.rolechip.root { background: linear-gradient(180deg, var(--gold), var(--gold-deep)); color: #14100a; border: none; }
.rolechip.admin { border-color: var(--gold); color: var(--gold); }
.rolechip.mod { border-color: #6f6248; color: #d8c58e; }
.rolesel, .placesel {
  background: #0f0d0a; color: var(--text); border: 1.5px solid #3a332a; border-radius: 9px;
  padding: 7px 9px; font-size: 12px; font-family: inherit;
}
.rolesel:focus, .placesel:focus { outline: none; border-color: var(--gold); }

/* ---------- the activity panel (root only) ---------- */
/* Reads as a ledger rather than a dashboard: the crew summary on top, then one line
   per player whose LEAD number is whatever the list is sorted by, so the ordering
   always shows its own reasoning. */
.actsummary {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 10px;
}
.actstat {
  background: #17130e; border: 1px solid #46381b; border-radius: 11px;
  padding: 10px 12px; display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.actstat b {
  font-family: var(--font-head); font-weight: 900; font-size: 16px; color: var(--gold);
  letter-spacing: .02em; line-height: 1.1;
}
.actstat span { font-size: 10px; color: #8d7f5c; text-transform: uppercase; letter-spacing: .1em; }
.actbar { gap: 8px; justify-content: flex-start; flex-wrap: wrap; }
.actbar .actsort { margin-right: auto; }
.actsort { max-width: 260px; }

.actrow {
  display: flex; gap: 10px; align-items: center; background: #14110d;
  border: 1px solid #262019; border-radius: 12px; padding: 10px 14px;
  flex-wrap: wrap; cursor: pointer; transition: border-color .14s, background .14s;
}
.actrow:hover { border-color: #46381b; background: #171310; }
.actrow.open { border-color: var(--gold); background: #17130e; }
.actidx {
  font-family: var(--font-head); font-weight: 900; font-size: 11px; color: #6f6248;
  min-width: 20px; text-align: right; flex: none;
}
/* the little green pip that says they are on the site right this second */
.actdot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--green); box-shadow: 0 0 6px rgba(31,174,75,.8); margin-left: 6px;
  vertical-align: middle;
}
.actmetric {
  display: flex; flex-direction: column; gap: 1px; text-align: right;
  min-width: 74px; flex: none;
}
.actmetric b {
  font-family: var(--font-head); font-weight: 900; font-size: 13px; color: var(--text);
  letter-spacing: .01em; white-space: nowrap;
}
.actmetric span {
  font-size: 9px; color: #8d7f5c; text-transform: uppercase; letter-spacing: .08em;
  white-space: nowrap;
}
/* the sorted-by column, pulled forward */
.actmetric.lead { min-width: 96px; }
.actmetric.lead b { color: var(--gold); font-size: 15px; }
.actmetric.lead span { color: #b9a877; }

/* the drawer: full width of the row, so it needs its own line in the flex wrap */
.actdetail { display: none; }
.actrow.open .actdetail {
  display: block; width: 100%; cursor: default;
  border-top: 1px solid #2c2620; margin-top: 10px; padding-top: 12px;
}
.actdetailgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.actsub {
  font-family: var(--font-head); font-weight: 700; font-size: 9px; color: var(--gold);
  text-transform: uppercase; letter-spacing: .18em; margin-bottom: 8px;
}
.actbarrow { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; font-size: 11.5px; }
.actbarname { min-width: 78px; color: #d8cba0; text-transform: capitalize; }
.actbartrack { flex: 1; height: 7px; background: #221d15; border-radius: 4px; overflow: hidden; }
.actbarfill { display: block; height: 100%; background: linear-gradient(90deg, var(--gold-deep), var(--gold)); }
.actbarval { color: #8d7f5c; white-space: nowrap; font-size: 11px; }
.actbarval small { color: #6f6248; }

.actchips { display: flex; flex-wrap: wrap; gap: 5px; }
.actchip {
  background: #221d15; border: 1px solid #3a332a; border-radius: 7px;
  padding: 4px 8px; font-size: 11px; color: #b9a877;
}
.actchip b { color: var(--gold); font-family: var(--font-head); font-size: 11px; }

.actfight { display: flex; align-items: baseline; gap: 7px; font-size: 12px; margin-bottom: 4px; }
.actfight .ok { color: #4ed07c; font-weight: 700; font-size: 10px; }
.actfight .no { color: #ff8b98; font-weight: 700; font-size: 10px; }
.actfight b { color: #d8cba0; }

/* thirty days, thirty columns — the shape of a habit reads faster than the numbers */
.actdays {
  display: flex; align-items: flex-end; gap: 3px; height: 46px;
  background: #100e0a; border: 1px solid #262019; border-radius: 10px; padding: 6px 8px;
}
.actday {
  flex: 1; min-width: 0; height: var(--h, 3%); border-radius: 2px;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep)); opacity: .9;
}
.actday[style*="--h:3%"] { background: #2c2620; }

@media (max-width: 720px) {
  .admintabs { gap: 5px; }
  .admintab { padding: 8px 11px; font-size: 9px; letter-spacing: .12em; }
  /* the six per-player controls get the full width under the name instead of
     being squeezed into a column beside it */
  .crewacts { flex: 1 1 100%; justify-content: flex-start; }
  .crewbar { flex-wrap: wrap; }
  .crewbar .crewsearch { flex: 1 1 100%; order: -1; }
  .actsummary { grid-template-columns: repeat(2, 1fr); }
  .actdetailgrid { grid-template-columns: 1fr; }
  .actrow { padding: 10px 12px; row-gap: 8px; }
  .admininfo { margin-right: auto; }
  /* On a phone the row wraps: identity on the first line, the metrics spread evenly
     underneath it rather than stacking into a ragged column. */
  .actmetric { min-width: 0; flex: 1; text-align: left; }
  .actmetric.lead { min-width: 100%; text-align: left; }
}

/* active-match banner */
.rejoin-banner {
  background: var(--red); color: #fff; border-radius: 12px; padding: 12px 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase; font-size: 13px;
  margin-bottom: 14px; flex-wrap: wrap;
}

/* The sign-up band: sits where the challenge panel would, because that is exactly
   what is missing and the rows otherwise look like an ordinary live ladder. Dashed,
   quiet, gold — a notice, not an alarm. */
.signupnote {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 11px 15px;
  border: 1px dashed rgba(246,194,67,.42); border-radius: 12px; background: #17130e;
}
.signupnote b {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 11px; letter-spacing: .18em; color: var(--gold);
}
.signupnote span { font-size: 12px; color: #8d7f5c; line-height: 1.45; }

/* ---------- fighter icons, hat avatars, climb animation ---------- */
.micon { width: 26px; height: 26px; object-fit: contain; display: inline-block; vertical-align: middle; }
.vsicon { width: 34px; height: 34px; object-fit: contain; vertical-align: middle; }
.cq {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; background: #241f18;
  color: var(--gold); font-family: var(--font-head); font-weight: 900; font-size: 14px;
}
.charcard .cq { width: 38px; height: 38px; font-size: 20px; }
.rankrow .mains .m .micon { width: 32px; height: 32px; }
.histicons { display: inline-flex; gap: 4px; align-items: center; }
.hatmark { width: 62%; height: 62%; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,.4)); }
.lockicon { width: 12px; height: 14px; display: inline-block; vertical-align: baseline; }
.rankrow .lock { display: inline-flex; align-items: center; color: var(--ink-soft); }
.mainchip .micon { margin-right: 2px; }
.pickpill .micon { width: 22px; height: 22px; }

.res-trophy { font-size: 56px; line-height: 1; margin-bottom: 6px; }

.rankrow.me.pulse { animation: rowpulse 1.6s ease 2; }
@keyframes rowpulse {
  0%, 100% { box-shadow: var(--row-lift), var(--row-face); }
  50% { box-shadow: 0 0 0 3px var(--gold), 0 0 34px rgba(246,194,67,.85), var(--row-face); }
}

@media (max-width: 640px) {
  .rankrow {
    grid-template-columns: 19px 32px minmax(0,1fr) 26px 74px;
    --row-pad-y: 12px; --row-pad-x: 10px; gap: 7px;
  }
  .board.has-art .rankrow { grid-template-columns: 19px 32px minmax(0,1fr) 26px 74px 64px; }
  .rankrow .mains .m:nth-child(n+2) { display: none; }
  .rankrow .mains .m { width: 28px; height: 28px; }
  .rankrow .mains .m .micon { width: 28px; height: 28px; }
  .rankrow .pos { font-size: 17px; }
  .rankrow .ava { width: 32px; height: 32px; flex: 0 0 32px; font-size: 16px; }
  .rankrow .ava-dot { width: 10px; height: 10px; border-width: 1.5px; }
  .rankrow .who { gap: 8px; }
  .rankrow .tag { font-size: clamp(10px, 2.8vw, 13.5px); }
  .rankrow .crewtag { font-size: 8px; letter-spacing: .16em; }
  .rankrow .paps { font-size: 8px; letter-spacing: .04em; }
  .recentwin { font-size: 14px; }
  .movebadge { width: 22px; height: 22px; flex: 0 0 22px; font-size: 15px; }
  .movebadge.new { font-size: 9px; }
  .medal { width: 32px; height: 37px; }
  .topbar { padding: 12px 20px 0; }
  .topbar-logo { margin: 22px auto 10px; }
  /* Below this width the inline nav becomes a dropdown behind the burger button
     (toggled via app.js) instead of wrapping onto extra rows. */
  .nav-burger { display: flex; }
  .mainnav {
    display: none; position: absolute; top: 100%; left: 0; right: 0; margin-top: 8px;
    flex-direction: column; align-items: stretch; gap: 3px; max-width: none;
    padding: 10px; background: #1c1710; border: 1px solid var(--card-border);
    border-radius: 12px; box-shadow: 0 18px 40px rgba(0,0,0,.55); z-index: 40;
  }
  .mainnav.open { display: flex; }
  .mainnav a, .mainnav button { font-size: 11px; padding: 9px 12px; text-align: left; letter-spacing: .02em; border-width: 1.5px; }
  .mainnav .nav-me { gap: 8px; }
  .dotava { width: 16px; height: 16px; flex: 0 0 16px; }
}

@media (max-width: 400px) {
  /* A slightly narrower dropdown card on the smallest phones. */
  .mainnav { padding: 8px; }
  .mainnav a, .mainnav button { font-size: 10px; padding: 8px 10px; }
  .rankrow { grid-template-columns: 18px 26px minmax(0,1fr) 26px 64px; gap: 6px; }
  .board.has-art .rankrow { grid-template-columns: 18px 26px minmax(0,1fr) 26px 64px 52px; }
  .rankrow .tag { font-size: clamp(9px, 2.7vw, 11px); }
  .rankrow .paps { font-size: 7.5px; }
  .qrow { align-items: stretch; flex-direction: column; }
  .qbtns { width: 100%; flex-wrap: wrap; }
  .qbtns .btn { flex: 1 1 120px; }
}

/* ======================= QUICKPLAY ======================= */
:root { --qp-on: #22d3ee; --qp-on-deep: #0891b2; }
/* nav link: a soft cyan pulse while you're ONLINE in the pool */
.mainnav .nav-quickplay.searching {
  border-color: var(--qp-on); color: var(--qp-on);
  animation: qp-navpulse 1.5s ease-in-out infinite;
}
@keyframes qp-navpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(34,211,238,.0); }
  50% { box-shadow: 0 0 0 3px rgba(34,211,238,.28); }
}

/* ======================================================================
   QUICKPLAY — the casual room.
   The ladder screen is gold and heavy because a spot there is worth
   something. This room is the opposite promise: nothing you own is on the
   line, only your aura. So it runs on the cyan the mode has always used,
   built as an ARENA — the aura on a plinth with rings going out from it
   while it looks for someone, the switch under it, and the player's own
   record below the fold.
   Everything here is about THEM: what they're risking, how they're doing,
   who they last played. Nothing about how the matchmaker picks — no pool
   count, no aura band. That was a deliberate call by the crew and this
   rebuild keeps it.
   ====================================================================== */
.card.quickplay { text-align: center; max-width: 460px; }

.qp-head { margin-bottom: 4px; }
/* scoped past `.card h2`, which would otherwise paint the wordmark gold — the one
   thing this room must not be, since gold is the ladder's colour and the whole
   point of quickplay is that the ladder is not involved */
.card.quickplay .qp-word {
  font-family: var(--font-head); font-weight: 900; font-size: clamp(22px, 7vw, 30px);
  letter-spacing: .2em; color: var(--qp-on); line-height: 1;
  text-shadow: 0 0 24px rgba(34,211,238,.35);
}
.qp-stakes {
  margin: 10px auto 0; max-width: 300px;
  color: #8d7f5c; font-size: 12px; line-height: 1.5;
}

/* the plinth: the aura sits in the middle and the rings go out from behind it.
   Fixed height whether or not it's searching, so flipping the switch never
   makes the page jump under the player's thumb. */
.qp-arena {
  position: relative; height: 208px; margin: 6px auto 8px;
  display: flex; align-items: center; justify-content: center;
}
/* Three rings, expanding out and fading. They exist only while ONLINE — this is
   the whole visual difference between "waiting" and "off", so it has to read
   from across the room. pointer-events off: they sit over the aura number. */
.qp-ring {
  position: absolute; left: 50%; top: 50%; width: 132px; height: 132px;
  margin: -66px 0 0 -66px; border-radius: 50%;
  border: 1.5px solid var(--qp-on); opacity: 0; pointer-events: none;
}
.qp-arena.live .qp-ring { animation: qp-ping 2.7s cubic-bezier(.2,.6,.35,1) infinite; }
.qp-arena.live .qp-ring.r2 { animation-delay: .9s; }
.qp-arena.live .qp-ring.r3 { animation-delay: 1.8s; }
/* Widest ring lands just inside the plinth: any further and it crosses the stakes
   line above, which turned the header into noise the first time round. */
@keyframes qp-ping {
  0%   { transform: scale(.55); opacity: .0; }
  12%  { opacity: .55; }
  100% { transform: scale(1.72); opacity: 0; }
}
/* a soft pool of light under the number while it's looking */
.qp-arena.live::before {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 230px; height: 230px; margin: -115px 0 0 -115px; border-radius: 50%;
  background: radial-gradient(circle, rgba(34,211,238,.14), transparent 68%);
  animation: qp-breathe 2.7s ease-in-out infinite; pointer-events: none;
}
@keyframes qp-breathe { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .qp-arena.live .qp-ring { animation: none; opacity: .3; }
  .qp-arena.live .qp-ring.r2, .qp-arena.live .qp-ring.r3 { display: none; }
  .qp-arena.live::before { animation: none; }
}

/* big aura readout */
.qp-aura {
  position: relative; z-index: 1; display: inline-flex;
  flex-direction: column; align-items: center; gap: 2px;
}
.qp-auranum {
  font-family: var(--font-head); font-weight: 900; font-size: clamp(64px, 20vw, 104px);
  line-height: .9; color: var(--cream);
  text-shadow: 0 2px 0 rgba(0,0,0,.4);
  transition: color .3s, text-shadow .3s;
}
.qp-auralabel {
  font-family: var(--font-head); font-weight: 900; letter-spacing: .42em;
  font-size: 13px; color: #b9a877; margin-left: .42em;
}
/* glow flashes when the number animates after a bout */
.qp-aura.up .qp-auranum { color: #7ef0a6; text-shadow: 0 0 26px rgba(31,174,75,.75); }
.qp-aura.down .qp-auranum { color: #ff8a8a; text-shadow: 0 0 26px rgba(224,52,72,.7); }
/* floating ±delta chip that rises and fades */
.qp-delta {
  position: absolute; top: -6px; right: -14px;
  font-family: var(--font-head); font-weight: 900; font-size: 22px;
  animation: qp-float 1.8s ease-out forwards;
}
.qp-delta.pos { color: #7ef0a6; }
.qp-delta.neg { color: #ff8a8a; }
@keyframes qp-float {
  0% { opacity: 0; transform: translateY(6px) scale(.8); }
  18% { opacity: 1; transform: translateY(-4px) scale(1.1); }
  70% { opacity: 1; transform: translateY(-20px) scale(1); }
  100% { opacity: 0; transform: translateY(-40px) scale(1); }
}

/* the big switch */
.qp-switchrow { display: flex; align-items: center; justify-content: center; gap: 16px; }
.qp-switch {
  --w: 108px; --h: 52px; --pad: 5px;
  position: relative; width: var(--w); height: var(--h); border: none; padding: 0;
  border-radius: 999px; background: #2a2420; box-shadow: inset 0 2px 6px rgba(0,0,0,.55);
  transition: background .25s ease;
}
.qp-switch .qp-knob {
  position: absolute; top: var(--pad); left: var(--pad);
  width: calc(var(--h) - var(--pad) * 2); height: calc(var(--h) - var(--pad) * 2);
  border-radius: 50%; background: linear-gradient(180deg, #f4efe4, #cbc3b0);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  transition: transform .25s cubic-bezier(.34,1.56,.64,1);
}
.qp-switch.on { background: linear-gradient(180deg, var(--qp-on), var(--qp-on-deep)); }
.qp-switch.on .qp-knob { transform: translateX(calc(var(--w) - var(--h))); }
.qp-state {
  font-family: var(--font-head); font-weight: 900; letter-spacing: .12em;
  font-size: 20px; color: var(--gray); min-width: 84px; text-align: left;
}
.qp-state.on { color: var(--qp-on); text-shadow: 0 0 18px rgba(34,211,238,.5); }

.qp-status {
  margin-top: 18px; color: #b9a877; font-size: 13px; line-height: 1.5;
  max-width: 360px; margin-left: auto; margin-right: auto;
  min-height: 1.5em;   /* holds its line so the record below never shifts */
}
.qp-status.searching { color: var(--qp-on); font-weight: 700; }
/* their OWN wait, in a tabular face so the seconds don't jiggle the line */
.qp-elapsed {
  display: inline-block; margin-left: 8px; padding: 2px 7px; border-radius: 999px;
  background: rgba(34,211,238,.1); border: 1px solid rgba(34,211,238,.3);
  font-family: var(--font-head); font-weight: 900; font-size: 11px;
  letter-spacing: .06em; font-variant-numeric: tabular-nums;
}

/* ---- the record: the part of this screen that is worth coming back to -------
   The ladder can't tell anyone how they're doing in quickplay — the board never
   reacts to a bout fought here. So the mode keeps its own books, and puts them
   on the screen where the decision to play is made. */
.qp-record { margin-top: 26px; display: flex; flex-direction: column; gap: 12px; }
.qp-panel {
  background: #12100c; border: 1px solid var(--card-border); border-radius: 14px;
  padding: 14px 16px;
}
.qp-panel-title {
  font-family: var(--font-head); font-weight: 900; font-size: 10px;
  letter-spacing: .2em; text-transform: uppercase; color: #8d7f5c;
  text-align: left; margin-bottom: 12px;
}
.qp-figures { display: flex; justify-content: space-between; gap: 10px; }
.qp-fig { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.qp-fig b {
  font-family: var(--font-head); font-weight: 900; font-size: 30px; line-height: 1;
  color: var(--text);
}
.qp-fig span {
  font-family: var(--font-head); font-weight: 900; font-size: 9px;
  letter-spacing: .16em; text-transform: uppercase; color: #8d7f5c;
}
.qp-fig.won b { color: #7ef0a6; }
.qp-fig.lost b { color: #ff8a8a; }
/* a streak only earns the fire colour once it's actually a streak */
.qp-fig.streak.hot b { color: var(--qp-on); text-shadow: 0 0 18px rgba(34,211,238,.45); }
/* one bar, green over red — the whole record read at a glance */
.qp-bar {
  margin-top: 14px; height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(224,52,72,.5);
}
.qp-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #1fae4b, #7ef0a6);
  transition: width .5s ease;
}

.qp-bouts { display: flex; flex-direction: column; gap: 7px; }
.qp-bout {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; border-radius: 9px; background: #171310;
  border-left: 2px solid transparent;
}
.qp-bout.won { border-left-color: var(--green); }
.qp-bout.lost { border-left-color: var(--red); }
.qb-mark { font-size: 11px; line-height: 1; }
.qp-bout.won .qb-mark { color: #7ef0a6; }
.qp-bout.lost .qb-mark { color: #ff8a8a; }
.qb-opp {
  flex: 1; text-align: left; font-family: var(--font-head); font-weight: 900;
  font-size: 12px; letter-spacing: .04em; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.qb-score {
  font-family: var(--font-head); font-weight: 900; font-size: 13px;
  color: var(--cream); font-variant-numeric: tabular-nums;
}
.qb-dash { color: #6b6152; margin: 0 3px; }

/* nobody has played one yet — an invitation, not an empty table */
.qp-empty { text-align: center; }
.qp-empty-line {
  font-family: var(--font-head); font-weight: 900; font-size: 12px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text);
}
.qp-empty-sub { margin-top: 7px; color: #8d7f5c; font-size: 12px; }

/* run-it-back offer shown on the quickplay screen after a bout */
.qp-rematch {
  margin-top: 20px; display: flex; flex-direction: column; align-items: center; gap: 10px;
  color: var(--text); font-size: 14px; text-align: center;
}
.qp-rematch .btns { display: flex; gap: 10px; justify-content: center; }

/* small badge on the match screen so a quickplay bout reads as casual */
.qp-badge {
  display: inline-block; margin-top: 6px; padding: 3px 10px; border-radius: 999px;
  background: rgba(34,211,238,.14); border: 1px solid var(--qp-on);
  color: var(--qp-on); font-family: var(--font-head); font-weight: 900;
  font-size: 10px; letter-spacing: .16em;
}

/* ======================================================================
   REQUEST INVITE — "the rite of petition"
   A candlelit chamber: a spinning wax-seal sigil, a spare summons, three
   quiet underline fields. Mysterious, elegant, cult-at-the-door. Everything
   is scoped to .rite so the rest of the app is untouched.
   ====================================================================== */

/* a soft dark vignette that dims the fire/halftone behind this page only */
.rite-veil {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% 32%, rgba(11,10,8,0) 0%, rgba(8,7,5,.55) 55%, rgba(4,3,2,.9) 100%);
}

.rite {
  max-width: 460px; margin: 4px auto 40px; padding: 0 22px;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
/* staggered reveal — each element rises out of the dark in turn */
.rite > * { animation: riteRise .9s cubic-bezier(.2,.7,.2,1) both; }
.rite > *:nth-child(2) { animation-delay: .10s; }
.rite > *:nth-child(3) { animation-delay: .18s; }
.rite > *:nth-child(4) { animation-delay: .26s; }
.rite > *:nth-child(5) { animation-delay: .34s; }
.rite > *:nth-child(6) { animation-delay: .42s; }
.rite > *:nth-child(7) { animation-delay: .50s; }
@keyframes riteRise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ---- the seal ---- */
.rite-seal {
  position: relative; width: 220px; height: 220px; margin: 22px 0 26px;
  display: grid; place-items: center;
}
.rite-seal-glow {
  position: absolute; inset: -22%; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(246,194,67,.34) 0%, rgba(246,194,67,.10) 42%, transparent 66%);
  filter: blur(6px); animation: riteBreathe 5.6s ease-in-out infinite;
}
@keyframes riteBreathe {
  0%, 100% { opacity: .55; transform: scale(.94); }
  50%      { opacity: 1;   transform: scale(1.06); }
}
.rite-seal-ring { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.rite-ring { fill: none; stroke: var(--gold); }
.rite-ring-o { stroke: rgba(246,194,67,.55); stroke-width: 1; }
.rite-ring-m { stroke: rgba(246,194,67,.9);  stroke-width: 1.4; stroke-dasharray: 1.5 6; }
.rite-ring-i { stroke: rgba(246,194,67,.28); stroke-width: 1; }
.rite-legend {
  transform-origin: 120px 120px; animation: riteSpin 48s linear infinite;
}
.rite-legend text {
  fill: var(--gold); font-family: var(--font-head); font-weight: 900;
  font-size: 9px; letter-spacing: 1.3px;
  paint-order: stroke; filter: drop-shadow(0 0 6px rgba(246,194,67,.35));
}
@keyframes riteSpin { to { transform: rotate(360deg); } }
.rite-seal-mark {
  position: relative; width: 92px; height: 92px; object-fit: contain;
  filter: drop-shadow(0 0 14px rgba(246,194,67,.45)) drop-shadow(0 3px 6px rgba(0,0,0,.5));
  animation: riteBreathe 5.6s ease-in-out infinite;
}
/* Gooby is a full standing mascot; kept small so he reads as a little figure
   inside the ring rather than filling it */
.rite-seal-mark.is-gooby { width: 66px; height: 66px; }
/* sealed state (confirmation): the mark cools, a struck stamp lands over it */
.rite-seal.is-sealed .rite-legend { animation-duration: 120s; }
.rite-seal.is-sealed .rite-seal-mark { filter: drop-shadow(0 0 8px rgba(246,194,67,.25)) grayscale(.15); opacity: .8; animation: none; }
.rite-seal.is-sealed .rite-seal-glow { opacity: .4; animation: none; }
.rite-seal-stamp {
  position: absolute; font-family: var(--font-head); font-weight: 900;
  font-size: 116px; line-height: 1; color: var(--red);
  opacity: .16; transform: rotate(-14deg); pointer-events: none;
  text-shadow: 0 2px 10px rgba(0,0,0,.5);
  animation: riteStamp .5s cubic-bezier(.2,1.4,.4,1) .3s both;
}
@keyframes riteStamp {
  0%   { opacity: 0; transform: rotate(-14deg) scale(2.6); }
  70%  { opacity: .28; }
  100% { opacity: .16; transform: rotate(-14deg) scale(1); }
}

/* ---- the words ---- */
.rite-kicker {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: 10px; letter-spacing: .42em; color: var(--gold);
  margin-left: .42em; opacity: .82;
}
.rite-title {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(30px, 8vw, 46px); line-height: .96; letter-spacing: .02em;
  color: var(--cream); margin: 14px 0 0;
  text-shadow: 0 1px 0 rgba(0,0,0,.6), 0 0 26px rgba(246,194,67,.14);
}
.rite-whisper {
  font-family: var(--font-body); font-size: 14px; line-height: 1.7;
  color: #cbb98c; opacity: .72; max-width: 36ch; margin: 16px auto 0;
  text-wrap: balance;
}

/* ---- the fields: quiet gold underlines, not boxes ---- */
.rite-form { width: 100%; margin-top: 16px; display: flex; flex-direction: column; gap: 22px; }
.rite-field { display: block; text-align: left; position: relative; }
.rite-field > span {
  display: block; font-family: var(--font-head); font-weight: 900;
  text-transform: uppercase; font-size: 9px; letter-spacing: .32em;
  color: #b9a877; opacity: .62; margin: 0 0 7px 1px;
}
.rite-field input {
  width: 100%; padding: 7px 2px 9px; border: none; border-bottom: 1px solid rgba(246,194,67,.28);
  background: transparent; color: var(--cream); font-family: var(--font-body);
  font-size: 17px; letter-spacing: .01em;
  transition: border-color .25s ease, box-shadow .25s ease;
}
.rite-field input::placeholder { color: #6f6552; opacity: .7; }
.rite-field input:focus {
  outline: none; border-bottom-color: var(--gold);
  box-shadow: 0 1px 0 var(--gold), 0 6px 18px -12px rgba(246,194,67,.8);
}
.rite-field:focus-within > span { color: var(--gold); opacity: .95; }

/* ---- consent checkboxes: the two "Optional/Required" groups above the submit ---- */
.rite-checks { display: flex; flex-direction: column; gap: 10px; margin-top: -6px; }
.rite-check-label {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  letter-spacing: .28em; font-size: 9px; color: #b9a877; opacity: .62;
  margin: 6px 0 -2px 1px;
}
.rite-check-label:first-child { margin-top: 0; }
.rite-check {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  font-family: var(--font-body); font-size: 12.5px; line-height: 1.4;
  color: rgba(255,255,255,.78);
}
.rite-check input {
  appearance: none; -webkit-appearance: none; width: 17px; height: 17px; flex: 0 0 17px;
  margin-top: 1px; border: 1.5px solid rgba(246,194,67,.5); border-radius: 4px;
  background: transparent; position: relative; cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.rite-check input:checked { background: var(--gold); border-color: var(--gold); }
.rite-check input:checked::after {
  content: ""; position: absolute; left: 5px; top: 1px; width: 4px; height: 8px;
  border: solid #14100a; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.rite-check input:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.rite-err { color: #ff8f84; font-size: 13px; text-align: center; margin: -4px 0 0; min-height: 16px; }

/* ---- the seal button ---- */
.rite-submit {
  position: relative; margin-top: 6px; width: 100%; padding: 15px 22px;
  border: 1px solid rgba(246,194,67,.55); border-radius: 2px; background: transparent;
  color: var(--gold); font-family: var(--font-head); font-weight: 900;
  text-transform: uppercase; letter-spacing: .34em; font-size: 12px;
  overflow: hidden; cursor: pointer;
  transition: color .3s ease, border-color .3s ease, box-shadow .3s ease, letter-spacing .3s ease;
}
.rite-submit > span { position: relative; z-index: 1; margin-left: .34em; }
.rite-submit::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(180deg, #ffe093, #f6c243 46%, #e5ab2e);
  transform: translateY(101%); transition: transform .32s cubic-bezier(.2,.7,.2,1);
}
.rite-submit:hover, .rite-submit:focus-visible {
  outline: none; color: var(--ink); border-color: var(--gold);
  box-shadow: 0 0 30px -6px rgba(246,194,67,.6); letter-spacing: .4em;
}
.rite-submit:hover::before, .rite-submit:focus-visible::before { transform: translateY(0); }
.rite-submit:active { transform: translateY(1px); }

.rite-alt { margin-top: 26px; font-size: 12px; letter-spacing: .04em; color: #8a7f66; }
.rite-alt a {
  color: var(--gold); font-weight: 700; text-transform: uppercase;
  font-size: 11px; letter-spacing: .18em; margin-left: 4px;
  border-bottom: 1px solid rgba(246,194,67,.4); padding-bottom: 1px;
}
.rite-alt a:hover { border-bottom-color: var(--gold); }
/* stacked links (login) sit close together rather than double-spaced */
.rite-alt-tight { margin-top: 12px; }

.rite-done .rite-title { margin-top: 8px; }

@media (prefers-reduced-motion: reduce) {
  .rite > *, .rite-seal-glow, .rite-seal-mark, .rite-legend, .rite-seal-stamp {
    animation: none !important;
  }
  .rite > * { opacity: 1; transform: none; }
}

/* route chrome: on the petition page the seal is the hero, so the header
   brand shrinks, the halftone dims, and the whole scene pulls to center */
body.on-rite .topbar-logo { width: clamp(112px, 13vw, 148px); margin: 12px auto 4px; }
body.on-rite .header-bg { opacity: .22; }
body.on-rite .footer { display: none; }
body.on-rite .rite { min-height: calc(100vh - 240px); justify-content: center; margin-top: 0; }

/* ===================== NOTIFICATIONS =====================================
   A bell beside the MOJOS gem, with a dropdown hung under it. The button is a
   deliberate clone of .mojobtn — same plate, same badge geometry — so the two read
   as one pair of header controls instead of two unrelated widgets. The count badge
   is red where mojos is gold: one is a balance, the other is something waiting. */
.nav-notif { position: relative; display: inline-flex; }
.nav-notif:empty { display: none; }
.notifbtn {
  position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 10px;
  background: transparent; border: 1.5px solid rgba(246,194,67,.45); color: var(--gold);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.notifbtn svg { width: 17px; height: 17px; display: block; }
.notifbtn:hover { background: var(--gold); color: #14100a; border-color: var(--gold); }
.notifbtn .notifcount {
  position: absolute; top: -6px; right: -6px; min-width: 16px; height: 16px; padding: 0 3px;
  display: flex; align-items: center; justify-content: center; border-radius: 999px;
  background: var(--red-hot); color: #fff; border: 1.5px solid #14100a;
  font-family: var(--font-head); font-weight: 900; font-size: 9px; line-height: 1;
}
.notifbtn .notifcount[hidden] { display: none; }

/* The panel. Anchored to the button's right edge so it never runs off the viewport
   on the side it opens from. */
.notifmenu {
  position: absolute; top: calc(100% + 9px); right: 0; z-index: 60;
  width: min(340px, calc(100vw - 24px));
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 14px; box-shadow: var(--shadow); overflow: hidden;
}
.notifmenu[hidden] { display: none; }
.nt-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 14px; border-bottom: 1px solid var(--card-border);
}
.nt-head b { font-family: var(--font-head); font-size: 12px; letter-spacing: .06em; color: var(--gold); }
.nt-clear {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 11px; color: var(--gray);
}
.nt-clear:hover { color: var(--cream); }
.nt-list { display: flex; flex-direction: column; max-height: min(60vh, 420px); overflow-y: auto; }
.nt-empty {
  padding: 22px 14px; text-align: center;
  font-family: var(--font-body); font-size: 13px; color: var(--gray);
}
.nt-row {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 14px; border-bottom: 1px solid var(--card-border);
  color: var(--text); text-decoration: none;
}
.nt-row:last-child { border-bottom: 0; }
/* Unread is tinted, dotted and brighter — three cues, because the row has to be
   scannable at a glance rather than read. Read rows recede to the flat panel. */
.nt-row.unread { background: rgba(246,194,67,.075); box-shadow: inset 2px 0 0 var(--gold); }
a.nt-row:hover { background: rgba(246,194,67,.14); }
.nt-dot { width: 7px; height: 7px; border-radius: 50%; background: transparent; flex: 0 0 auto; }
.nt-row.unread .nt-dot { background: var(--gold); }
.nt-row.unread .nt-text { color: var(--cream); }
.nt-text { flex: 1 1 auto; font-family: var(--font-body); font-size: 13px; line-height: 1.35; color: #cbbf9f; }
.nt-when { flex: 0 0 auto; font-family: var(--font-body); font-size: 11px; color: var(--gray); }

@media (max-width: 560px) {
  /* Narrow screens: pin the panel across the header instead of hanging it off a
     32px button, which would leave it clipped against the right edge. */
  .notifmenu { position: fixed; top: 60px; right: 12px; left: 12px; width: auto; }
  .nt-row { padding: 12px 13px; }
}

/* ============================================================================
   GOOBY WAS FED
   The way out of a pozo-only result. It is a full black plate over the entire
   app — deliberately #000 and not the site's warm dark, because the point is
   that everything the dojo normally shows you is gone for a moment. The app is
   free to navigate underneath: by the time this dissolves, the ranking has
   loaded and settled and is simply there.
   ========================================================================== */
body.gooby-rite { overflow: hidden; }
.goobyrite {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  background: #000;
  opacity: 1; transition: opacity 1.4s ease-in;
  /* the plate arrives fast and hard — the slowness is all in the leaving */
  animation: gr-in .45s ease-out both;
}
.goobyrite.out { opacity: 0; pointer-events: none; }
@keyframes gr-in { from { opacity: 0; } to { opacity: 1; } }
/* A vignette that breathes: the black is never quite even, so the screen reads as
   a space with something in it rather than as a failed render. */
.goobyrite::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(120,90,20,.13), transparent 62%);
  animation: gr-breathe 4.6s ease-in-out infinite;
}
@keyframes gr-breathe { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
.gr-inner {
  position: relative; z-index: 1; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 22px;
  padding: 24px;
}
/* He rises out of the black and keeps rising, very slightly, the whole time. */
.gr-gooby {
  width: clamp(15px, 2.75vw, 26px); height: auto;
  filter: drop-shadow(0 0 46px rgba(246,194,67,.28)) saturate(.62) brightness(.9);
  animation: gr-rise 2.6s cubic-bezier(.16,.7,.3,1) both, gr-float 6s ease-in-out 2.6s infinite;
}
@keyframes gr-rise { from { opacity: 0; transform: translateY(28px) scale(.94); } to { opacity: 1; transform: none; } }
@keyframes gr-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
.gr-line {
  font-family: var(--font-head); font-weight: 900; text-transform: uppercase;
  font-size: clamp(9px, 1.1vw, 13px); letter-spacing: .34em;
  /* the tracking is on the right of every glyph including the last, so the line
     sits a half-space right of centre without this */
  text-indent: .34em;
  color: #d8c48a; text-shadow: 0 0 34px rgba(246,194,67,.4);
  animation: gr-word 3.2s ease-out .7s both;
}
@keyframes gr-word { from { opacity: 0; letter-spacing: .6em; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .goobyrite, .goobyrite::after, .gr-gooby, .gr-line { animation: none; }
}
