
:root{
  /* The palette is the RANK LADDER's palette, not a new one. Those colours are
     already on every rank card the bot posts, so the site and the bot read as
     one product and each hue already means something to a player. */
  --blue:#4ea8f0;   --blue-2:#6f8ef5;
  --purple:#8b7bf7; --purple-2:#b07bf7;
  --gold:#f0b43f;   --orange:#e08a4a;
  --teal:#35c9a6;   --lime:#8fc752;
  --slate:#5f6878;  --red:#ef5f4a;

  /* Roles. Colour is assigned by MEANING, so a hue never says two things:
     blue is "you can interact with this", purple is identity, gold is the
     brand and the top of a board, teal/red are up and down. */
  --bg:#050608; --card:#0b0d11; --card2:#11141a;
  --line:#191d25; --fg:#f3f5f8; --dim:#7b8593; --dimmer:#49515e;
  --acc:var(--blue); --acc-dim:rgba(78,168,240,.14);
  --pink:#f36fc0;
  /* Money has its own green. Teal already means "up" on every chart and K/D
     row, so reusing it for a balance would make the two say the same thing. */
  --cash:#43c97a;
  /* The other side of every market. Deliberately not red: No is not bad news,
     it is simply the opposite bet, and red would score it. */
  --chart-no:#9aa4b2;
  --brand:var(--gold);
  --good:var(--teal); --bad:var(--red);
  --r:14px;
  /* ONE motion vocabulary for the whole site. Anything that moves picks from
     these, so nothing feels like it belongs to a different page.
       --ease   settles without overshoot: fades, colour, hovers
       --spring overshoots slightly: things that TRAVEL, like the switch pill
       --exit   accelerates away: anything leaving */
  --ease:cubic-bezier(.22,.9,.28,1);
  --spring:cubic-bezier(.34,1.45,.44,1);
  --exit:cubic-bezier(.55,0,.85,.4);
  --d-fast:.16s; --d:.3s; --d-slow:.52s;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--fg);
  font:16px/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
.lnk{transition:color .18s var(--ease)}

/* ---- no pinch or double-tap zoom ----
   touch-action:manipulation drops the double-tap-to-zoom gesture, which also
   removes the 300ms wait browsers keep in case a tap becomes a double tap --
   so every button on a phone answers immediately as a side effect.

   The 16px floor on form controls is the part that matters on iOS. Safari has
   ignored user-scalable=no since iOS 10 on purpose, and instead zooms the page
   in whenever you focus an input whose text is under 16px -- which is what
   actually made the site jump about. At 16px it has no reason to.
   Pinch-zoom still works on iPhone by design, and that is not something a
   website can or should override. */
html{touch-action:manipulation}
@media(pointer:coarse){
  input,select,textarea,.mkin,.embq,.svfrow input{font-size:16px}
}

/* ---- chrome ---- */
/* THE NAV MUST OUTRANK EVERY PAGE ELEMENT.
   position:sticky with a z-index makes the nav its own stacking context, so
   everything inside it -- the notification panel included -- is capped at the
   nav's own level however high its personal z-index is. At 20 the bell panel
   opened UNDERNEATH the search box (60) and the suggestion dropdown. Site
   chrome sits above page content, so the nav goes above the highest thing on
   any page (80). Modal <dialog> is unaffected: it renders in the top layer. */
nav{position:sticky;top:0;z-index:120;backdrop-filter:blur(14px);
  background:rgba(5,6,8,.86);border-bottom:1px solid var(--line)}
.navin{max-width:1060px;margin:0 auto;padding:11px 18px;
  display:flex;gap:6px;align-items:center}
.navleft{display:flex;align-items:center;flex:none}
.navlinks{display:flex;gap:6px;align-items:center;min-width:0;overflow-x:auto;
  scrollbar-width:none}
.navlinks::-webkit-scrollbar{display:none}
.navright{display:flex;gap:9px;align-items:center;margin-left:auto;flex-shrink:0;
  padding-left:10px}
.btn-sm{padding:8px 15px;border-radius:10px;font-size:14px;font-weight:650;
  background:var(--acc);color:#04121d;white-space:nowrap;
  transition:transform .16s var(--spring),filter .18s var(--ease)}
.btn-sm.ghost{background:transparent;color:var(--dim);border:1px solid var(--line);
  font-weight:500}
/* the avatar button */
.meBtn{display:flex;align-items:center;gap:8px;padding:4px 4px 4px 10px;
  border-radius:12px;border:1px solid var(--line);background:var(--card);
  transition:border-color .2s var(--ease),transform .2s var(--spring)}
.meBtn .nm{font-size:13.5px;font-weight:600;max-width:110px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.meBtn img,.meBtn .gen{width:30px;height:30px;border-radius:9px;flex-shrink:0;
  object-fit:cover;display:block}
/* the tick sits on the corner of the avatar, overlapping it slightly */
.avwrap{position:relative;display:block;flex-shrink:0}
.meBtn .vmark{flex-shrink:0;margin-right:2px}
/* On a phone the name is hidden, so the mark keeps its meaning by sitting on
   the avatar instead of floating on its own. */
@media (max-width:559px){
  .meBtn .vmark{position:absolute;right:-5px;bottom:-4px;margin:0;
    filter:drop-shadow(0 1px 4px rgba(0,0,0,.7))}
  .meBtn{position:relative}
}
.meBtn .gen{display:inline-flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;background:var(--card2);color:var(--dim)}
@media (max-width:559px){.meBtn .nm{display:none}.meBtn{padding:4px}}
.navin::-webkit-scrollbar{display:none}
.brand{font-weight:800;letter-spacing:-.03em;font-size:19px;margin-right:12px;
  white-space:nowrap;display:inline-flex;align-items:center;gap:5px}
.brand i{color:var(--brand);font-style:normal}
/* The mark is centred on the LETTERS, not on the line box. Flex centring lines
   it up with the full 29px line box — descender space included — which drops it
   5.2px below the caps and reads as sagging. That gap is 0.275em at any size,
   so the nudge is expressed in em and survives a font-size change.
   Height is a little over the cap height, the way a mark usually sits in a
   lockup: level with the word, not shrunk to fit inside it. */
.bmark{height:1.15em;width:auto;object-fit:contain;flex:none;
  transform:translateY(-.275em);
  transition:transform .22s var(--spring)}
nav a.tab{color:var(--dim);font-size:14.5px;padding:7px 13px;border-radius:9px;
  white-space:nowrap;transition:color .18s var(--ease),background .18s var(--ease)}
nav a.tab.on{color:var(--fg);background:var(--card2)}
.wrap{max-width:1060px;margin:0 auto;padding:30px 18px 96px}

/* ---- type ---- */
h1{font-size:clamp(28px,6vw,44px);line-height:1.04;margin:0 0 8px;
  letter-spacing:-.035em;font-weight:800}
h2{font-size:13px;text-transform:uppercase;letter-spacing:.1em;color:var(--dim);
  margin:34px 0 12px;font-weight:600}
.sub{color:var(--dim);margin:0 0 24px;font-size:16px;max-width:60ch}

/* ---- search ---- */
form.q{display:flex;gap:9px;margin:0 0 26px}
form.q input{flex:1;min-width:0;padding:15px 17px;border-radius:12px;
  border:1px solid var(--line);background:var(--card);color:var(--fg);font-size:16px;
  transition:border-color .2s var(--ease),box-shadow .2s var(--ease),background .2s}
form.q input::placeholder{color:var(--dimmer)}
form.q input:focus{outline:0;border-color:var(--acc);background:var(--card2);
  box-shadow:0 0 0 4px var(--acc-dim)}
form.q button{padding:15px 22px;border-radius:12px;border:0;background:var(--fg);
  color:var(--bg);font-weight:700;cursor:var(--xhp);font-size:16px;white-space:nowrap;
  transition:transform .16s var(--ease),opacity .16s}
form.q button:active{transform:translateY(0) scale(.98)}

/* The roster table: an avatar and a name are one thing, so they get a gap and
   a shared baseline rather than sitting flush against each other. */
.ptable td.lead{display:flex;align-items:center;gap:9px}
.ptable td.lead .mini{border-radius:50%;flex:none}
.ptable td{vertical-align:middle}
.ptable .num{white-space:nowrap}

/* ---- social: timeline, rail, servers ----
   Two columns where there is room, one where there is not. The rail is the
   part that gets dropped on a narrow screen, never the timeline. */
.soclayout{display:grid;gap:18px;grid-template-columns:minmax(0,1fr) 310px;align-items:start}
.socmain{min-width:0}
.socrail{display:flex;flex-direction:column;gap:14px;position:sticky;top:78px}
@media(max-width:1000px){
  .soclayout{grid-template-columns:1fr}
  /* Content first. The rail is context, and on a phone it was pushing the
     timeline (or the clan list) below three cards of preamble. */
  .socrail{position:static;order:2}
  .socmain{order:1}
}

.railcard{border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  padding:18px 20px}
.railhead{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--dimmer);
  font-weight:700;margin-bottom:4px}
.raillead{color:var(--dim);font-size:13px;margin:0 0 10px}
.sglist{display:flex;flex-direction:column;gap:4px}
.sfrow{display:flex;align-items:center;gap:9px;padding:6px 0}
.sfrow .mini{border-radius:50%;flex:none}
.sfmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.sfmain .lnk{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sfmeta{display:flex;align-items:center;gap:6px;font-size:11.5px;flex-wrap:wrap}
.sftag{font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;font-weight:700;
  color:var(--acc);border:1px solid var(--acc-dim);border-radius:5px;padding:1px 4px}
.sffollow{flex:none}

/* ---- a clan's own page ----
   The banner is a band, not a hero: the roster is what the page is for, and a
   full-bleed image would push it under the fold. Fixed height so every clan
   page opens the same shape whatever artwork it happens to have. */
/* The banner FADES OUT downward instead of ending on a hard edge, so the page
   grows out of the artwork rather than sitting under a photograph. The mask
   does the fade on the image itself, which keeps it working on any page
   background and in either theme -- an overlay would have to know the colour
   behind it. Older browsers without mask support simply get the full image,
   which is the old behaviour and still fine. */
.clanban{overflow:hidden;height:clamp(130px,20vw,210px);margin-bottom:-46px;
  border-radius:var(--r) var(--r) 0 0}
.clanban img{width:100%;height:100%;object-fit:cover;object-position:50% 40%;display:block;
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 34%,rgba(0,0,0,.55) 68%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 0%,#000 34%,rgba(0,0,0,.55) 68%,transparent 100%)}
/* Lifted onto the banner, with a scrim behind the text so any artwork works. */
.clanhead.onban{position:relative;z-index:1;padding:0 4px;
  text-shadow:0 2px 12px rgba(0,0,0,.6)}
.clanhead.onban .clface{box-shadow:0 6px 22px rgba(0,0,0,.6)}
.clanhead{display:flex;align-items:center;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.clanhead .clface{width:64px;height:64px;border-radius:18px;flex:none}
.clanheadT{flex:1;min-width:0}
.clanheadT h1{margin:0;font-size:clamp(24px,4vw,34px);line-height:1.15}
.clanheadT .sub{margin:4px 0 0}
.clanlink{display:inline-flex;align-items:center;gap:9px;text-decoration:none;color:var(--fg)}
.clanlink .clface{width:30px;height:30px;border-radius:9px;flex:none}

/* Discord's mark, on Discord's colour, so the button is recognised before it
   is read. */
.dcbtn{display:inline-flex;align-items:center;gap:8px;flex:none;border-radius:10px;
  padding:9px 15px;background:#5865f2;color:#fff;font-weight:700;font-size:13.5px;
  text-decoration:none;transition:filter .15s var(--ease),transform .15s var(--ease)}
.dcico{flex:none}
.clanedit{flex:none;white-space:nowrap}

/* ---- the competitive line-up, as a roster reveal ----
   Portrait tiles in a row, the picture filling each one and a plate across the
   bottom carrying the name. Short on purpose: this sits ABOVE the member table,
   so it is a strip, not a hero. Every tile is the same size whatever picture it
   happens to hold. */
/* On the clan page every other block is a card, so this is one too -- same
   radius, same padding as .card.pad. The tiles are the interesting part; the
   container should not be a second thing competing with them. */
.compstrip{margin-bottom:16px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);padding:18px 20px}
.compstrip .ctile{background:var(--card2)}
.comphead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.comphead b{font-size:15px}
.comphead .dim{font-size:12.5px}
/* FIXED-WIDTH COLUMNS, not 1fr. With aspect-ratio plus a max-height, the height
   cap decides the WIDTH -- so every tile sat at 78px inside a 150px column with
   a gap beside it, looking scattered. Give the column the width and let the
   ratio give the height.
   (No backticks in this comment. The whole stylesheet is one template literal
   and a backtick here ends it: that is what just took the file down.) */
.ctiles{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,116px);
  justify-content:start;align-items:stretch}
.ctile{position:relative;display:block;aspect-ratio:3/4;overflow:hidden;
  border-radius:12px;border:1px solid var(--line);background:var(--card2);
  text-decoration:none;color:var(--fg);isolation:isolate;
  animation:rise .5s var(--ease) backwards;animation-delay:calc(var(--i)*.05s);
  transition:border-color .18s var(--ease),transform .18s var(--ease)}

/* The picture fills the tile; the lettered fallback fills it just the same, so
   a member with no avatar does not leave a hole in the row. */
.ctileArt{position:absolute;inset:0;display:block}
/* TOP-ANCHORED. These are full-body operator renders; centring them filled the
   tiles with boots. object-position keeps the head in frame at any tile size. */
.ctileChar{width:100%;height:100%;object-fit:cover;object-position:50% 0%;display:block;
  filter:saturate(1.02) contrast(1.04)}
.ctileArt .mini{width:100%;height:100%;border-radius:0;object-fit:cover;display:block;
  filter:saturate(1.05) contrast(1.03)}
.ctileArt .mini.gen{display:flex;align-items:center;justify-content:center;font-size:44px;
  font-weight:800}
/* A wash from the card colour up, so the plate always has something to sit on
   whatever the picture underneath is doing. */
.ctile::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(to top,var(--card) 4%,rgba(0,0,0,.55) 34%,rgba(0,0,0,.05) 62%)}
.ctile > :not(.ctileArt){position:absolute;z-index:2}


/* The name plate: a slight skew is the whole nod to the reveal graphics, and
   the text is un-skewed back so it stays readable. */
.ctilePlate{left:0;right:0;bottom:0;padding:9px 10px 10px;
  display:flex;flex-direction:column;gap:2px;
  border-top:2px solid var(--acc);transform:skewY(-1.5deg);transform-origin:left bottom;
  background:linear-gradient(to top,var(--card),color-mix(in srgb,var(--card) 70%,transparent))}
.ctileName{transform:skewY(1.5deg);font-weight:800;font-size:12.5px;letter-spacing:.01em;
  text-transform:uppercase;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ctileLead{transform:skewY(1.5deg);font-size:9px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--acc)}
.pill.comp{border-color:var(--acc);color:var(--acc)}

/* Inside a recruitment card the strip has a fraction of the width, so the
   tiles step down rather than wrapping onto three ragged rows. */
.ctiles.tight{grid-template-columns:repeat(auto-fill,74px);gap:7px}
.ctiles.tight .ctile{border-radius:9px}
.ctiles.tight .ctilePlate{padding:5px 6px 6px;border-top-width:2px}
.ctiles.tight .ctileName{font-size:10px}
.ctiles.tight .ctileArt .mini.gen{font-size:26px}

@media(max-width:560px){
  .ctiles{grid-template-columns:repeat(auto-fill,96px);gap:8px}
  .ctileName{font-size:11px}
}

/* ---- clans looking for members ----
   Same rule as the server cards: every card emits every block and each block is
   clamped and floored, so a clan with a long pitch and a full roster is exactly
   the size of one with neither. */
.clgrid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(330px,1fr));
  grid-auto-rows:1fr;align-items:stretch}
.clcard{position:relative;overflow:hidden;
  border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  padding:16px 18px;display:flex;flex-direction:column;gap:11px;
  transition:border-color .2s var(--ease),transform .2s var(--ease)}
/* THE BANNER COSTS NO HEIGHT. It is absolutely positioned behind the header
   rather than stacked above it, so a clan with artwork and one without are the
   same size -- which is the rule the whole grid depends on. It fades out
   downward with a mask, so the text over it stays readable whatever the image
   is doing and the card still ends in its own background colour. */
.clbanBg{position:absolute;top:0;left:0;right:0;height:108px;z-index:0;
  pointer-events:none;display:block}
/* A scrim over the artwork, weighted to the left where the name and tag sit.
   Without it readability depends on whichever image a clan happens to upload,
   which is not something a layout should be gambling on. */
.clbanBg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to right,var(--card) 0%,rgba(0,0,0,.45) 46%,rgba(0,0,0,.12) 100%)}
.clbanBg img{width:100%;height:100%;object-fit:cover;object-position:50% 40%;display:block;
  opacity:.42;
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,rgba(0,0,0,.6) 45%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 0%,rgba(0,0,0,.6) 45%,transparent 100%)}
/* Everything the card actually says sits above the artwork. */
.clcard > :not(.clbanBg){position:relative;z-index:1}
.cltop{display:flex;align-items:center;gap:12px;min-height:52px}
.clface{width:52px;height:52px;border-radius:14px;flex:none;object-fit:cover;
  background:var(--card2);box-shadow:0 2px 12px rgba(0,0,0,.45)}
.clface.letter{display:flex;align-items:center;justify-content:center;font-weight:800;
  font-size:17px;color:var(--dim);letter-spacing:.02em}
.clname{min-width:0;flex:1;display:flex;flex-direction:column;gap:3px}
.clname b{font-size:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  line-height:20px}
.cltag{color:var(--acc)}
.clsub{display:flex;align-items:center;gap:9px;font-size:12px}
.clmode{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  border-radius:6px;padding:3px 7px;border:1px solid var(--line);color:var(--dim)}
.clmode.competitive{color:var(--acc);border-color:var(--acc-dim)}
.clmode.casual{color:var(--cash);border-color:color-mix(in srgb,var(--cash) 45%,transparent)}
.clblurb{margin:0;font-size:13.5px;line-height:20px;min-height:40px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.clblurb .dimmer,.clrlist .dimmer{color:var(--dimmer)}
.clwant,.clroster{display:flex;flex-direction:column;gap:6px;min-height:52px}
.clwlab{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--dimmer);
  font-weight:700}
.clwvals{display:flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:12.5px}
.clrank{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);
  border-radius:7px;padding:3px 8px;font-size:11.5px;color:var(--dim)}
.clrankico{width:15px;height:15px}
.clkd{border:1px solid var(--acc-dim);color:var(--acc);border-radius:7px;padding:3px 8px;
  font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums}
.clrlist{display:flex;flex-wrap:wrap;gap:7px;align-items:center}
.clrp{display:inline-flex;align-items:center;gap:5px;text-decoration:none;color:var(--fg);
  font-size:12px;border:1px solid var(--line);border-radius:999px;padding:2px 9px 2px 2px}
.clrp .mini{border-radius:50%;flex:none}
/* How to reach them: a handle to copy, a server to open, or a sentence.
   Fixed height so a clan giving all three is the same size as one giving one. */
.clcontact{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-height:32px;
  font-size:12.5px}
.clat{display:inline-flex;align-items:center;border:1px solid var(--line);
  border-radius:8px;padding:4px 10px;color:var(--fg);background:var(--card2);
  font-variant-numeric:tabular-nums;user-select:all}
.cljoin{display:inline-flex;align-items:center;gap:6px;border-radius:8px;padding:4px 11px;
  background:var(--acc);color:var(--bg);font-weight:700;text-decoration:none;font-size:12px}
.clcontact .clhow{color:var(--dim);white-space:normal}
.clfoot{margin-top:auto;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding-top:6px;border-top:1px solid var(--line);min-height:38px}
.clhow{flex:1;min-width:0;font-size:12.5px;color:var(--dim);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.clhow b{color:var(--fg)}
.clleft{font-size:11px;color:var(--dimmer);white-space:nowrap}

/* ---- the leader's own panel ----
   Collapsible, because everything open at once was a wall of form. <details>
   does it with no JavaScript, so it survives a failed script and works from the
   keyboard for free. */
.clmanage{margin-bottom:16px;overflow:hidden}
.clhead{display:flex;align-items:center;gap:12px;padding:16px 18px;
  border-bottom:1px solid var(--line)}
.clhead .clface{width:40px;height:40px;border-radius:12px}
.clheadT{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.clheadT b{font-size:15px}
.clheadT .dim{font-size:12.5px}
.clpill{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  border-radius:999px;padding:4px 10px;border:1px solid var(--line);color:var(--dimmer)}
.clpill.live{color:var(--cash);border-color:color-mix(in srgb,var(--cash) 45%,transparent)}

.clsec{border-bottom:1px solid var(--line)}
.clsec:last-child{border-bottom:0}
.clsec > summary{display:flex;align-items:center;gap:10px;padding:14px 18px;cursor:var(--xhp);
  list-style:none;user-select:none;transition:background .15s var(--ease)}
.clsec > summary::-webkit-details-marker{display:none}
.clsec > summary:focus-visible{outline:2px solid var(--acc);outline-offset:-2px}
.clsecT{font-weight:700;font-size:14px}
.clsecS{flex:1;color:var(--dimmer);font-size:12.5px}
/* A chevron drawn from a rotated corner, so there is no icon file to load. */
.clchev{width:8px;height:8px;flex:none;border-right:2px solid var(--dim);
  border-bottom:2px solid var(--dim);transform:rotate(45deg) translate(-2px,-2px);
  transition:transform .2s var(--ease)}
.clsec[open] > summary .clchev{transform:rotate(225deg) translate(-2px,-2px)}
.clsecB{padding:4px 18px 18px}

/* ---- a checkbox that belongs on a dark page ----
   The browser's own box is a white square and cannot be styled into anything
   else. The real input stays for the keyboard and for forms without scripting;
   it is just moved out of sight and a drawn box follows its :checked state. */
.cchips{display:flex;flex-wrap:wrap;gap:8px}
.cchip{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--line);
  border-radius:10px;padding:7px 12px 7px 9px;font-size:12.5px;cursor:var(--xhp);
  color:var(--dim);background:var(--card2);
  transition:border-color .15s var(--ease),background .15s var(--ease),color .15s var(--ease)}
.cchip input{position:absolute;opacity:0;width:0;height:0;margin:0}
.cbox{width:16px;height:16px;flex:none;border-radius:5px;border:1.5px solid var(--line);
  background:var(--bg);position:relative;
  transition:background .15s var(--ease),border-color .15s var(--ease)}
/* The tick: two borders of an empty box, rotated. */
.cbox::after{content:"";position:absolute;left:4.5px;top:1px;width:4px;height:8px;
  border-right:2px solid var(--bg);border-bottom:2px solid var(--bg);
  transform:rotate(45deg) scale(.4);opacity:0;
  transition:opacity .15s var(--ease),transform .15s var(--ease)}
.cchip input:checked ~ .cbox{background:var(--acc);border-color:var(--acc)}
.cchip input:checked ~ .cbox::after{opacity:1;transform:rotate(45deg) scale(1)}
.cchip:has(input:checked){border-color:var(--acc);background:var(--acc-dim);color:var(--fg)}
.cchip input:focus-visible ~ .cbox{outline:2px solid var(--acc);outline-offset:2px}
.cchip .mini{border-radius:50%}
.clrankico{width:16px;height:16px}
.clld{font-style:normal;font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--acc);font-weight:700}

.clform{display:flex;flex-direction:column;gap:14px}
.clfrow{display:grid;gap:12px;grid-template-columns:1fr 1fr}
.clfld{display:flex;flex-direction:column;gap:7px;font-size:12.5px;color:var(--dim)}
.clfld > span{font-weight:700;color:var(--fg);font-size:12px}
.clfld i{font-style:normal;color:var(--dimmer);font-weight:400;text-transform:none}
.clfld .mkin{width:100%}
/* A file picker that matches the site, built on the pattern the feed composer
   already uses: a label styled as a button, with a plain hidden input inside
   it. Clicking the label reaches the input, and the input stays a normal
   submittable control -- which the previous absolutely-positioned, zero-sized
   version was not, in Safari. */
.filepick{display:flex;align-items:center;gap:11px;min-width:0;flex-wrap:wrap}
.filename{min-width:0;font-size:12.5px;color:var(--dimmer);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.filename.set{color:var(--fg)}
.clpicrow{display:flex;align-items:flex-start;gap:14px}
.clpicrow .clface{width:56px;height:56px;border-radius:16px}
.clbanPrev{display:block;border-radius:10px;overflow:hidden;border:1px solid var(--line);
  height:84px;background:var(--card2)}
.clbanPrev img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:760px){
  .clfrow{grid-template-columns:1fr}
}

/* ---- the server directory ----
   A card is mostly the server's own artwork, because that is what somebody
   posting their server wants shown. Fixed banner height so a grid of them
   lines up whatever art each one happens to have. */
.svform{margin-bottom:16px}
.svfrow{display:flex;gap:8px;flex-wrap:wrap}
.svfrow input{flex:1;min-width:170px;padding:11px 13px;border-radius:10px;
  border:1px solid var(--line);background:var(--card2);color:var(--fg);font-size:14px}
.svfrow input:focus{outline:0;border-color:var(--acc)}
.svfrow .btn{padding:11px 20px;border-radius:10px;border:0;background:var(--fg);
  color:var(--bg);font-weight:700;cursor:var(--xhp)}
.svgrid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));
  grid-auto-rows:1fr;align-items:stretch}
.svcard{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--card);
  display:flex;flex-direction:column;transition:border-color .2s var(--ease),transform .2s var(--ease)}
.svcard.dead{opacity:.6}
/* A pinned card says so on the card itself. Without the badge the only clue is
   its position, which reads as "biggest server" rather than "chosen". */
.svcard.pinned{border-color:color-mix(in srgb,var(--acc) 55%,var(--line))}
.svpin{position:absolute;top:9px;right:9px;z-index:2;font-size:9.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.07em;color:var(--bg);background:var(--acc);
  border-radius:6px;padding:3px 7px;box-shadow:0 2px 10px rgba(0,0,0,.45)}
.svcard{position:relative}
.svbanner{height:86px;background:var(--card2);overflow:hidden}
.svbanner img{width:100%;height:100%;object-fit:cover;display:block}
.svbanner.none{background:linear-gradient(135deg,var(--card2),var(--card))}
.svbody{padding:12px 14px 14px;display:flex;flex-direction:column;gap:8px;flex:1}
.svtop{display:flex;align-items:center;gap:11px;margin-top:-34px;min-height:58px}
.svicon{width:52px;height:52px;border-radius:15px;flex:none;border:3px solid var(--card);
  background:var(--card2);object-fit:cover}
.svicon.letter{display:flex;align-items:center;justify-content:center;font-weight:800;
  font-size:21px;color:var(--dim)}
.svname{min-width:0;flex:1;padding-top:30px}
.svname b{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:15px;line-height:20px}
.svcounts{display:flex;align-items:center;gap:5px;font-size:12px;color:var(--dim);
  font-variant-numeric:tabular-nums}
.svdot{width:7px;height:7px;border-radius:50%;background:var(--dimmer);display:inline-block}
.svdot.online{background:#3ba55c}
/* EVERY CARD IS THE SAME HEIGHT, whatever it happens to contain.
   Grid stretches cards within a ROW for free, which hides the problem until a
   second row appears. So each part is given a fixed share instead: the banner
   and header are fixed, the two text blocks are clamped to an exact number of
   lines AND floored at that height so an absent tagline still occupies its
   line, and the footer is pushed to the bottom. Content can then vary
   arbitrarily without any card being a different size from its neighbour. */
.svtag{margin:0;font-size:13.5px;line-height:20px;min-height:20px;
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.svdesc{margin:0;font-size:12.5px;color:var(--dim);line-height:19px;min-height:38px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.svdesc .dimmer{color:var(--dimmer)}
.svfoot{margin-top:auto;display:flex;gap:8px;align-items:center;padding-top:4px;min-height:34px}
.svgone{font-size:12.5px;color:var(--orange)}
.mini-btn.danger{color:var(--bad);border-color:transparent}

/* ---- search suggestions ----
   The box hangs off the form, which is why the form is positioned. It sits
   ABOVE the results underneath it and is only ever shown when it has rows in
   it, so an empty query never leaves an empty panel floating on the page. */
/* THE Z-INDEX GOES ON THE FORM, not only on the box. The form animates in with
   .rise, and a transform makes it a stacking context of its own at z-index
   auto -- so the stat tiles below it (also transformed, also their own context,
   and later in the DOM) painted straight over the suggestions no matter what
   z-index the box itself carried. Raising the form raises everything in it. */
form.q[data-suggest]{position:relative;flex-wrap:wrap;z-index:60}
.sgbox{position:absolute;top:calc(100% + 7px);left:0;right:0;z-index:60;
  max-height:min(58vh,420px);overflow-y:auto;border-radius:var(--r);
  border:1px solid var(--line);background:var(--card);padding:5px;
  box-shadow:0 20px 48px rgba(0,0,0,.5)}
.sghead{padding:9px 11px 6px;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.07em;color:var(--dimmer);font-weight:700}
.sgrow{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:9px;
  color:var(--fg);text-decoration:none;font-size:14.5px}
.sgrow .mini{border-radius:50%;flex:none}
.sgname{flex:1;min-width:0;display:flex;align-items:baseline;gap:6px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sgname b{overflow:hidden;text-overflow:ellipsis}
.sgmeta{flex:none;display:flex;align-items:center;gap:6px;color:var(--dim);
  font-size:13px;font-variant-numeric:tabular-nums}
.sgrank{width:17px;height:17px}
.sgban{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--bad);font-weight:700}
.sgrow.on{background:var(--card2)}
.sgrow.on{outline:1px solid var(--acc)}
@media(max-width:560px){
  .sgmeta .dim{display:none}
}

/* ---- surfaces ---- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden}
.pad{padding:18px 20px}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:2px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.stat{background:var(--card);padding:16px 18px}
.stat b{display:block;font-size:clamp(20px,4.4vw,26px);line-height:1.15;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.stat span{color:var(--dim);font-size:11px;text-transform:uppercase;
  letter-spacing:.08em;display:block;margin-top:3px}

/* ---- tables that become cards on phones ---- */
table{border-collapse:collapse;width:100%}
th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--dim);font-weight:600;padding:12px 16px;border-bottom:1px solid var(--line)}
td{padding:13px 16px;border-bottom:1px solid var(--line)}
tbody tr{transition:background .16s var(--ease)}
tbody tr:last-child td{border-bottom:0}
.rk{color:var(--dimmer);width:44px;font-variant-numeric:tabular-nums}
.num{text-align:right;font-variant-numeric:tabular-nums}
.b{font-weight:700}
.dim{color:var(--dim)}
.good{color:var(--good)}.bad{color:var(--bad)}
/* Anything hidden stays hidden. A later rule setting display: on the same
   element would otherwise outrank the browser's own [hidden] and leave it on
   screen — which is exactly how the emblem picker ended up covering the page. */
[hidden]{display:none!important}
tr.us{background:rgba(240,180,63,.09)}
tr.us .b{color:var(--gold)}
.pill{display:inline-block;padding:3px 10px;border-radius:99px;font-size:12px;
  border:1px solid var(--line);color:var(--dim);white-space:nowrap}
.pill.on{border-color:var(--purple);color:var(--purple);
  background:rgba(139,123,247,.10)}
.pill.gold{border-color:var(--gold);color:var(--gold);background:rgba(240,180,63,.10)}
/* Rank text carries its own ladder colour, so a board scans by colour alone. */
.tier{font-weight:600}
.ev .ico{font-size:15px}
.ico.join{color:var(--teal)}.ico.leave{color:var(--orange)}
.ico.rankup{color:var(--lime)}.ico.rankdown{color:var(--orange)}
.ico.ban{color:var(--red)}.ico.unban{color:var(--teal)}
.ico.leader{color:var(--gold)}
/* Top three on any board get the medal hues rather than plain grey. */
tr:nth-child(1) .rk{color:var(--gold);font-weight:700}
tr:nth-child(2) .rk{color:#c7ced8;font-weight:700}
tr:nth-child(3) .rk{color:var(--orange);font-weight:700}

/* Phones get the SAME table as a tablet, not a rebuilt stack of cards: the
   table keeps its real shape and the card scrolls sideways instead. A row you
   can compare against the row above it is the whole point of a leaderboard,
   and the stacked version threw that away. */
@media (max-width:719px){
  .card:has(table){overflow-x:auto;-webkit-overflow-scrolling:touch}
  .card table{min-width:600px}
  th,td{padding-left:10px;padding-right:10px;white-space:nowrap}
  td.lead{white-space:nowrap}
}

/* ---- tabs ---- */
/* THEY WRAP, THEY DO NOT SCROLL.
   This was a scrolling row with its scrollbar hidden, which on a desktop means
   the tabs past the right edge are unreachable and nothing says they are
   there. The admin screen has ten of them. Wrapping shows the lot; the
   horizontal scroll stays only as a fallback for a very narrow window, and
   there it gets a visible bar. */
.tabs{display:flex;gap:7px;margin:26px 0 16px;flex-wrap:wrap;padding-bottom:2px}
@media (max-width:520px){
  .tabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}
  .tabs::-webkit-scrollbar{height:6px}
  .tabs::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
}
.tabs button{padding:9px 16px;border-radius:10px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);cursor:var(--xhp);font-size:14.5px;
  white-space:nowrap;transition:all .18s var(--ease)}
.tabs button.on{background:var(--fg);color:var(--bg);border-color:var(--fg);font-weight:650}

/* ---- events ---- */
.ev{display:flex;gap:14px;padding:13px 0;border-bottom:1px solid var(--line);
  align-items:baseline}
.ev:last-child{border-bottom:0}
.ev .when{color:var(--dimmer);font-size:13px;min-width:96px;
  font-variant-numeric:tabular-nums;flex-shrink:0}
.ev .ico{width:20px;flex-shrink:0;text-align:center;color:var(--dim)}
@media (max-width:519px){
  .ev{flex-wrap:wrap;gap:4px 12px}
  .ev .when{min-width:0;width:100%;order:2;font-size:12px}
}


/* identity header */
.idhead{display:flex;gap:16px;align-items:center;margin:0 0 6px}
.pfp{width:96px;height:96px;border-radius:26px;flex-shrink:0;object-fit:cover;
  border:1px solid var(--line);background:var(--card2)}
/* Discord banner behind a profile header. Fades out downward so the name sits
   on the page's own background rather than on busy artwork. */
.pbanner{height:132px;border-radius:16px;background-size:cover;background-position:center;
  margin:0 0 -46px;position:relative;
  -webkit-mask-image:linear-gradient(180deg,#000 38%,transparent 100%);
  mask-image:linear-gradient(180deg,#000 38%,transparent 100%)}
.pbanner.flat{background-image:linear-gradient(160deg,var(--a),transparent 78%)}
/* The generated stand-in. Two hues plus a soft highlight, so it reads as a
   deliberate cover rather than a flat block where a picture failed to load. */
.pbanner.gen{background-image:
  radial-gradient(120% 150% at 18% -30%,color-mix(in srgb,var(--a) 55%,transparent),transparent 62%),
  linear-gradient(118deg,var(--a) 0%,var(--b) 58%,transparent 96%)}
.idhead{position:relative;z-index:1}
.idmeta{min-width:0;flex:1}
@media(max-width:560px){.pbanner{height:104px;margin-bottom:-40px}}

/* Follower / following counts under the name. */
/* Followers / following, as a pair of tabs on the list page. */
.ftabs{display:inline-flex;gap:4px;padding:4px;background:var(--card);
  border:1px solid var(--line);border-radius:12px;margin:0 0 14px}
.ftab{padding:8px 16px;border-radius:9px;font-size:14px;color:var(--dim);
  text-decoration:none;transition:color .18s var(--ease),background .18s var(--ease)}
.ftab b{color:var(--fg);font-weight:700}
.ftab.on{background:var(--card2);color:var(--fg)}
.fstats{display:flex;gap:14px;margin-top:6px;font-size:13.5px;color:var(--dim)}
.fstat{color:var(--dim);text-decoration:none}
.fstat b{color:var(--fg);font-weight:650}
.fbtnform{margin-left:auto;flex:none}
.fbtn{margin-left:auto;flex:none;padding:9px 20px;border-radius:11px;cursor:var(--xhp);
  border:1px solid var(--acc);background:var(--acc);color:#04121d;font:inherit;
  font-weight:650;font-size:14px;text-decoration:none;display:inline-block;
  transition:transform .16s var(--spring),background .18s var(--ease),color .18s var(--ease)}
.fbtn.on{background:transparent;color:var(--dim);border-color:var(--line)}

/* Editing your own banner: folded away until wanted, so somebody reading their
   own profile is not looking at a form. */
.banedit{margin:-6px 0 16px}
.banedit > summary{display:inline-flex;align-items:center;gap:8px;cursor:var(--xhp);
  list-style:none;font-size:13px;color:var(--dim);padding:6px 0}
.banedit > summary::-webkit-details-marker{display:none}
.banedit > summary:hover{color:var(--fg)}
.baneditT{font-weight:600}
.banedit[open] > summary .clchev{transform:rotate(225deg) translate(-2px,-2px)}
.banedit form{margin-top:8px}

/* Picking your own emblem: a wall of pictures with a filter over it. */
.embq{width:100%;margin-bottom:12px;padding:11px 13px;border-radius:10px;
  border:1px solid var(--line);background:var(--card2);color:var(--fg);font-size:14px}
.embq:focus{outline:0;border-color:var(--acc)}
.embgrid{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(92px,1fr));
  max-height:min(62vh,540px);overflow-y:auto;padding:2px}
.embcell{display:flex;flex-direction:column;align-items:center;gap:5px;padding:8px 5px;
  border:1px solid var(--line);border-radius:11px;background:var(--card2);cursor:var(--xhp);
  color:var(--dim);font:inherit;font-size:10.5px;text-align:center;
  transition:border-color .15s var(--ease),transform .15s var(--ease)}
.embcell img{width:46px;height:46px;object-fit:contain}
.embcell span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* Already spoken for. Still clickable -- an emblem can legitimately repeat. */
.embcell.used{opacity:.42}
.embdone{display:flex;align-items:center;gap:16px}
.emb.big{width:64px;height:64px;object-fit:contain;flex:none}

/* The add-to-home banner. Sits above the safe area so it clears the iPhone
   home indicator, and above everything else so a page cannot bury it. */
.a2hs{position:fixed;left:10px;right:10px;z-index:200;
  bottom:calc(10px + env(safe-area-inset-bottom,0px));
  animation:a2hsIn .32s var(--ease) both}
.a2hsIn{display:flex;align-items:center;gap:12px;padding:12px 12px 12px 13px;
  border-radius:16px;border:1px solid var(--line);background:var(--card);
  box-shadow:0 16px 44px rgba(0,0,0,.6);max-width:520px;margin:0 auto}
.a2hsIco{border-radius:12px;flex:none}
.a2hsT{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.a2hsT b{font-size:14px}
.a2hsT span{font-size:12px;color:var(--dim);line-height:1.45}
.a2hsGo{flex:none;border:0;border-radius:10px;padding:9px 16px;background:var(--acc);
  color:var(--bg);font-weight:700;font-size:13.5px;cursor:var(--xhp)}
.a2hsX{flex:none;border:0;background:none;color:var(--dimmer);font-size:22px;
  line-height:1;padding:2px 4px;cursor:var(--xhp)}
@keyframes a2hsIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* The bell and its panel. */
.bellwrap{position:relative}
.bellbtn{position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:10px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);cursor:var(--xhp);
  transition:color .18s var(--ease),border-color .18s var(--ease)}
.bellbtn[aria-expanded="true"]{color:var(--fg);border-color:var(--dim)}
.bdot{position:absolute;top:-5px;right:-5px;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;background:var(--pink);color:#180a12;font-size:10.5px;
  font-weight:750;display:flex;align-items:center;justify-content:center;
  border:2px solid var(--bg)}
.bellpanel{position:absolute;right:0;top:calc(100% + 9px);width:min(370px,92vw);
  background:var(--card);border:1px solid var(--line);border-radius:15px;z-index:60;
  box-shadow:0 18px 46px rgba(0,0,0,.55);overflow:hidden;
  animation:panelIn .24s var(--ease) both}
.bhead{display:flex;align-items:center;justify-content:space-between;
  padding:12px 14px;border-bottom:1px solid var(--line);font-size:14px}
.nlist{max-height:min(60vh,430px);overflow-y:auto}
.nlist .ev{padding-left:14px;padding-right:14px}
/* The Manage menu, inside the bell panel. Its switches are the same drawn
   checkbox the clan panel uses, so there is one control in the whole site
   rather than two that look almost alike. */
/* A button does NOT inherit colour the way a link does -- font:inherit covers
   the type and leaves the browser's own buttontext black, which on this
   background is invisible. Say the colour. */
.nptoggle{background:none;border:0;padding:0;font:inherit;cursor:var(--xhp);
  color:var(--acc)}
.npbox{border-bottom:1px solid var(--line);background:var(--card2);
  max-height:min(72vh,620px);overflow-y:auto}
.nprefs{display:flex;flex-direction:column;gap:12px;padding:13px 14px}
.npgroup{display:flex;flex-direction:column;gap:6px}
.npdevice{display:flex;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--line);
  border-radius:11px;background:var(--card)}
.npdevice .npmain{flex:1;min-width:0}
.npdevice .btn{flex:none;padding:7px 13px;border-radius:9px;border:1px solid var(--line);background:var(--card2);
  color:var(--fg);font:inherit;font-size:12.5px;font-weight:650;cursor:var(--xhp)}
.npdevice .btn:disabled{color:var(--dim);cursor:default}
.npnote{margin:0;font-size:11.5px;line-height:1.45;color:var(--dimmer)}
.npnote b{color:var(--dim);font-weight:600}
.nphead{font-size:10px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dimmer);font-weight:700}
.npchip{width:100%;align-items:flex-start;padding:8px 10px;background:var(--card)}
.npchip .cbox{margin-top:1px}
.npmain{display:flex;flex-direction:column;gap:1px;min-width:0;text-align:left}
.npmain i{font-style:normal;font-size:11px;color:var(--dimmer)}
.npfoot{display:flex;flex-direction:column;gap:10px;padding-top:4px;
  border-top:1px solid var(--line)}
.npfoot .btn{align-self:flex-start;padding:8px 16px;border-radius:9px;border:0;
  background:var(--fg);color:var(--bg);font-weight:700;cursor:var(--xhp);font-size:13px}
.nempty{padding:26px 16px;text-align:center;color:var(--dim);font-size:14px}
.nempty span{font-size:12.5px;color:var(--dimmer)}
@keyframes panelIn{from{opacity:0;transform:translateY(-7px)}to{opacity:1;transform:none}}

.pfp.gen{display:inline-flex;align-items:center;justify-content:center;
  font-size:38px;font-weight:600;letter-spacing:-.02em}
.pfp.emba{object-fit:contain;padding:9px;background:var(--card2)}
/* Two faces on one card. The button is only as big as the picture, so the
   click target and the thing that turns are the same shape. */
/* The CARD turns, not the two faces separately. Rotating each face needs the
   faces to share a 3D context, which they did not, and the front simply never
   moved. Turning the container with preserve-3d is the reliable way: the back
   sits pre-flipped behind, and backface-visibility hides whichever is facing
   away. */
.pfpflip{width:96px;height:96px;flex-shrink:0;padding:0;border:0;background:none;
  cursor:var(--xhp);position:relative;border-radius:26px;transform-style:preserve-3d;
  /* An explicit identity rather than a bare none: going from no transform at all
     into a 3D matrix leaves the element unrotated until something else forces
     a recalc, so both ends of the transition are spelled the same way. */
  transform:perspective(700px) rotateY(0deg);
  transition:transform .55s var(--spring)}
.pfpflip.turned{transform:perspective(700px) rotateY(180deg)}
.pfpflip:focus-visible{outline:2px solid var(--acc);outline-offset:3px}
.pfpface{position:absolute;inset:0;backface-visibility:hidden;border-radius:26px;
  overflow:hidden}
.pfpface .pfp{width:100%;height:100%}
.pfpface.back{transform:rotateY(180deg)}
/* A quiet hint that there is a second side, so nobody has to guess. */
.pfpflip::after{content:"";position:absolute;right:-2px;bottom:-2px;width:15px;height:15px;
  border-radius:50%;background:var(--card2);border:1px solid var(--line);
  background-image:radial-gradient(circle at 50% 50%,var(--dim) 1.6px,transparent 1.7px);
  transition:border-color .18s var(--ease)}
.idhead h1{margin:0}
.dtag{color:var(--dim);font-size:14px;display:flex;align-items:center;gap:6px;margin-top:2px}
.dtag .dot{width:7px;height:7px;border-radius:50%;background:var(--purple);flex-shrink:0}
.rankicon{width:26px;height:26px;object-fit:contain;vertical-align:-7px;margin-right:6px}
.bigrank{display:flex;align-items:center;gap:10px}
.bigrank img{width:42px;height:42px;object-fit:contain}

/* players / clans toggle */
.seg{display:inline-flex;padding:3px;background:var(--card);border:1px solid var(--line);
  border-radius:11px;margin:0 0 12px;position:relative;isolation:isolate}
.mini-btn{padding:5px 10px;border-radius:7px;border:1px solid var(--line);
  background:var(--card2);color:var(--dim);font-size:12.5px;cursor:var(--xhp);
  transition:all .18s var(--ease)}
.mini-btn.on{color:var(--fg);border-color:var(--acc);background:var(--acc-dim)}
/* How full your tracking allowance is. */
.tcount{font-variant-numeric:tabular-nums;font-size:12.5px;color:var(--dim);
  border:1px solid var(--line);border-radius:999px;padding:3px 10px;white-space:nowrap}
.tcount.full{color:var(--orange);border-color:var(--orange)}
.trackcard .ign{font-size:14px}
/* Narrow column, so the rows lose the wide table gutters. */
.trackcard td{padding:10px 14px}
.trackcard .freealert{margin:12px 14px 0}
.trackcard .chint{margin:8px 14px 12px}
.trackcard .dim[style]{font-size:12px}
.btn{padding:12px 20px;border-radius:11px;border:0;background:var(--acc);
  color:#04121d;font-weight:700;font-size:15px;cursor:var(--xhp);
  transition:transform .16s var(--ease)}
.ta{width:100%;min-height:150px;padding:13px 15px;border-radius:11px;
  border:1px solid var(--line);background:var(--bg);color:var(--fg);
  font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;resize:vertical}
.ta:focus{outline:0;border-color:var(--acc);box-shadow:0 0 0 4px var(--acc-dim)}
.file{color:var(--dim);font-size:14px}
/* Every tab the same width, so a short word does not make a narrow button. */
.seg a{min-width:98px;text-align:center;}
.seg:has(a[data-mode="names"].on) .segpill{background:var(--pink)}
.seg a{padding:8px 18px;border-radius:8px;font-size:14px;color:var(--dim);
  position:relative;z-index:1;transition:color .28s var(--ease);
  -webkit-tap-highlight-color:transparent}
.seg a.on{color:#04121d;font-weight:650}
/* The pill SLIDES between options instead of each one repainting. Its position
   is measured in JS because the two labels differ in width; CSS does the move. */
.segpill{position:absolute;top:3px;bottom:3px;left:0;width:0;border-radius:9px;
  background:var(--acc);z-index:0;opacity:0;
  box-shadow:0 2px 12px rgba(78,168,240,.28);
  transition:transform .42s var(--spring),width .42s var(--spring),opacity .2s var(--ease)}
.seg.ready .segpill{opacity:1}
/* With JS off there is no pill, so the active option still has to look active. */
.seg:not(.ready) a.on{background:var(--acc)}
/* On a phone the tabs share the row instead of each claiming 98px. Four of
   them (Social's Timeline / Servers / Clans / People) needed 400px on a 375px
   screen, which pushed the whole page sideways. flex-basis 0 keeps them equal;
   min-width:auto stops any shrinking below its own word, so a label never
   clips. The home switch's sliding pill re-measures on resize, so it follows. */
@media (max-width:559px){
  .seg{display:flex;width:100%}
  .seg a{flex:1 1 0;min-width:auto;padding:8px 6px;white-space:nowrap}
}
.respane{animation:paneIn .42s var(--ease) both}
.respane[data-dir="left"]{animation-name:paneInLeft}
@keyframes paneIn{from{opacity:0;transform:translate3d(16px,0,0)}
  to{opacity:1;transform:none}}
@keyframes paneInLeft{from{opacity:0;transform:translate3d(-16px,0,0)}
  to{opacity:1;transform:none}}

/* chart */
.chart{position:relative}
.chead{display:flex;justify-content:space-between;align-items:baseline;
  gap:12px;margin-bottom:10px;flex-wrap:wrap}
.chead .cval{font-size:23px;font-variant-numeric:tabular-nums}
.chead .cdelta{font-size:14px;font-variant-numeric:tabular-nums}
.chart .cursor{transition:opacity .12s var(--ease)}
.chart .hit{cursor:var(--xh)}
.chint{color:var(--dimmer);font-size:12.5px;margin-top:8px}


/* match rows */
.games{display:flex;flex-direction:column;gap:8px}
.g{display:flex;align-items:center;gap:14px;padding:13px 16px;border-radius:12px;
  background:var(--card);border:1px solid var(--line);position:relative;overflow:hidden;
  animation:rise .44s var(--ease) both;animation-delay:calc(var(--i,0)*22ms);
  transition:border-color .18s var(--ease),transform .18s var(--ease)}
/* The map fills the whole row and is masked away before the right edge, so the
   numbers on that side always sit on flat colour and stay readable. */
.g .bg{position:absolute;inset:0;background-size:cover;background-position:center 38%;
  opacity:.38;transition:opacity .25s var(--ease);pointer-events:none;
  -webkit-mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,.85) 34%,transparent 72%);
  mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,.85) 34%,transparent 72%)}
.g>*:not(.bg){position:relative;z-index:1}
.g .res{width:5px;align-self:stretch;border-radius:99px;flex-shrink:0}
.g .res.w{background:var(--teal)}.g .res.l{background:var(--red)}
.g .mid{flex:1;min-width:0}
.g .ttl{font-weight:650;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.g .meta{color:var(--dim);font-size:13px;margin-top:2px}
.g .right{text-align:right;flex-shrink:0}
.g .dlt{font-variant-numeric:tabular-nums;font-weight:700}
.g .kda{color:var(--dim);font-size:13px;font-variant-numeric:tabular-nums}
.g .chev{color:var(--dimmer);flex-shrink:0}
.score{font-variant-numeric:tabular-nums;font-weight:700}
@media (max-width:519px){
  .g{gap:10px;padding:11px 13px}
  .g .meta{font-size:12px}
  /* Less bleed on a narrow card, or the text sits on top of the map. */
  .g .bg{-webkit-mask-image:linear-gradient(90deg,#000 0%,transparent 58%);
    mask-image:linear-gradient(90deg,#000 0%,transparent 58%);opacity:.3}
}
/* match detail */
.mteams{display:grid;gap:14px;grid-template-columns:1fr}
@media (min-width:760px){.mteams{grid-template-columns:1fr 1fr}}
.hero{position:relative;border-radius:var(--r);overflow:hidden;margin-bottom:16px}
.hero img{width:100%;height:190px;object-fit:cover;display:block;filter:brightness(.5)}
.hero .cap{position:absolute;left:20px;bottom:16px}
.hero .cap h1{margin:0;text-shadow:0 2px 18px rgba(0,0,0,.8)}


/* ---- dashboard ---- */
.tiles{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));
  margin:0 0 22px}
.tile{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 18px 16px;position:relative;overflow:hidden;
  animation:pop .55s var(--spring) both;animation-delay:calc(var(--i,0)*70ms);
  transition:border-color var(--d) var(--ease),transform var(--d) var(--ease)}
.tile::after{content:"";position:absolute;inset:0 0 auto 0;height:1px;
  background:linear-gradient(90deg,transparent,var(--acc),transparent);opacity:.4}
.tval{font-size:clamp(26px,5.2vw,34px);font-weight:800;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;line-height:1.1;
  transition:color .5s var(--ease)}
.tval.bump{color:var(--acc)}
.tlab{color:var(--dim);font-size:12px;text-transform:uppercase;letter-spacing:.07em;
  margin-top:5px;display:flex;align-items:center;gap:7px}
.tnote{color:var(--dimmer);font-size:12.5px;margin-top:6px;text-transform:none;
  letter-spacing:0}
.pulse{width:7px;height:7px;border-radius:50%;background:var(--teal);flex-shrink:0;
  box-shadow:0 0 0 0 rgba(53,201,166,.6);animation:pulse 2.4s var(--ease) infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(53,201,166,.5)}
  70%{box-shadow:0 0 0 7px rgba(53,201,166,0)}100%{box-shadow:0 0 0 0 rgba(53,201,166,0)}}

.grid2{display:grid;gap:16px;margin:0 0 22px}
/* The chart row is two columns EVERYWHERE now, phones included. Its contents
   are scaled down under 560px so they fit rather than wrap into three lines —
   see the narrow-screen block further down. */
.grid2{grid-template-columns:1.1fr .9fr}

/* per-day bars */
.bars{display:flex;align-items:flex-end;gap:6px;height:132px;margin-top:16px}
.bar{flex:1;display:flex;flex-direction:column;justify-content:flex-end;
  align-items:center;gap:7px;height:100%;min-width:0;position:relative;
  cursor:var(--xh);outline:none}
/* The value rides above the bar on hover, focus or tap — a native title
   attribute takes a second to appear and cannot be styled, which is the
   opposite of what a chart needs. */
.bartip{position:absolute;bottom:calc(100% - 14px);left:50%;
  transform:translate(-50%,6px) scale(.96);transform-origin:bottom center;
  background:var(--card2);border:1px solid var(--line);border-radius:9px;
  padding:7px 11px;font-size:12.5px;white-space:nowrap;pointer-events:none;
  opacity:0;z-index:5;box-shadow:0 10px 28px rgba(0,0,0,.55);
  transition:opacity .18s var(--ease),transform .28s var(--spring)}
.bartip b{font-size:15px;font-variant-numeric:tabular-nums}
.bartip .tipday{display:block;color:var(--dim);font-size:11.5px;margin-top:1px}
.bar:focus-visible .bartip,.bar.tapped .bartip{
  opacity:1;transform:translate(-50%,0) scale(1)}
.bar.tapped .barfill{opacity:1;filter:brightness(1.25)}
/* First and last tooltips would overflow the card, so they hug the edge. */
.bar:first-child .bartip{left:0;transform:translate(0,6px) scale(.96)}
.bar:first-child.tapped .bartip{transform:translate(0,0) scale(1)}
.bar:last-child .bartip{left:auto;right:0;transform:translate(0,6px) scale(.96)}
.bar:last-child.tapped .bartip{transform:translate(0,0) scale(1)}
.barfill{width:100%;border-radius:5px 5px 3px 3px;background:var(--acc);
  height:var(--h);min-height:3px;transform-origin:bottom;
  animation:grow .7s var(--spring) both;animation-delay:calc(var(--i,0)*45ms);
  transition:opacity var(--d-fast) var(--ease)}

.barlab{color:var(--dimmer);font-size:10.5px;font-variant-numeric:tabular-nums}
@keyframes grow{from{transform:scaleY(0);opacity:0}to{transform:scaleY(1);opacity:1}}

/* rank distribution */
.dist{margin-top:16px;display:flex;flex-direction:column;gap:9px}
.drow{display:grid;grid-template-columns:82px 1fr 46px;align-items:center;gap:11px;
  animation:rise .5s var(--ease) both;animation-delay:calc(var(--i,0)*45ms)}
.dname{font-size:11.5px;font-weight:700;letter-spacing:.05em;text-align:right}
.dtrack{height:9px;border-radius:99px;background:var(--card2);overflow:hidden}
.dfill{display:block;height:100%;width:var(--w);border-radius:99px;
  transform-origin:left;animation:widen .85s var(--spring) both;
  animation-delay:calc(var(--i,0)*50ms + .12s)}
@keyframes widen{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.drow-out{opacity:.6;border-bottom:1px solid var(--line);padding-bottom:10px;margin-bottom:4px}
.dnote{font-size:11.5px;color:var(--dimmer);font-style:italic}
.dnum{font-size:13px;color:var(--dim);font-variant-numeric:tabular-nums;text-align:right}
@media (max-width:519px){.drow{grid-template-columns:70px 1fr 40px;gap:9px}}


/* small avatars in rosters */
.who{display:flex;align-items:center;gap:9px;min-width:0}
.mini{width:30px;height:30px;border-radius:9px;flex-shrink:0;object-fit:cover;
  border:1px solid var(--line);background:var(--card2)}
.mini.gen{display:inline-flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;letter-spacing:0}
.who .rankicon{width:22px;height:22px;margin:0;vertical-align:0}


/* live feed */
.feed{margin-top:14px}
/* Consecutive cards need air between them; several pages stack them directly. */
.card + .card{margin-top:14px}
.card + h2,.tabpane + h2{margin-top:26px}
.feed .ev{animation:rise .45s var(--ease) both;animation-delay:calc(var(--i,0)*32ms)}
.feed .ev .when{margin-left:auto;text-align:right}
.ico.played{color:var(--blue)}.ico.discovered{color:var(--purple)}
.ico.clanjoin{color:var(--teal)}.ico.clanmove{color:var(--blue-2)}
.ico.rename{color:var(--gold)}


/* clickable tiles */
a.tile{display:block;position:relative}
.tgo{position:absolute;top:14px;right:15px;color:var(--dimmer);font-size:15px;
  transition:transform .22s var(--spring),color .2s var(--ease)}

/* drawn feed icons */
svg.ico{flex-shrink:0;vertical-align:-3px;color:var(--dim)}
svg.ico.played{color:var(--blue)}svg.ico.rankup{color:var(--lime)}
svg.ico.rankdown{color:var(--orange)}svg.ico.rename{color:var(--gold)}
svg.ico.clanjoin,svg.ico.join{color:var(--teal)}
svg.ico.clanleave,svg.ico.leave{color:var(--orange)}
svg.ico.clanmove{color:var(--blue-2)}svg.ico.discovered{color:var(--purple)}
svg.ico.ban{color:var(--red)}svg.ico.unban{color:var(--teal)}

/* active + match rows */
.g.act .mid .ttl{font-size:15.5px}
.g.act .mini{width:40px;height:40px;border-radius:12px}
.rankicon.big{width:30px;height:30px}
.g.match .meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* pager */
.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin-top:18px;font-size:14px}
.btn-ghost{padding:9px 16px;border-radius:10px;border:1px solid var(--line);
  background:var(--card);color:var(--fg);transition:all .18s var(--ease)}


/* upload progress */
.pbar{height:8px;border-radius:99px;background:var(--card2);overflow:hidden}
.pfill{height:100%;width:0;border-radius:99px;background:var(--acc);
  transition:width .3s var(--ease)}


/* drag and drop */
.drop{border:2px dashed var(--line);border-radius:var(--r);padding:34px 20px;
  text-align:center;transition:border-color .2s var(--ease),background .2s var(--ease),
  transform .2s var(--spring);cursor:var(--xhp)}
.drop.over{border-color:var(--acc);background:var(--acc-dim);transform:scale(1.01)}
.dropinner{display:flex;flex-direction:column;gap:6px;pointer-events:none}
.dropinner b{font-size:17px}
.drop .pick{pointer-events:auto;cursor:var(--xhp);color:var(--acc)}
#dropcount{font-variant-numeric:tabular-nums}


/* system pane */
.sysgrid{display:grid;gap:12px;grid-template-columns:1fr}
@media (min-width:700px){.sysgrid{grid-template-columns:1fr 1fr}}
.card.center{display:flex;flex-direction:column;align-items:center;justify-content:center}
.wheel{position:relative;display:inline-flex;align-items:center;justify-content:center}
.wheel svg{display:block;max-width:100%;height:auto}
/* The arc draws itself on: dashoffset walks from a full circle down to zero. */
.wheel .arc{stroke-dashoffset:var(--circ);animation:sweepin 1.1s var(--ease) .15s forwards}
@keyframes sweepin{to{stroke-dashoffset:0}}
.wheelmid{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;pointer-events:none}
.wheelmid b{font-size:38px;font-weight:800;letter-spacing:-.03em;line-height:1;
  font-variant-numeric:tabular-nums}
.wheelmid b span{font-size:19px;color:var(--dim);margin-left:2px}
.wlab{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim);margin-top:6px}
.wsub{font-size:12px;color:var(--dimmer);margin-top:2px;font-variant-numeric:tabular-nums}

.tierrows{display:flex;flex-direction:column;gap:11px;margin-top:4px}
.tierrow{display:grid;grid-template-columns:96px 74px 1fr 84px;align-items:center;gap:11px;
  animation:rise .5s var(--ease) both;animation-delay:calc(var(--i,0)*60ms)}
.tname{font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.tevery{font-size:12px;font-variant-numeric:tabular-nums}
.ttrack{height:10px;border-radius:99px;background:var(--card2);overflow:hidden}
.tfill{display:block;height:100%;width:var(--w);border-radius:99px;transform-origin:left;
  animation:widen .8s var(--spring) both;animation-delay:calc(var(--i,0)*60ms + .1s)}
.tnum{font-size:13px;text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
@media (max-width:559px){
  .tierrow{grid-template-columns:1fr 1fr;gap:4px 10px}
  .ttrack{grid-column:1/-1;order:3}
  .tnum{text-align:right}
}


/* account page */
.mehead{display:flex;gap:20px;align-items:center;margin-bottom:22px;flex-wrap:wrap}
.mepfp{width:96px;height:96px;border-radius:26px;object-fit:cover;flex-shrink:0;
  border:1px solid var(--line);background:var(--card2)}
.mepfp.gen{display:inline-flex;align-items:center;justify-content:center;
  font-size:38px;font-weight:800;color:var(--dim)}
.meid h1{margin:0 0 8px}
.mepills{display:flex;gap:7px;flex-wrap:wrap}
.merow{display:flex;gap:10px;margin-top:20px;flex-wrap:wrap}


/* verification badges */
.vb{display:inline-flex;align-items:center;gap:6px;vertical-align:middle}
.vb .vmark{flex-shrink:0;display:block;
  filter:drop-shadow(0 1px 4px rgba(0,0,0,.45))}
h1 .vb{margin-left:11px;vertical-align:-3px}
.vb.chip{padding:5px 13px 5px 9px;border-radius:99px;border:1.5px solid;
  font-size:13px;font-weight:700;letter-spacing:.01em;
  background:color-mix(in srgb, currentColor 10%, transparent)}
.who .vb{margin-left:3px}
/* a gentle pulse on first paint, so it reads as a mark rather than a dot */
@keyframes vpop{from{transform:scale(.4);opacity:0}
  70%{transform:scale(1.12)}to{transform:scale(1);opacity:1}}
.vb .vmark{animation:vpop .5s var(--spring) both}



/* the filter drawer */
.filterbox{border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  margin-bottom:14px;overflow:hidden}
.filterbox summary{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:14px 18px;cursor:var(--xhp);list-style:none;
  transition:background .18s var(--ease)}
.filterbox summary::-webkit-details-marker{display:none}
.fsum{font-weight:650;font-size:14.5px;display:flex;gap:6px;flex-wrap:wrap;align-items:baseline}
.fsum .dim{font-weight:400;font-size:13.5px}
.fcount{color:var(--dimmer);font-size:12.5px;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.filterbox summary::after{content:"";width:8px;height:8px;flex-shrink:0;
  border-right:2px solid var(--dim);border-bottom:2px solid var(--dim);
  transform:rotate(45deg) translateY(-2px);transition:transform .25s var(--ease)}
.filterbox[open] summary::after{transform:rotate(-135deg) translateY(-2px)}
#a-users,#a-queue{transition:opacity .18s var(--ease)}
.acctlink{display:block;transition:transform .18s var(--ease)}
.fbody{padding:2px 18px 16px;border-top:1px solid var(--line);
  animation:rise .3s var(--ease) both}
.fbody .filters{margin:12px 0 0}
.clearf{color:var(--red)!important;border-color:transparent!important;
  background:transparent!important;padding-left:0!important}

/* filter chips */
.filters{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-bottom:9px}
.filters .flabel{font-size:11px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--dimmer);margin-right:2px}
.filters a{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;
  border-radius:99px;border:1px solid var(--line);background:var(--card);
  color:var(--dim);font-size:13.5px;transition:all .18s var(--ease);white-space:nowrap}
.filters a.on{background:var(--fg);color:var(--bg);border-color:var(--fg);font-weight:650}
.filters a .n{font-size:12px;opacity:.7;font-variant-numeric:tabular-nums}
.filters.ranks .rankicon{width:18px;height:18px;margin:0}

.acts{display:flex;gap:6px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.acts form{display:inline-flex;gap:4px;align-items:center;margin:0}
.badgeform select{padding:5px 8px;border-radius:7px;border:1px solid var(--line);
  background:var(--card2);color:var(--dim);font-size:12.5px}


/* a bar behind the games count, so a career reads at a glance */
.sbar{display:inline-block;height:7px;width:var(--w);min-width:3px;border-radius:99px;
  background:var(--acc);opacity:.5;margin-right:9px;vertical-align:middle;
  transform-origin:right;animation:widen .7s var(--ease) both}


/* ban notice */
.banbox{display:flex;gap:14px;align-items:center;padding:15px 18px;margin:0 0 16px;
  border-radius:var(--r);border:1px solid var(--red);
  background:linear-gradient(90deg,rgba(239,95,74,.14),rgba(239,95,74,.04))}
.banbox svg{flex-shrink:0}
.bantitle{font-weight:700;font-size:16px;color:var(--red)}
.banwhy{color:var(--dim);font-size:13.5px;margin-top:2px}


/* queue statuses */
.qs{display:inline-block;padding:3px 10px;border-radius:99px;font-size:12px;
  font-weight:650;border:1px solid}
.qs.ok{color:var(--teal);border-color:var(--teal);background:rgba(53,201,166,.1)}
.qs.now{color:var(--gold);border-color:var(--gold);background:rgba(240,180,63,.12);
  animation:qpulse 1.8s var(--ease) infinite}
.qs.soon{color:var(--blue);border-color:var(--blue);background:rgba(78,168,240,.1)}
.qs.wait{color:var(--dim);border-color:var(--line)}
.qs.bad{color:var(--red);border-color:var(--red);background:rgba(239,95,74,.09)}
@keyframes qpulse{0%,100%{opacity:1}50%{opacity:.55}}

.empty{color:var(--dim);padding:34px 18px;text-align:center}
footer{color:var(--dimmer);font-size:12.5px;margin-top:56px;line-height:1.7;
  border-top:1px solid var(--line);padding-top:22px}

/* ---- motion ----------------------------------------------------------
   Everything animates on the compositor only (transform + opacity), so a
   five-year-old iPad stays at 60fps. Rows reveal in a stagger driven by an
   inline --i, which costs nothing at runtime because it is just a delay. */
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes pop{from{opacity:0;transform:scale(.94) translateY(8px)}
  60%{opacity:1}to{opacity:1;transform:none}}
@keyframes sweep{from{stroke-dashoffset:var(--len)}to{stroke-dashoffset:0}}
.rise{animation:rise var(--d-slow) var(--ease) both}
.fade{animation:fade var(--d-slow) var(--ease) both}
.pop{animation:pop var(--d-slow) var(--ease) both}
.stagger>*{animation:rise var(--d-slow) var(--ease) both;
  animation-delay:calc(var(--i,0)*38ms)}
tbody tr{animation:rise .46s var(--ease) both;animation-delay:calc(var(--i,0)*26ms)}
.stat{animation:pop .5s var(--spring) both;animation-delay:calc(var(--i,0)*55ms)}
.tabpane{animation:paneIn .38s var(--ease) both}
/* Ranked results picked up from MMR movement. */
.rsum{display:flex;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.rstat{flex:1 1 120px;background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:12px 14px}
.rstat b{display:block;font-size:22px;font-weight:700;letter-spacing:-.02em}
.rstat b.up{color:var(--good)} .rstat b.dn{color:var(--bad)}
.rstat span{display:block;font-size:12px;color:var(--dim);margin-top:2px}
.reslist{display:flex;flex-direction:column;gap:7px}
.res-row{position:relative;display:grid;align-items:center;gap:12px;
  grid-template-columns:4px 46px 74px 1fr auto auto 12px;
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:11px 13px;color:inherit;text-decoration:none;overflow:hidden;
  animation:rowIn .4s var(--ease) both;animation-delay:calc(var(--i)*22ms);
  transition:border-color .18s var(--ease),transform .18s var(--spring),background .18s}
.rbar{width:4px;height:var(--h);min-height:12px;border-radius:3px;align-self:center}
.res-row.w .rbar{background:var(--good)} .res-row.l .rbar{background:var(--bad)}
.rverd{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}
.res-row.w .rverd{color:var(--good)} .res-row.l .rverd{color:var(--bad)}
.rdelta{font-size:17px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.res-row.w .rdelta{color:var(--good)} .res-row.l .rdelta{color:var(--bad)}
.runit{font-size:10px;color:var(--dim);margin-left:3px;font-weight:500}
.rwho{display:flex;align-items:center;gap:8px;min-width:0}
.rname{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rclan{color:var(--dim);font-size:12px;flex:none}
.rnow{display:flex;align-items:center;gap:6px;color:var(--dim);font-size:13px;
  font-variant-numeric:tabular-nums}
.rnow img{width:19px;height:19px}
.rwhen{color:var(--dim);font-size:12px;white-space:nowrap;display:flex;align-items:center;gap:7px}
.rmulti{border:1px solid var(--line);border-radius:999px;padding:1px 7px;font-size:10px;
  letter-spacing:.03em;text-transform:uppercase}
@keyframes rowIn{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
@media(max-width:719px){
  .res-row{grid-template-columns:4px 1fr auto;grid-template-areas:
    "bar verd when" "bar who now" "bar delta delta";row-gap:5px}
  .rbar{grid-area:bar;height:100%} .rverd{grid-area:verd} .rwhen{grid-area:when}
  .rwho{grid-area:who} .rnow{grid-area:now} .rdelta{grid-area:delta;font-size:15px}
  .res-row .chev{display:none}
}
/* Emblem art is square with rounded corners, like every other avatar here. */
/* An emblem is line art on transparency, so it needs a plate behind it and
   room to breathe — a Discord photo fills its square, this does not. */
.mini.emba{object-fit:contain;padding:2px;background:var(--card2)}
.emb{width:34px;height:34px;border-radius:9px;display:block;object-fit:contain;
  background:var(--card2);border:1px solid var(--line)}
.emb.none{background:repeating-linear-gradient(45deg,var(--card2),var(--card2)5px,
  transparent 5px,transparent 10px)}
td.ethumb{width:46px;padding-right:0}
.pickbtn{padding:6px 11px;font-size:13px;white-space:nowrap}
/* IGN availability. Status carries the meaning, so it gets the colour. */
.ign{font-weight:600;font-variant-ligatures:none}

/* Making the desktop two-column layout survive a 375px screen. Without this
   the card titles wrap onto three lines and the rank list overflows its
   column — measured, not assumed. */
@media(max-width:560px){
  .grid2{gap:10px}
  .champs{gap:10px}
  .grid2 .card.pad,.champs .champ{padding:12px 11px}
  .chead b{font-size:14px!important;line-height:1.25;display:block}
  .chead .dim{font-size:10.5px!important;line-height:1.3}
  .chead{gap:6px}
  .bars{height:96px;gap:2px;margin-top:12px}
  .bar{min-width:0}
  .barlab{font-size:8px}
  .bars .bar:nth-child(even) .barlab{display:none}
  .dist{margin-top:12px;gap:7px}
  .drow{grid-template-columns:52px 1fr 26px;gap:5px;font-size:10px}
  .dname{font-size:8.5px;letter-spacing:0;overflow:hidden;text-overflow:ellipsis}
  .dnum{font-size:9.5px}
  .dnote{font-size:9px}
  /* champion cards, same treatment */
  .chlabel{font-size:9px;letter-spacing:.07em;margin-bottom:8px}
  .chbody{gap:9px}
  .chpic{width:46px;height:46px;border-radius:13px}
  .chname{font-size:11.5px;gap:3px;margin-bottom:5px;line-height:1.25}
  .chstats{gap:2px}
  .chstat{min-width:0}
  .chstat b{font-size:11.5px}
  .chstat span{font-size:7px;letter-spacing:0;white-space:nowrap;overflow:hidden;
    text-overflow:clip}
  /* The clan tag is the first thing to go when there is no room for it. */
  .chtag{display:none}
  .chnote{font-size:9px}
  .phpill{font-size:8px;padding:1px 5px;margin-left:5px}
}

/* ---- featured video ----
   Text left, thumbnail right, sitting in the space the bar chart leaves under
   itself. */
.ytfeat{display:flex;align-items:flex-start;gap:16px;margin-top:18px;padding-top:16px;
  border-top:1px solid var(--line);text-decoration:none;color:inherit}
.ytfmain{flex:1;min-width:0;align-self:center;text-align:center}
.ytflabel{font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--dim);margin-bottom:6px}
.ytftitle{font-size:15px;font-weight:650;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ytfby{display:flex;align-items:center;justify-content:center;gap:7px;margin-top:8px;
  font-size:12.5px;color:var(--dim);min-width:0}
.ytfav{width:22px;height:22px;border-radius:50%;object-fit:cover;flex:none;
  background:var(--card2);border:1px solid var(--line)}
.ytfav.gen{display:flex;align-items:center;justify-content:center;font-size:11px;
  font-weight:700;color:var(--dim)}
.ytfchan{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ytfdot{color:var(--dimmer)}
.ytfviews{flex:none}
.ytfthumb{position:relative;flex:none;width:200px;margin-top:12px;border-radius:13px;
  overflow:hidden;border:1px solid var(--line);line-height:0}
.ytfthumb img{width:100%;display:block;aspect-ratio:16/9;object-fit:cover;
  transition:transform .3s var(--ease)}
.ytfplay{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:46px;height:46px;border-radius:50%;background:rgba(220,0,0,.94);
  display:flex;align-items:center;justify-content:center;
  transition:transform .2s var(--spring)}
@media(max-width:519px){
  .ytfeat{flex-direction:column-reverse;align-items:stretch;gap:12px}
  .ytfthumb{width:100%;margin-top:0}
  .ytfmain{align-self:stretch}
}
/* admin: current video + the form */
.fvnow{display:flex;gap:12px;align-items:flex-start;margin-top:12px}
.fvnow img{width:120px;border-radius:10px;border:1px solid var(--line);
  aspect-ratio:16/9;object-fit:cover;flex:none}
.fvin{width:100%;padding:10px 13px;border-radius:11px;border:1px solid var(--line);
  background:var(--bg);color:var(--fg);font:inherit;font-size:14px;margin-bottom:8px}
.fvin:focus{outline:0;border-color:var(--acc)}
.fvrow{display:grid;gap:8px;grid-template-columns:1fr}
@media(min-width:620px){.fvrow{grid-template-columns:1fr 1fr}}

/* ---- matchmaking champions ----
   Wide and low: picture left, everything else beside it. The tall centred
   version pushed the live feed a long way down for two lines of information. */
.champs{display:grid;gap:16px;margin:0 0 22px}
/* Champion cards likewise. */
.champs{grid-template-columns:1fr 1fr}
.champ{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 16px 14px;position:relative;overflow:hidden;
  animation:rowIn .4s var(--ease) both}
/* A quiet crown of light behind the winner, not a coloured card. */
.champ:not(.empty)::before{content:"";position:absolute;left:-30px;top:-70px;
  width:210px;height:150px;pointer-events:none;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--gold) 18%,transparent),transparent)}
.chlabel{position:relative;font-size:10.5px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:var(--dim);margin-bottom:12px;display:flex;
  align-items:center;justify-content:center}
.chbody{position:relative;display:flex;align-items:center;gap:16px;min-width:0}
.chpicwrap{display:block;line-height:0;flex:none}
.chpic{width:88px;height:88px;border-radius:24px;object-fit:cover;display:block;
  border:1px solid var(--line);background:var(--card2);
  transition:transform .22s var(--spring)}
.chpic.gen{display:flex;align-items:center;justify-content:center;font-size:26px;
  font-weight:700;color:var(--dim)}
.chinfo{min-width:0;flex:1}
.chname{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:16.5px;
  margin-bottom:10px;min-width:0}
.chtag{flex:none}
.chstats{display:flex;gap:10px;align-items:baseline;justify-content:space-between}
.chstat{text-align:left}
.chstat b{display:block;font-size:18px;font-weight:750;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1.15}
.chstat span{display:block;font-size:9.5px;color:var(--dim);letter-spacing:.07em;
  text-transform:uppercase;margin-top:2px}
.champ.ph .chpic{filter:grayscale(.35);opacity:.9}
.champ.ph::before{opacity:.35}
.phpill{margin-left:8px;font-size:9.5px;letter-spacing:.06em;color:var(--dimmer);
  border:1px solid var(--line);border-radius:999px;padding:2px 7px;text-transform:uppercase}
.chnote{position:relative;margin:11px 0 0;font-size:11px;color:var(--dimmer);
  text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.champ.empty .chnone{color:var(--dim);font-size:14px;line-height:1.6;padding:6px 0 8px}
.chnone span{font-size:12.5px;color:var(--dimmer)}
@media(max-width:420px){
  .chpic{width:44px;height:44px;border-radius:13px}
}

/* ---- season history ---- */
.seasons{padding:4px 6px}
.srow{display:grid;grid-template-columns:76px 1fr 68px 74px 78px;gap:12px;align-items:center;
  padding:11px 10px;border-radius:11px;
  animation:rowIn .36s var(--ease) both;animation-delay:calc(var(--i)*26ms);
  transition:background .16s var(--ease)}
.srow.cur{background:var(--acc-dim)}
.snum{font-weight:700;font-size:14px;font-variant-numeric:tabular-nums}
.scur{display:block;font-size:9.5px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--acc);margin-top:1px}
.sbarwrap{min-width:0}
/* Length = how much they played that season; the green share = how it went. */
.sbar2{height:9px;width:var(--w);min-width:10px;border-radius:99px;overflow:hidden;
  background:var(--bad);margin-bottom:5px}
.sbar2 .sw{display:block;height:100%;width:var(--p);background:var(--good);
  border-radius:99px 0 0 99px}
.swl{font-size:12.5px;font-variant-numeric:tabular-nums;display:flex;gap:4px;align-items:baseline}
.sgames{margin-left:6px;font-size:11.5px}
.skd,.swr,.scas{text-align:right;font-variant-numeric:tabular-nums;line-height:1.25}
.skd b,.swr b,.scas b{display:block;font-size:14.5px;font-weight:700}
.slab{display:block;font-size:10px;color:var(--dim);letter-spacing:.04em;
  text-transform:uppercase;margin-top:1px}
@media(max-width:719px){
  .srow{grid-template-columns:60px 1fr auto;row-gap:6px;padding:11px 8px}
  .scas{display:none}
  .swr{min-width:60px}
}
@media(max-width:430px){
  .srow{grid-template-columns:56px 1fr auto}
  .swr{display:none}
}

/* ---- match scoreboard ---- */
.mhero{position:relative;border-radius:18px;overflow:hidden;border:1px solid var(--line);
  margin:0 0 14px;min-height:180px;display:flex;align-items:flex-end;background:var(--card)}
.mhero img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:.55;filter:saturate(.92)}
.mheroin{position:relative;padding:20px 22px;width:100%;
  background:linear-gradient(0deg,rgba(5,6,8,.88),rgba(5,6,8,.2) 62%,transparent)}
.mmap{font-size:13px;letter-spacing:.09em;text-transform:uppercase;color:var(--dim)}
.mbig{display:flex;align-items:baseline;gap:10px;font-size:46px;font-weight:800;
  letter-spacing:-.035em;line-height:1;margin:4px 0 5px}
.mbig .mw{color:var(--good)} .mbig .ml{color:var(--dim)}
.mdash{color:var(--dimmer);font-weight:400}
.msub{color:var(--dim);font-size:13px}

.mteams{display:grid;gap:12px}
@media(min-width:744px){.mteams{grid-template-columns:1fr 1fr}}
.mteam{background:var(--card);border:1px solid var(--line);border-radius:16px;overflow:hidden}
.mteam.won{border-color:color-mix(in srgb,var(--good) 42%,var(--line))}
.mthead{display:flex;align-items:center;justify-content:space-between;
  padding:12px 15px;border-bottom:1px solid var(--line)}
.mtname{font-size:12.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--dim)}
.mteam.won .mtname{color:var(--good)}
.mtscore{font-size:24px;font-weight:800;letter-spacing:-.02em}
.mteam.won .mtscore{color:var(--good)}
.mttot{display:flex;gap:14px;padding:9px 15px;border-bottom:1px solid var(--line);
  font-size:12px;color:var(--dim);background:var(--card2)}
.mttot b{color:var(--fg);font-weight:650}
.mrows{padding:4px 0}
.mrow{position:relative;display:grid;grid-template-columns:1fr auto auto;gap:12px;
  align-items:center;padding:9px 15px;
  animation:rowIn .38s var(--ease) both;animation-delay:calc(var(--i)*35ms)}
/* The bar is behind the row, not a column of its own — it reads as weight
   rather than as another number to parse. */
.mbar{position:absolute;left:0;top:3px;bottom:3px;width:var(--w);pointer-events:none;
  background:linear-gradient(90deg,rgba(255,255,255,.045),transparent 88%);
  border-radius:0 8px 8px 0}
.mteam.won .mbar{background:linear-gradient(90deg,
  color-mix(in srgb,var(--good) 7%,transparent),transparent 88%)}
.mwho{position:relative;display:flex;align-items:center;gap:9px;min-width:0}
.mnames{min-width:0}
.mign{display:flex;align-items:center;gap:6px;font-size:14px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.mshare{display:block;color:var(--dim);font-size:11.5px;margin-top:1px}
.mkda{position:relative;font-variant-numeric:tabular-nums;font-size:14px;white-space:nowrap}
.mkda b{font-weight:700}
.msep{color:var(--dimmer);margin:0 2px}
.mkd{position:relative;font-variant-numeric:tabular-nums;font-size:13px;font-weight:650;
  min-width:38px;text-align:right}
.mrow.mvp .mign{font-weight:700}
@media(max-width:560px){
  .mbig{font-size:38px}
  .mrow{grid-template-columns:1fr auto;row-gap:2px}
  .mkd{grid-column:2;font-size:12px}
}

/* ---- feed ----------------------------------------------------------------
   One surface with hairline dividers rather than a stack of floating cards:
   a timeline should read as a single column, not a pile of boxes. */
.composer{margin-bottom:14px}
.composer textarea{width:100%;min-height:70px;padding:12px 14px;border-radius:12px;
  border:1px solid var(--line);background:var(--bg);color:var(--fg);font:inherit;
  font-size:16px;line-height:1.5;resize:vertical}
.composer textarea::placeholder{color:var(--dimmer)}
.composer textarea:focus{outline:0;border-color:var(--acc);box-shadow:0 0 0 4px var(--acc-dim)}
.crow{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap}
.cfile{cursor:var(--xhp);font-size:13px;padding:8px 14px}
.cnames{font-size:12.5px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crow .btn{margin-left:auto;padding:9px 22px;font-size:14.5px;border-radius:999px}

.feedwrap{background:var(--card);border:1px solid var(--line);border-radius:16px;
  overflow:hidden}
.post{display:grid;grid-template-columns:44px 1fr;gap:12px;padding:14px 16px;
  border-top:1px solid var(--line);animation:rowIn .38s var(--ease) both;
  animation-delay:calc(var(--i)*24ms);transition:background .16s var(--ease)}
.post:first-child{border-top:0}
.pav{display:block;line-height:0}
.pav .mini{width:44px;height:44px;border-radius:13px}
.pmain{min-width:0}
.phead{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}
.pname{display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:14.5px;
  line-height:1.3;min-width:0}
.ptag{flex:none}
.pdot{color:var(--dimmer)}
.pwhen{color:var(--dim);font-size:13px}
.pdelbtn{background:none;border:0;color:var(--dimmer);cursor:var(--xhp);padding:3px;
  border-radius:6px;line-height:0;transition:color .16s var(--ease)}
.pbody{margin:3px 0 0;font-size:15px;line-height:1.5;overflow-wrap:anywhere;
  white-space:normal}

/* Media is CAPPED. An uploaded phone screenshot is 3000px tall and would
   otherwise push every other post off the screen. */
.pmedia-grid{display:grid;gap:3px;margin-top:10px;border-radius:14px;overflow:hidden;
  border:1px solid var(--line);max-width:520px}
.pmedia-grid.n1{grid-template-columns:1fr}
.pmedia-grid.n2{grid-template-columns:1fr 1fr}
.pmedia-grid.n3,.pmedia-grid.n4{grid-template-columns:1fr 1fr}
.pmedia{width:100%;display:block;background:var(--card2);object-fit:cover;
  max-height:290px;aspect-ratio:16/10}
.pmedia-grid.n1 .pmedia{max-height:380px;aspect-ratio:auto}
.pmedia-a{display:block;line-height:0;overflow:hidden}
video.pmedia{object-fit:contain;background:#000}

.ytcard{position:relative;display:block;margin-top:10px;border-radius:14px;overflow:hidden;
  border:1px solid var(--line);line-height:0;text-decoration:none;max-width:520px}
.ytcard img{width:100%;display:block;aspect-ratio:16/9;object-fit:cover}
.ytplay{position:absolute;left:50%;top:44%;transform:translate(-50%,-50%);
  width:52px;height:52px;border-radius:50%;background:rgba(220,0,0,.94);
  display:flex;align-items:center;justify-content:center;
  transition:transform .2s var(--spring)}
.ytmeta{position:absolute;left:0;right:0;bottom:0;padding:9px 12px;line-height:1.35;
  background:linear-gradient(0deg,rgba(0,0,0,.88),transparent);display:block}
.ytmeta b{display:block;font-size:11.5px;color:#fff;letter-spacing:.04em}
.ytmeta span{display:block;font-size:11.5px;color:rgba(255,255,255,.7);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.linkcard{display:block;margin-top:10px;padding:11px 13px;border-radius:13px;
  border:1px solid var(--line);background:var(--card2);text-decoration:none;
  max-width:520px;transition:border-color .18s var(--ease)}
.lhost{display:block;font-size:13.5px;font-weight:600;color:var(--fg)}
.lpath{display:block;font-size:12px;color:var(--dim);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

/* Actions read as quiet icons until you touch them, the way X does it. */
.pactions{display:flex;align-items:center;gap:2px;margin:8px 0 0;margin-left:-8px}
.vbtn{display:inline-flex;align-items:center;gap:5px;padding:6px 9px;border-radius:999px;
  border:0;background:none;color:var(--dim);cursor:var(--xhp);font:inherit;font-size:13px;
  text-decoration:none;line-height:1;
  transition:color .14s var(--ease),background .14s var(--ease)}
.vbtn .vn{min-width:8px;font-variant-numeric:tabular-nums}
.vbtn:disabled{opacity:.45;cursor:var(--xh)}
.vbtn.on{color:var(--good)}
.vbtn.dn.on{color:var(--bad)}
.vbtn.bump{animation:vpop .34s var(--spring)}
@keyframes vpop{0%{transform:scale(1)}40%{transform:scale(1.22)}100%{transform:scale(1)}}
.pdel{flex:none;line-height:0}

.comment{padding:12px 0;border-top:1px solid var(--line)}
.comment:first-child{border-top:0;padding-top:0}
.crow2{display:grid;grid-template-columns:36px 1fr;gap:10px}
.crow2 .pav .mini{width:36px;height:36px;border-radius:11px}
.comment.nested{margin-left:22px;padding-left:14px;border-left:2px solid var(--line);
  border-top:0;padding-top:12px}
.cbody{margin:3px 0 0;font-size:14.5px;line-height:1.5;overflow-wrap:anywhere}
.creply{display:flex;gap:7px;margin:9px 0 0}
.creply input{flex:1;min-width:0;padding:8px 12px;border-radius:999px;
  border:1px solid var(--line);background:var(--bg);color:var(--fg);font:inherit;font-size:13.5px}
.creply input:focus{outline:0;border-color:var(--acc)}
@media(max-width:560px){
  .post{grid-template-columns:38px 1fr;gap:10px;padding:13px 13px}
  .pav .mini{width:38px;height:38px;border-radius:11px}
  .comment.nested{margin-left:8px;padding-left:10px}
  .pmedia-grid,.ytcard,.linkcard{max-width:none}
}

/* ---- sweep ring ----
   The tile keeps the same footprint as the three beside it; the ring replaces
   the big number rather than sitting on top of it. */
.sweeptile{display:flex;align-items:center;gap:13px}
.sweepring{position:relative;flex:none;width:64px;height:64px}
.sweepring svg{transform:rotate(-90deg);display:block}
.ringbg{fill:none;stroke:var(--card2);stroke-width:7}
.ringfg{fill:none;stroke:var(--acc);stroke-width:7;stroke-linecap:round;
  transition:stroke-dasharray .6s var(--ease)}
.ringpct{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:15px;font-weight:750;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.ringpct i{font-style:normal;font-size:9px;color:var(--dim);margin-left:1px}
.sweepmeta{min-width:0}
.sweepmeta .tlab{margin:0}
.sweepmeta .tnote{margin-top:3px}
@media(max-width:560px){
  .sweeptile{gap:9px}
  .sweepring{width:48px;height:48px}
  .sweepring svg{width:48px;height:48px}
  .ringpct{font-size:12px}
}

/* Two matched containers. Both are the SAME height, both carry the same header
   block, and each scrolls its own body — so they start on one line, end on one
   line, and neither can grow past the other. */
.ignrow{display:grid;gap:14px;grid-template-columns:340px 1fr;
  align-items:stretch;margin:0 0 14px}
/* The global ".card + .card" spacing rule pushed the SECOND card in the row
   down by 14px, so the two tops never lined up. Inside a grid the gap does
   that job — and the override has to out-specify that rule, not just follow it. */
.ignrow > *{margin:0;min-width:0}
.ignrow > .card + .card{margin-top:0}
.ignrow .trackcard,.ignrow .ignlist{display:flex;flex-direction:column;height:520px}
/* One header shape for both, so the titles sit on the same baseline and the
   two bodies begin at the same y. */
.ighead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  padding:15px 16px;border-bottom:1px solid var(--line);flex:none;min-height:66px}
.ighead b{font-size:15px;display:block;line-height:1.3}
.ighead .dim{font-size:12px;margin-top:3px;line-height:1.35}
.tscroll,.lscroll{overflow-y:auto;flex:1;min-height:0}
.tscroll table,.lscroll table{width:100%}
/* The last row should not sit against the card edge. */
.tscroll tbody tr:last-child td,.lscroll tbody tr:last-child td{border-bottom:0}
.lscroll thead th{position:sticky;top:0;background:var(--card);z-index:1}
/* Nothing tracked: the list takes the whole row. */
.ignrow > .ignlist:only-child,.ignrow > .empty:only-child{grid-column:1 / -1}
@media(max-width:860px){
  .ignrow{grid-template-columns:1fr}
  .ignrow .trackcard,.ignrow .ignlist{height:auto;max-height:460px}
}

/* Length and category share one control and one look. A separate row of
   coloured chips was a second visual language for the same job. */
.ignbar{display:flex;align-items:flex-start;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.ignbar .filterbox{flex:1;min-width:240px;margin:0}
.ignbar .ignsort{flex:none}
.lopt{cursor:var(--xhp);user-select:none}
.lopt.on{color:var(--fg);border-color:var(--acc);background:var(--acc-dim)}
.lopt.on .vn{color:var(--fg)}
.ignsort{display:inline-flex;gap:3px;padding:3px;background:var(--card);
  border:1px solid var(--line);border-radius:10px;flex:none}
.sortbtn{padding:6px 12px;border-radius:8px;border:0;background:none;color:var(--dim);
  cursor:var(--xhp);font:inherit;font-size:12.5px;white-space:nowrap;
  transition:color .16s var(--ease),background .16s var(--ease)}
.sortbtn.on{background:var(--card2);color:var(--fg)}
/* The length badge rides next to the name, where the eye already is. */
.lenpill{margin-left:8px;font-size:10.5px;font-weight:650;color:var(--dim);
  background:var(--card2);border:1px solid var(--line);border-radius:999px;padding:1px 7px;
  font-variant-numeric:tabular-nums}
tr.isfree .ign{color:var(--good)}
.freealert{margin:10px 0 0;padding:9px 12px;border-radius:10px;font-size:13.5px;
  color:var(--good);background:color-mix(in srgb,var(--good) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--good) 38%,transparent)}

/* Categories live behind one control instead of two dozen loose chips. */
.vgrid{display:grid;gap:6px;grid-template-columns:repeat(auto-fill,minmax(132px,1fr))}
.vopt{display:flex;align-items:center;gap:9px;padding:8px 11px;border-radius:10px;
  border:1px solid var(--line);background:var(--card2);cursor:var(--xhp);font-size:13px;
  color:var(--dim);transition:color .16s var(--ease),border-color .16s var(--ease)}
.vopt input{accent-color:var(--pink);width:15px;height:15px;flex:none;cursor:var(--xhp)}
.vopt:has(input:checked){color:var(--fg);border-color:var(--pink)}
.vname{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vopt .vn{font-variant-numeric:tabular-nums;font-size:11px;color:var(--dim);
  background:var(--card);border-radius:999px;padding:1px 7px;flex:none}
.vactions{display:flex;justify-content:flex-end;margin-top:10px}
.vcell{font-size:12px}
.nst{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  border:1px solid var(--line);border-radius:999px;padding:2px 9px;display:inline-block}
.nst.free{color:var(--good);border-color:color-mix(in srgb,var(--good) 45%,transparent)}
.nst.taken{color:var(--dim)}
.nst.unk{color:var(--orange);border-color:color-mix(in srgb,var(--orange) 45%,transparent)}
/* Progress through the emblem ids. */
.embbar{height:7px;border-radius:99px;background:var(--card2);border:1px solid var(--line);
  overflow:hidden;margin-top:12px}
.embbar span{display:block;height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--purple),var(--blue));
  transition:width .6s var(--ease)}
.miss{color:var(--orange);font-weight:600;font-size:12px;letter-spacing:.03em;
  text-transform:uppercase;margin-right:7px}
/* A picture already spoken for: dimmed, with a tick. Still clickable, because
   two ids can legitimately want the same art and only you can judge that. */
.embcell.used{opacity:.42}
.embcell{position:relative}
.embcell.used::after{content:"";position:absolute;top:5px;right:5px;width:15px;height:15px;
  border-radius:50%;background:var(--good);
  -webkit-mask:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20 6L9 17l-5-5' fill='none' stroke='black' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/13px no-repeat,
    linear-gradient(#000,#000);
  -webkit-mask-composite:xor;mask-composite:exclude;
  mask:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M20 6L9 17l-5-5' fill='none' stroke='black' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/13px no-repeat,
    linear-gradient(#000,#000);
  mask-composite:exclude}
.mecard{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;
  background:var(--card2);border:1px solid var(--line);border-radius:12px;padding:11px 13px;
  animation:rowIn .4s var(--ease) both}
/* The picker itself: a sheet of real emblem art over the page. */
.embpick{position:fixed;inset:0;z-index:80;background:rgba(0,0,0,.62);
  backdrop-filter:blur(6px);display:flex;align-items:flex-end;justify-content:center;
  animation:fadeIn .2s var(--ease) both}
/* display:flex above outranks the browser's own [hidden] rule, so the overlay
   has to opt out of it explicitly or it covers the page from the moment it
   loads — blurring everything behind it. */
.embpick[hidden]{display:none}
@media(min-width:760px){.embpick{align-items:center}}
.embpanel{background:var(--card);border:1px solid var(--line);
  border-radius:20px 20px 0 0;width:min(920px,100%);max-height:88vh;display:flex;
  flex-direction:column;padding:16px;gap:12px;animation:sheetIn .34s var(--spring) both}
@media(min-width:760px){.embpanel{border-radius:20px}}
.embhead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
#embsearch{padding:10px 13px;border-radius:12px;border:1px solid var(--line);
  background:var(--card2);color:var(--fg);font:inherit;font-size:14px}
#embsearch:focus{outline:none;border-color:var(--acc)}
.embgrid{overflow-y:auto;display:grid;gap:9px;padding:2px;
  grid-template-columns:repeat(auto-fill,minmax(84px,1fr))}
.embcell{background:var(--card2);border:1px solid var(--line);border-radius:13px;
  padding:9px 5px 7px;display:flex;flex-direction:column;align-items:center;gap:5px;
  cursor:var(--xhp);color:var(--dim);font:inherit;font-size:10px;line-height:1.25;
  transition:border-color .16s var(--ease),transform .16s var(--spring),background .16s}
.embcell img{width:52px;height:52px;object-fit:contain}
.embcell span{text-align:center;max-width:100%;overflow:hidden;text-overflow:ellipsis;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes sheetIn{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
.card{transition:border-color .2s var(--ease),transform .2s var(--ease)}
.spark path.line{stroke-dasharray:var(--len);animation:sweep 1.15s var(--ease) .15s both}

/* ---- wallet ----
   The balance is the headline and everything else defers to it. An empty wallet
   is the common case on day one, so it is designed as an invitation rather than
   as an error state. */
.walhead{display:flex;gap:38px;flex-wrap:wrap;align-items:flex-end;margin:0 0 20px}
.walbal b{display:block;font-size:clamp(40px,8vw,60px);line-height:1;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;margin-top:6px}
.walunit{color:var(--dim);font-size:13px;margin-top:6px;display:inline-block}
/* The mark leads the figure the way a currency symbol does. On its own under a
   60px number it read as a stray icon rather than a unit. */
.walnum{display:flex;align-items:center;gap:12px}
.walnum .cashmark{width:clamp(34px,6.5vw,50px);height:auto;margin-top:6px}
.walearn b{display:block;font-size:22px;margin-top:6px;color:var(--dim);
  font-variant-numeric:tabular-nums}
.walempty h2{font-size:19px}
.walways{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:2px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.walways2{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:2px;
  background:var(--line);margin-bottom:22px}
.walway{background:var(--card);padding:14px 16px}
.walway b{display:block;font-size:22px;color:var(--teal);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.walway span{display:block;color:var(--dim);font-size:12.5px;margin-top:3px}
/* The balance chip in the nav. */
.cashchip{display:flex;align-items:center;gap:8px;padding:4px 12px;height:38px;
  border-radius:12px;border:1px solid var(--line);background:var(--card);
  font-size:13.5px;font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--fg);white-space:nowrap;
  transition:border-color .2s var(--ease),transform .2s var(--spring)}
.cashchip.zero{color:var(--dim)}
/* The note itself. Drawn rather than an emoji so it takes the surrounding
   colour, stays crisp at 13px, and looks the same on every platform. */
.cashmark{width:17px;height:12px;flex:none;color:var(--cash);
  display:inline-block;vertical-align:-1px}
.cashchip.zero .cashmark{color:var(--dimmer)}
/* ---- performance diary (profile > Form) ----
   The label sits ABOVE the number here, unlike .stat, because the tiles also
   carry a third line underneath and reading label-value-detail top to bottom is
   what makes six of them scannable in a row. */
.dhead{display:flex;align-items:center;justify-content:space-between;
  flex-wrap:wrap;gap:10px;margin-bottom:12px}
.dstrip{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.dlab{font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:var(--dim);
  font-weight:600}
.dstripnote{font-size:11px;margin-left:4px}
.fp{width:15px;height:15px;border-radius:5px;display:inline-block;flex:none;
  animation:pop .45s var(--spring) both;animation-delay:calc(var(--i,0)*40ms)}
.fp.w{background:var(--teal)}
.fp.l{background:var(--red)}

.dtiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:2px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;margin-bottom:14px}
.dtile{background:var(--card);padding:14px 16px}
.dtile b{display:block;font-size:clamp(19px,4vw,25px);line-height:1.15;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;margin-top:5px}
.dtile .dsub{display:block;color:var(--dimmer);font-size:11.5px;margin-top:4px;
  font-variant-numeric:tabular-nums}

/* The correction affordance. A repair most rows never need, so it stays out of
   the way until the row is hovered -- and is always visible on touch, where
   there is no hover to reveal it with. */
.fixbtn{margin-left:7px;vertical-align:middle;background:none;border:0;padding:2px;
  color:var(--dimmer);cursor:var(--xhp);line-height:0;border-radius:6px;opacity:0;
  transition:opacity .15s var(--ease),color .15s var(--ease)}
.fixbtn:focus-visible{opacity:1}
@media (hover:none){.fixbtn{opacity:.65}}

.pindlg{border:1px solid var(--line);border-radius:var(--r);background:var(--card);
  color:var(--fg);padding:0;max-width:420px;width:calc(100% - 32px);box-shadow:0 24px 60px rgba(0,0,0,.6)}
.pindlg::backdrop{background:rgba(0,0,0,.6);backdrop-filter:blur(2px)}
.pinform{padding:20px}
.pinform h3{margin:0 0 4px;font-size:17px;letter-spacing:-.01em}
.pinwhat{margin:0 0 14px;color:var(--dim);font-size:13px}
.pinopts{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}
.pinopt{display:flex;align-items:center;gap:9px;padding:10px 12px;border:1px solid var(--line);
  border-radius:10px;cursor:var(--xhp);font-size:13px;font-variant-numeric:tabular-nums}
.pinopt input{accent-color:var(--acc);margin:0}
.pinopt:has(input:checked){border-color:var(--acc);background:var(--card2)}
.pinact{display:flex;gap:8px;justify-content:flex-end;align-items:center;margin-top:14px}
.pinact .fbtn{padding:8px 16px;font-size:13px}
.pill.warn{border-color:var(--orange);color:var(--orange);margin-left:7px}
/* Submitted. A moment of "yes, that worked" before the page gets on with it.
   It dismisses itself -- nobody should have to close a confirmation. */
/* TWO animations on one element, both touching opacity. The exit one MUST use
   fill-mode forwards, NOT both: with both, its backwards fill applies during
   the 2s delay, and since it only declares an end keyframe the element sits at
   opacity 0 for the whole wait -- the overlay never appeared at all.
   (No backticks in this comment: it lives inside a JS template literal.) */
.burst{position:fixed;inset:0;display:flex;align-items:flex-start;justify-content:center;
  padding-top:9vh;background:rgba(0,0,0,.55);z-index:80;pointer-events:none}
.burst[hidden]{display:none}
.burst.go{animation:fadeIn .18s var(--ease) both, burstOut .4s var(--ease) 2s forwards}
.burst.go .burstcard{animation:sheetIn .34s var(--spring) both}
.burst.go .tickring{animation:drawRing .5s var(--ease) .05s forwards}
.burst.go .ticksign{animation:drawTick .3s var(--ease) .42s forwards}
.burstcard{background:var(--card);border:1px solid var(--line);border-radius:18px;
  padding:26px 34px;text-align:center;box-shadow:0 24px 60px rgba(0,0,0,.55)}
.burstcard b{display:block;font-size:17px;margin-top:10px;letter-spacing:-.01em}
.burstcard span{display:block;font-size:12.5px;color:var(--dim);margin-top:5px;max-width:30ch}
.tickring{stroke:var(--teal);stroke-dasharray:145;stroke-dashoffset:145}
.ticksign{stroke:var(--teal);stroke-dasharray:36;stroke-dashoffset:36}
@keyframes drawRing{to{stroke-dashoffset:0}}
@keyframes drawTick{to{stroke-dashoffset:0}}
@keyframes burstOut{to{opacity:0;visibility:hidden}}

/* Something IS happening, and it is not instant -- say so rather than leaving a
   row that reads exactly like one nobody has touched. */
.readnote{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:var(--r);padding:10px 14px;
  font-size:12.5px;color:var(--dim);margin:0 0 14px}
.readbar{flex:none;width:96px;height:4px;border-radius:99px;background:var(--card2);
  overflow:hidden;display:inline-block}
.readbar i{display:block;width:40%;height:100%;border-radius:99px;background:var(--acc);
  animation:slide 1.25s var(--ease) infinite}
@keyframes slide{0%{transform:translateX(-110%)}100%{transform:translateX(260%)}}
.reading{color:var(--acc);font-weight:600}
.reading i{display:inline-block;width:1.2em;text-align:left;font-style:normal}
.reading i::after{content:"";animation:dots 1.4s steps(4,end) infinite}
@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}
.dr.busy td{opacity:.75}
/* The MMR tile is the one stat with a badge, so it lays out as icon + value
   rather than the plain value-over-label the others use. */
.mmrstat{display:flex;align-items:center;gap:11px}
.mmricon{width:34px;height:34px;object-fit:contain;flex:none}
.mmrval{min-width:0}
.mmrval b{display:block;font-size:clamp(20px,4.4vw,26px);line-height:1.15;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.mmrval span{color:var(--dim);font-size:11px;text-transform:uppercase;
  letter-spacing:.08em;display:block;margin-top:3px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.mmrval i{font-style:normal;font-weight:600}
@media (max-width:520px){.mmricon{width:28px;height:28px}}
/* Owner controls under a match, and the map picker they open. The maps are
   shown as pictures because that is how anybody actually recognises one -- a
   list of ten names is a memory test. */
.mown{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}
.mapdlg{max-width:560px}
#updlg{max-width:560px}
.uplab{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--dim);font-weight:600;margin:14px 0 2px}
#updlg .mapgrid{max-height:34vh}
.mapgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:8px;
  margin:14px 0 4px;max-height:52vh;overflow-y:auto}
.mapopt{position:relative;border:1px solid var(--line);border-radius:10px;overflow:hidden;
  cursor:var(--xhp);display:block;background:var(--card2);transition:border-color .15s var(--ease),
  transform .15s var(--ease)}
.mapopt input{position:absolute;opacity:0;pointer-events:none}
.mapopt img{display:block;width:100%;aspect-ratio:16/10;object-fit:cover;
  filter:saturate(.75) brightness(.72);transition:filter .15s var(--ease)}
.mapopt span{display:block;padding:7px 9px;font-size:12.5px;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mapopt:has(input:checked){border-color:var(--acc)}
.mapopt:has(input:checked) img{filter:saturate(1) brightness(1)}
/* A tick, so the choice is obvious without relying on the border colour alone. */
.mapopt:has(input:checked)::after{content:"";position:absolute;top:7px;right:7px;
  width:18px;height:18px;border-radius:50%;background:var(--acc);
  box-shadow:0 0 0 3px var(--card)}
.mapopt:has(input:checked)::before{content:"";position:absolute;top:12px;right:11px;
  width:9px;height:5px;border-left:2px solid var(--bg);border-bottom:2px solid var(--bg);
  transform:rotate(-45deg);z-index:1}
.pinact .fbtn.bad{background:var(--red);border-color:var(--red);color:#fff}
/* A game of your own with nothing attached: the row is how you add it. */
.dr.addrow{cursor:var(--xhp)}
.upfile{display:block;width:100%;margin:4px 0 2px;font:inherit;font-size:12.5px;
  color:var(--dim)}
.upfile::file-selector-button{font:inherit;font-size:12.5px;background:var(--card2);
  color:var(--fg);border:1px solid var(--line);border-radius:8px;padding:7px 12px;
  margin-right:10px;cursor:var(--xhp)}
.upsay{border:1px solid var(--line);border-radius:var(--r);padding:11px 14px;
  font-size:13px;margin:0 0 14px}
.upsay.ok{border-color:var(--teal);color:var(--teal)}
.upsay.warn{border-color:var(--orange);color:var(--orange)}
/* A screenshot we could not tie to a detected game. It is still a real game the
   player played, so it stays in the list -- just receded, with the empty MMR
   cell doing the explaining. A badge on every one of these shouted about a
   condition the footnote already states once. */
.dr.un td{opacity:.5}
.reltime{display:block;font-size:11px;color:var(--dimmer);line-height:1.35;margin-top:1px}
.dtable td{padding:11px 14px}
.dtable th{padding:10px 14px}
.dres{width:44px;padding-left:16px}
.wl{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:8px;font-size:12px;font-weight:800;letter-spacing:0}
.wl.w{background:color-mix(in srgb,var(--teal) 18%,transparent);color:var(--teal)}
.wl.l{background:color-mix(in srgb,var(--red) 16%,transparent);color:var(--red)}
.dr{position:relative}
.dtable tr.lnkrow{cursor:var(--xhp)}
.dlt2{font-size:11.5px;font-weight:700}
.mmrc{font-variant-numeric:tabular-nums}

/* Three EQUAL cards, each the same shape: header, then a body box of one fixed
   height that centres its contents. Equal columns alone would not line the ring
   up with the two lines, because each fills a different amount of its own box. */
.dgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;
  margin:0 0 14px;align-items:stretch}
.dcell{display:flex;flex-direction:column;padding:13px 15px;min-width:0}
.dh3{margin:0 0 8px;font-size:11px;text-transform:uppercase;letter-spacing:.09em;
  color:var(--dim);font-weight:600}
/* THE GLOBAL CARD SPACING RULE APPLIES INSIDE A GRID TOO.
   .card + .card{margin-top:14px} was pushing the 2nd and 3rd cards down 14px and
   shortening them by the same amount, which is what made the first one look
   bigger. Grid gap already does the spacing here. Specificity: this is (0,3,0)
   against that rule's (0,2,0). The IGN row needed exactly this fix as well. */
.dgrid > .card + .card{margin-top:0}

/* flex:1 sets flex-basis:0%, and in a COLUMN flex container flex-basis beats
   height -- so the earlier fixed height was silently ignored and each body
   still sized to its own content. Pinning the basis is what actually fixes it. */
.dbody{flex:0 0 118px;display:flex;align-items:center;justify-content:center;
  height:118px;min-width:0;overflow:hidden}
.dwr{flex-direction:column;gap:6px}
.wrcap{font-size:12px;font-variant-numeric:tabular-nums;text-align:center}
.wrcap b{font-weight:700}
/* Height comes from the viewBox, never from the flex box: an explicit 100%
   height on a flex child can resolve to zero and silently collapse the chart. */
.dbody .chart{width:100%;min-width:0}
.dbody .chart svg{display:block;width:100%;height:auto;max-height:118px}
.sparkempty{margin:0;font-size:12.5px;text-align:center;max-width:26ch}

/* The compact chart's own header. It doubles as the scrub readout: dragging
   across the line rewrites .cval and .cdate in place, so the number you are
   pointing at is always the big one. */
.mchead{display:flex;align-items:baseline;gap:6px;margin-bottom:4px;min-height:21px}
.mchead .cval{font-size:19px;font-weight:800;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1}
.munit{font-size:10.5px;color:var(--dim);text-transform:uppercase;letter-spacing:.06em}
.mchead .cdate{font-size:11px;margin-left:auto;font-variant-numeric:tabular-nums}
.mcdelta{font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums}
.mchart .line{stroke-dasharray:var(--len);animation:sweep 1.15s var(--ease) .15s both}
.mchart .hit{cursor:var(--xh)}

/* The ring is smaller here than on the system page, so its number has to be. */
.dcell .wheelmid b{font-size:23px}
.dcell .wheelmid b span{font-size:12px}

/* Under about 900px the three cells stop being readable side by side: the two
   trend lines squeeze to a few pixels per game. The ring keeps its own row. */
/* The three stay equal thirds at every width -- singling one out for a full row
   is what made it look bigger than its neighbours. They only stack once a third
   of the screen is genuinely too narrow for a line chart. */
@media (max-width:660px){
  .dgrid{grid-template-columns:1fr}
  .dbody{flex:0 0 150px;height:150px}
  .dbody .chart svg{max-height:150px}
}


/* ---- admin: building a market ----
   A utilitarian form, but the two numbers that decide whether a market is a
   good idea -- what the house can lose and where it starts -- are given real
   weight rather than being buried among the inputs. */
.mkkinds{display:grid;gap:10px;grid-template-columns:1fr;margin:4px 0 20px}
@media(min-width:700px){.mkkinds{grid-template-columns:1fr 1fr}}
.mkkind{position:relative;display:block;padding:14px 16px;border-radius:12px;
  border:1px solid var(--line);background:var(--bg);cursor:var(--xhp);
  transition:border-color .18s var(--ease),background .18s var(--ease)}
.mkkind input{position:absolute;opacity:0;pointer-events:none}
.mkkind b{display:block;font-size:14.5px;margin-bottom:3px}
.mkkind span{display:block;color:var(--dim);font-size:12.5px;line-height:1.5}
.mkkind:has(:checked){border-color:var(--acc);background:var(--acc-dim)}
.mkkind:has(:focus-visible){outline:2px solid var(--acc);outline-offset:2px}
.mkkind em{display:block;margin-top:7px;font-style:normal;font-size:11.5px;
  color:var(--teal);letter-spacing:.03em;text-transform:uppercase}
.mkkind.hand em{color:var(--orange)}

.mkgrid{display:grid;gap:14px;grid-template-columns:1fr}
@media(min-width:700px){.mkgrid{grid-template-columns:1fr 1fr}}
.mkf{display:flex;flex-direction:column;gap:6px;min-width:0}
.mkf.wide{grid-column:1/-1}
.mkf label{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dim);font-weight:700}
.mkin{width:100%;padding:11px 13px;border-radius:11px;border:1px solid var(--line);
  background:var(--bg);color:var(--fg);font:inherit;font-size:14.5px}
.mkin:focus{outline:0;border-color:var(--acc);box-shadow:0 0 0 4px var(--acc-dim)}
.mkin[type=number]{font-variant-numeric:tabular-nums}
.mkhint{font-size:12px;color:var(--dimmer);line-height:1.5}

/* The liquidity choice, priced in what it can actually cost. */
.mkrisk{display:flex;align-items:baseline;gap:8px;padding:12px 14px;border-radius:11px;
  background:var(--card2);border:1px solid var(--line);margin-top:2px}
.mkrisk b{font-size:20px;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.mkrisk .cashmark{width:22px;height:16px;align-self:center;margin-right:-2px}
.mkfact .cashmark{width:19px;height:14px;display:inline-block;vertical-align:-2px;
  margin-right:6px}
.mkrisk span{font-size:12.5px;color:var(--dim);line-height:1.45}

/* ---- the preview ---- */
.mkprev{display:grid;gap:14px;grid-template-columns:1fr;margin-bottom:18px}
@media(min-width:640px){.mkprev{grid-template-columns:repeat(4,1fr)}}
.mkfact{padding:13px 15px;border-radius:12px;background:var(--card2);
  border:1px solid var(--line);min-width:0}
.mkfact .k{display:block;font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dim);font-weight:700;margin-bottom:5px}
.mkfact .val{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums;
  overflow-wrap:anywhere}
.mkrules{white-space:pre-wrap;line-height:1.65;font-size:14px}

/* ---- the market list ---- */
.mkstate{display:inline-block;padding:3px 9px;border-radius:99px;font-size:11px;
  font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  border:1px solid var(--line);color:var(--dim);white-space:nowrap}
.mkstate.open{color:var(--teal);border-color:var(--teal)}
.mkstate.scheduled{color:var(--blue);border-color:var(--blue)}
.mkstate.closed{color:var(--orange);border-color:var(--orange)}
.mkstate.settled{color:var(--gold);border-color:var(--gold)}
.mkstate.void{color:var(--dimmer)}
.mkodds{display:flex;align-items:center;gap:9px;min-width:120px}
.mkoddsbar{flex:1;height:6px;border-radius:99px;background:var(--card2);
  overflow:hidden;min-width:44px}
.mkoddsfill{height:100%;border-radius:99px;background:var(--acc);
  transition:width .4s var(--ease)}
.mkoddsnum{font-variant-numeric:tabular-nums;font-weight:700;font-size:13px;
  min-width:38px;text-align:right}
.mkacts{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.mktitle{display:block;font-weight:600;line-height:1.4}
.mksub{display:block;color:var(--dim);font-size:12px;margin-top:2px}


/* ---- the markets tab ----
   The price is the headline on every surface here: biggest type, and the one
   thing that keeps its colour when everything around it goes grey. */
.mhead{margin-bottom:20px}
.mgrid{display:grid;gap:14px;grid-template-columns:1fr;margin-bottom:26px}
@media(min-width:640px){.mgrid{grid-template-columns:1fr 1fr}}
@media(min-width:1000px){.mgrid{grid-template-columns:repeat(3,1fr)}}

.mcard{display:flex;flex-direction:column;gap:12px;padding:16px 17px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--card);color:var(--fg);text-decoration:none;
  transition:border-color .2s var(--ease),transform .2s var(--ease);min-width:0}
.mcard.done{opacity:.62}
.mctop{display:flex;align-items:center;gap:8px;justify-content:space-between;min-height:22px}
.mcq{font-size:15.5px;line-height:1.42;font-weight:650;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.mcodds{display:flex;align-items:center;gap:12px;margin-top:auto}
.mcnum{display:flex;align-items:baseline;gap:3px;flex:none}
.mcnum b{font-size:30px;font-weight:800;letter-spacing:-.03em;color:var(--cash);
  font-variant-numeric:tabular-nums;line-height:1}
.mcnum span{font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.07em}
.mcbar{flex:1;height:7px;border-radius:99px;background:var(--card2);overflow:hidden;min-width:40px}
.mcbar i{display:block;height:100%;border-radius:99px;background:var(--cash)}
.mcard.done .mcnum b,.mcard.done .mcbar i{background:var(--dim);color:var(--dim)}
.mcfoot{display:flex;align-items:center;gap:10px;justify-content:space-between;
  font-size:12px;color:var(--dim);flex-wrap:wrap}
.mcvol{display:inline-flex;align-items:center;gap:5px}
.mcvol .cashmark{width:15px;height:11px}
.mcleft{white-space:nowrap}

.msubj{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--dim);
  min-width:0}
.msubj span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msubj .mini{width:22px;height:22px;border-radius:50%;flex:none}
.msubjicon{width:15px;height:15px;flex:none}

.mempty{flex-direction:column;gap:6px;padding:38px 20px;text-align:center}
.mempty b{font-size:16px}
.mempty span{color:var(--dim);font-size:13.5px}
.mjoin{margin-top:8px}
.mjoin b{font-size:15.5px}

/* What the viewer has riding on it, if anything. */
.mineband{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:13px 17px;
  border-radius:var(--r);border:1px solid var(--line);background:var(--card);
  text-decoration:none;color:var(--fg);margin-bottom:16px;font-size:13.5px;
  transition:border-color .2s var(--ease)}
.mineband b{font-size:17px;font-variant-numeric:tabular-nums}
.minesep{color:var(--dimmer)}
.minew{color:var(--dim);display:inline-flex;align-items:center;gap:5px}
.minew .cashmark{width:15px;height:11px}
.minepnl{margin-left:auto;font-weight:700;font-variant-numeric:tabular-nums}
.minepnl.good{color:var(--good)}.minepnl.bad{color:var(--bad)}

/* ---- one market ---- */
.backlnk{display:inline-block;color:var(--dim);font-size:13px;text-decoration:none;
  margin-bottom:10px}
.mtitle{font-size:clamp(24px,3.6vw,34px);line-height:1.22;text-wrap:balance;margin-bottom:10px}
.mmeta{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:20px;font-size:13px}
.mdot{color:var(--dimmer)}
.mnotice{border-color:var(--cash);margin-bottom:14px}

.mlayout{display:grid;gap:16px;grid-template-columns:1fr;align-items:start}
.mmain,.mside,.mextra{display:flex;flex-direction:column;gap:16px;min-width:0}
/* Wide: chart and outcomes on the left, the trade panel beside them, rules
   underneath. Narrow: the panel follows the outcomes directly, because burying
   the only control below the rules and the trade history hides it. */
@media(min-width:900px){
  .mlayout{grid-template-columns:minmax(0,1.55fr) minmax(300px,1fr)}
  .mmain{grid-column:1;grid-row:1}
  .mside{grid-column:2;grid-row:1/span 2}
  .mextra{grid-column:1;grid-row:2}
}

/* The price, both sides at once -- they are one book read two ways. */



/* ---- the trade panel ---- */
.mtsides{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
.mtside{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:12px 10px;border-radius:12px;border:1px solid var(--line);background:var(--bg);
  cursor:var(--xhp);transition:border-color .18s var(--ease),background .18s var(--ease)}
.mtside input{position:absolute;opacity:0;pointer-events:none}
.mtside span{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--dim);
  font-weight:700}
.mtside b{font-size:21px;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.mtside.yes:has(:checked){border-color:var(--cash);background:rgba(67,201,122,.12)}
.mtside.yes:has(:checked) b{color:var(--cash)}
.mtside.no:has(:checked){border-color:var(--blue);background:var(--acc-dim)}
.mtside.no:has(:checked) b{color:var(--blue)}
.mtside:has(:focus-visible){outline:2px solid var(--acc);outline-offset:2px}

.mtamt .dlab{display:block;margin-bottom:7px}
.mtrow{display:flex;flex-direction:column;gap:9px}
.mtinput{display:flex;align-items:center;gap:8px;padding:11px 13px;border-radius:11px;
  border:1px solid var(--line);background:var(--bg)}
.mtinput:focus-within{border-color:var(--acc);box-shadow:0 0 0 4px var(--acc-dim)}
.mtinput .cashmark{width:20px;height:14px;flex:none}
.mtinput input{flex:1;min-width:0;border:0;background:transparent;color:var(--fg);font:inherit;
  font-size:19px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.mtinput input:focus{outline:0}
.mtchips{display:flex;gap:7px;flex-wrap:wrap}
.mstake{flex:1;min-width:56px;padding:8px 6px;border-radius:9px;border:1px solid var(--line);
  background:var(--bg);color:var(--dim);font:inherit;font-size:12.5px;font-weight:600;
  cursor:var(--xhp);font-variant-numeric:tabular-nums;transition:all .15s var(--ease)}
.mstake:disabled{opacity:.35;cursor:not-allowed}

.mtquote{margin:15px 0;padding:13px 15px;border-radius:12px;background:var(--card2);
  border:1px solid var(--line);min-height:66px;display:flex;flex-direction:column;
  justify-content:center;gap:5px}
.mtq1{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.mtq1 b{font-size:23px;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.mtq1 span{font-size:12.5px;color:var(--dim)}
.mtq2{font-size:12.5px;color:var(--dim);line-height:1.5}
.mtq2 b{color:var(--cash);font-variant-numeric:tabular-nums}
.mtquote.bad{border-color:var(--red)}
.mtquote.bad .mtq1 b{color:var(--red);font-size:15px;font-weight:600}
.mtgo{width:100%}
.mclosed b{font-size:15.5px}

/* ---- your position ---- */

.mposcell{display:flex;flex-direction:column;gap:2px;padding:12px 13px;border-radius:11px;
  background:var(--card2);border:1px solid var(--line);min-width:0}
.mposcell b{font-size:19px;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.mposcell b.good{color:var(--good)}.mposcell b.bad{color:var(--bad)}
.mposcell .dim{font-size:11.5px;line-height:1.45}
.msell{display:flex;gap:9px;flex-wrap:wrap;margin-top:14px}
.msell .btn-ghost{flex:1;min-width:190px}
.mtape table{width:100%}
.mtape .chead{padding-bottom:0}
.mrules .mkrules{margin-top:10px;color:var(--dim);font-size:13.5px}

/* ---- admin: the player search ---- */
.mkwho{position:relative}
.mkfound{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:40;max-height:330px;
  overflow-y:auto;border-radius:12px;border:1px solid var(--line);background:var(--card);
  box-shadow:0 18px 44px rgba(0,0,0,.55);padding:5px}
.whohead{padding:9px 11px 6px;font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dimmer);font-weight:700}
.whorow{display:flex;align-items:center;gap:10px;width:100%;padding:9px 11px;border:0;
  border-radius:9px;background:transparent;color:var(--fg);font:inherit;text-align:left;
  cursor:var(--xhp)}
.whorow:focus-visible{background:var(--card2);outline:0}
.whorow .mini{width:30px;height:30px;border-radius:50%;flex:none}
.whomain{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.whomain b{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.whobadge{font-size:11px;line-height:1.3}
.whobadge.fast{color:var(--cash)}
.whobadge.slow{color:var(--orange)}
.whommr{display:inline-flex;align-items:center;gap:5px;font-size:13px;color:var(--dim);
  font-variant-numeric:tabular-nums;flex:none}
.whoicon{width:17px;height:17px}
.whonone{padding:16px 13px;color:var(--dim);font-size:13.5px;text-align:center}
.mkpicked{margin-top:9px;padding:11px 13px;border-radius:11px;border:1px solid var(--line);
  background:var(--card2);font-size:14px}
.mkpicked.fast{border-color:color-mix(in srgb,var(--cash) 45%,var(--line))}
.mkpicked.slow{border-color:color-mix(in srgb,var(--orange) 45%,var(--line))}
.mkpicked span{color:var(--dim);font-variant-numeric:tabular-nums}
.mkpicked em{display:block;margin-top:4px;font-style:normal;font-size:12px;line-height:1.5;
  color:var(--dim)}
.mkpicked.fast em{color:var(--cash)}
.mkpicked.slow em{color:var(--orange)}


/* ---- market card: outcome rows ----
   Laid out like an exchange lays out a game. The bar under each name is the
   probability drawn rather than written, so a grid of these can be read at a
   glance without reading a single digit. */
.mchead{display:flex;align-items:center;gap:10px;justify-content:space-between;
  min-height:22px;margin-bottom:2px}
.mckind{font-size:10.5px;text-transform:uppercase;letter-spacing:.09em;font-weight:800;
  color:var(--dim);white-space:nowrap}
.ostat{display:inline-flex;align-items:center;gap:6px;font-size:10.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.07em;color:var(--dim)}
.odot{width:6px;height:6px;border-radius:50%;flex:none;background:var(--dim)}
.odot.live{background:var(--cash);box-shadow:0 0 0 3px rgba(67,201,122,.16)}
.odot.soon{background:var(--blue)}
.odot.done{background:var(--dimmer)}
.ostat.live{color:var(--cash)}
.ostat.soon{color:var(--blue)}

.orows{display:flex;flex-direction:column;gap:9px;margin-top:auto;padding-top:4px}
.orow{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px}
.oswatch{width:9px;height:9px;border-radius:3px;flex:none}
.oswatch.yes{background:var(--cash)}
.oswatch.no{background:var(--chart-no)}
.oname{display:flex;flex-direction:column;gap:5px;min-width:0}
.oname b{font-size:13.5px;font-weight:650;line-height:1}
.obar{height:3px;border-radius:99px;background:var(--card2);overflow:hidden}
.obar i{display:block;height:100%;border-radius:99px}
.obar i.yes{background:var(--cash)}
.obar i.no{background:var(--chart-no)}
.opill{display:inline-flex;align-items:baseline;justify-content:center;gap:1px;
  min-width:62px;padding:6px 10px;border-radius:9px;border:1px solid var(--line);
  font-size:15px;font-weight:800;font-variant-numeric:tabular-nums;letter-spacing:-.01em;
  color:var(--dim);background:var(--bg)}
.opill i{font-style:normal;font-size:10.5px;font-weight:700}
.opill.yes.lead{color:var(--cash);border-color:color-mix(in srgb,var(--cash) 55%,transparent)}
.opill.no.lead{color:var(--chart-no);border-color:color-mix(in srgb,var(--chart-no) 55%,transparent)}
.mcard.done .opill{color:var(--dimmer);border-color:var(--line)}
.mcard.done .obar i,.mcard.done .oswatch{background:var(--dimmer)}
.mcfoot{border-top:1px solid var(--line);padding-top:11px;margin-top:2px}


/* ---- one market ---- */
.mtophead{margin-bottom:18px}
.mtophead .mckind{display:block;margin-bottom:7px}
.mtophead .ostat{margin-top:9px}
.mtitle{font-size:clamp(23px,3.4vw,33px);line-height:1.2;text-wrap:balance;margin:0}

/* The chart. Two lines that always sum to 100, mirrored about the middle. */
.mkchart{position:relative;margin:2px 0 4px}
.mkchart svg{display:block;width:100%;height:auto;touch-action:pan-y}

.endlab.yes{color:var(--cash)}
.endlab.no{color:var(--chart-no)}
.chit{cursor:var(--xh)}

.mkcyes{color:var(--cash);font-weight:700}
.mkcno{color:var(--chart-no);font-weight:700}
.mkcfoot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;border-top:1px solid var(--line);padding-top:12px;margin-top:8px}
.mkframes{display:flex;gap:3px}
.mkframe{padding:5px 11px;border-radius:8px;border:0;background:transparent;color:var(--dim);
  font:inherit;font-size:11.5px;font-weight:700;letter-spacing:.05em;cursor:var(--xhp)}
.mkframe.on{background:var(--card2);color:var(--fg)}

/* The outcome table: the whole decision in a row. */
.mout table{width:100%}
.mout th{font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--dimmer);
  font-weight:700;padding:13px 16px 9px;text-align:left}
.mout td{padding:13px 16px;border-top:1px solid var(--line);vertical-align:middle}
.ocell{display:flex;align-items:center;gap:10px}
.ocell b{font-size:15px}
.ochance{white-space:nowrap}
.ochance b{font-size:21px;font-weight:800;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.odelta{margin-left:7px;font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums}
.odelta.up{color:var(--cash)}
.odelta.down{color:var(--red)}
.oacts{text-align:right}
.obtn{padding:9px 15px;border-radius:9px;border:1px solid var(--line);background:var(--bg);
  color:var(--fg);font:inherit;font-size:13px;font-weight:650;cursor:var(--xhp);white-space:nowrap;
  transition:border-color .15s var(--ease),background .15s var(--ease)}
.obtn i{font-style:normal;color:var(--dim);font-variant-numeric:tabular-nums;margin-left:3px}

/* ---- the trade panel ---- */
.mpanel{overflow:hidden;position:sticky;top:14px}
.mptabs{display:flex;border-bottom:1px solid var(--line)}
.mptab{flex:1;padding:14px 10px;border:0;background:transparent;color:var(--dim);font:inherit;
  font-size:13.5px;font-weight:700;cursor:var(--xhp);position:relative}
.mptab.on{color:var(--fg)}
.mptab.on::after{content:"";position:absolute;left:16px;right:16px;bottom:-1px;height:2px;
  border-radius:2px;background:var(--cash)}
.mptab:disabled{opacity:.4;cursor:not-allowed}
.mpbody{padding:16px}
.mpsubj{margin-bottom:12px}
.mpsides{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:14px}
.mpside{display:flex;align-items:center;justify-content:center;gap:6px;text-align:center;
  padding:11px 10px;border-radius:10px;border:1px solid var(--line);background:var(--bg);
  color:var(--dim);font:inherit;font-size:13.5px;font-weight:700;cursor:var(--xhp);
  transition:all .15s var(--ease)}
.mpside i{font-style:normal;font-variant-numeric:tabular-nums;margin-left:0}
.mpside.yes.on{border-color:var(--cash);background:rgba(67,201,122,.14);color:var(--cash)}
.mpside.no.on{border-color:var(--chart-no);background:rgba(154,164,178,.14);color:var(--fg)}
.mpamt{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
.mpamt>span:first-child{font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dim);font-weight:700}
.mpin{display:flex;align-items:center;gap:8px;padding:11px 13px;border-radius:11px;
  border:1px solid var(--line);background:var(--bg)}
.mpin:focus-within{border-color:var(--acc);box-shadow:0 0 0 4px var(--acc-dim)}
.mpin input{flex:1;min-width:0;border:0;background:transparent;color:var(--fg);font:inherit;
  font-size:19px;font-weight:700;font-variant-numeric:tabular-nums}
.mpin input:focus{outline:0}
.mpsum{margin:14px 0;padding:12px 14px;border-radius:11px;background:var(--card2);
  border:1px solid var(--line);display:flex;flex-direction:column;gap:8px}
.mprow{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:13px}
.mprow span{color:var(--dim)}
.mprow b{font-variant-numeric:tabular-nums;font-weight:700}
.mprow.big{padding-top:8px;border-top:1px solid var(--line)}
.mprow.big b{font-size:19px;color:var(--cash);letter-spacing:-.02em}
.mpsum.bad{border-color:var(--red)}
.mpsum.bad .mprow b{color:var(--red)}
.mtgo{width:100%}
.mtgo.sell{background:var(--chart-no);color:#0a0d12}
.mtgo:disabled{opacity:.45;cursor:not-allowed}
.mclosed b{font-size:15.5px}

/* Rules fold away once a market is decided -- at that point they are history. */
.mrules summary{display:flex;align-items:baseline;gap:10px;cursor:var(--xhp);list-style:none}
.mrules summary::-webkit-details-marker{display:none}
.mrules summary b{font-size:16px}
.mrules summary span{font-size:12.5px}
.mrules summary::after{content:"+";margin-left:auto;color:var(--dim);font-size:17px}
.mrules[open] summary::after{content:"−"}
.mrules .mkrules{margin-top:12px;color:var(--dim);font-size:13.5px;white-space:pre-wrap;
  line-height:1.65}
.mtape table{width:100%}
.mtape .chead{padding-bottom:0}
/* The tape names the trader, so the row is a person first and a number second:
   the name column takes the slack and the rest sit at their natural width. */
.mtape td{vertical-align:middle}
.mtape .lead{width:auto}
.tpwho{display:inline-flex;align-items:center;gap:7px;min-width:0}
.tpwho .mini{border-radius:50%;flex:none}
.tpwho .lnk{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tpact{white-space:nowrap;font-size:13px}
.tpact .dim{font-weight:400}
@media(max-width:520px){
  .tpact .dim{display:none}
  .mtape .lead{max-width:120px}
}

@media(max-width:899px){
  .mpanel{position:static}
  .mlayout{grid-template-columns:1fr}
}


/* ---- admin: building a market, in steps ----
   The form is long, so it is broken into numbered stages and the preview sits
   beside it. Seeing the card take shape is what makes the form legible. */
.mkbuild{display:grid;gap:16px;grid-template-columns:1fr;align-items:start;margin-bottom:26px}
@media(min-width:1000px){.mkbuild{grid-template-columns:minmax(0,1.6fr) minmax(280px,1fr)}}
.mkformcard{min-width:0}
.mkstep{padding:18px 0;border-top:1px solid var(--line)}
.mkstep:first-of-type{border-top:0;padding-top:14px}
.mkstephead{display:flex;align-items:flex-start;gap:11px;margin-bottom:14px}
.mkstepn{width:23px;height:23px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--card2);border:1px solid var(--line);color:var(--dim);font-size:12px;
  font-weight:800;font-variant-numeric:tabular-nums}
.mkstephead b{display:block;font-size:15px;line-height:1.3}
.mkstephead span{display:block;color:var(--dim);font-size:12.5px;margin-top:2px}
.mkquick{margin-bottom:4px}
.mkpresets{display:flex;gap:8px;flex-wrap:wrap;margin-top:7px}
.mkpreset{padding:8px 13px;border-radius:99px;border:1px solid var(--line);background:var(--bg);
  color:var(--dim);font:inherit;font-size:12.5px;cursor:var(--xhp);
  transition:all .15s var(--ease)}

/* The preview column. Sticky, because it is the thing being checked against. */
.mkpreview{position:sticky;top:14px;display:flex;flex-direction:column;gap:8px;min-width:0}
.mkcardbox{min-width:0}
.mkcardbox .mcard{cursor:var(--xh)}
.mkcardwait{padding:34px 18px;border-radius:var(--r);border:1px dashed var(--line);
  color:var(--dim);font-size:13px;text-align:center;line-height:1.55}
.mkcardwait.bad{border-style:solid;border-color:color-mix(in srgb,var(--orange) 50%,var(--line));
  color:var(--orange);text-align:left}
@media(max-width:999px){.mkpreview{position:static}}

/* Resolving: three named outcomes, not three bare verbs on a dense row. */
.mkoutpick{display:flex;flex-direction:column;gap:9px;margin:16px 0 4px}
.mkout{display:flex;flex-direction:column;gap:2px;padding:13px 15px;border-radius:11px;
  border:1px solid var(--line);background:var(--bg);color:var(--fg);font:inherit;
  text-align:left;cursor:var(--xhp);transition:all .15s var(--ease)}
.mkout b{font-size:14.5px}
.mkout span{font-size:12.5px;color:var(--dim)}
.mkacts .mini-btn{white-space:nowrap}


/* ---- a player's bio, under their name ---- */
.pbio{margin:8px 0 0;font-size:14px;line-height:1.5;color:var(--fg);
  max-width:60ch;overflow-wrap:anywhere}
.biobox{width:100%;resize:vertical;min-height:52px;padding:9px 11px;border-radius:10px;
  background:var(--card2);border:1px solid var(--line);color:var(--fg);
  font:inherit;font-size:14px;line-height:1.45}
.biobox:focus{outline:none;border-color:var(--acc)}

/* ---- the destination icons ----
   Markets, Shop, Map and Aim are icons, not boxed pills. The boxes took more
   room than the words inside them and the bar had nothing left for another
   destination. Each keeps ONE colour so it can be found at a glance without
   its word, and each carries aria-label and title: an icon with no name is a
   link a screen reader cannot announce and a new member has to guess at. */
.navicon{display:inline-grid;place-items:center;flex:none;
  width:36px;height:36px;border-radius:10px;
  color:var(--ni,var(--dim));
  transition:background .15s var(--ease),box-shadow .15s var(--ease)}
.navicon svg{width:20px;height:20px;display:block}
.navicon.ni-markets{--ni:var(--cash)}
.navicon.ni-shop{--ni:var(--blue)}
.navicon.ni-map{--ni:var(--gold)}
.navicon.ni-aim{--ni:var(--pink)}
/* Where you are: a tinted well, not a filled pill, so the icon keeps the
   colour that identifies it. */
.navicon.on{background:color-mix(in srgb,var(--ni) 20%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ni) 45%,transparent)}
.navicon:focus-visible{outline:2px solid var(--ni);outline-offset:2px}
/* Admin, as a gear beside the bell it now matches. */
/* The brand IS the home button now that Search has gone. */
.brand{transition:opacity .15s var(--ease)}
.brand:hover{opacity:.82}
.adminbtn{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:10px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);flex:none;text-decoration:none;
  transition:color .15s var(--ease),border-color .15s var(--ease)}
.adminbtn:hover{color:var(--fg);border-color:color-mix(in srgb,var(--acc) 50%,var(--line))}

/* The nav right-hand group: cash, bell, account. */
.navright{display:flex;align-items:center;gap:9px}
.navright .cashchip{order:0}


/* ---- market page polish ----
   Everything on this page lines up on one of two edges: labels and values sit
   on a shared baseline grid, and every number is tabular so columns of digits
   do not shimmy as prices tick. */
.mkchart svg{overflow:visible}
.mkchart .cline{stroke-linecap:round;stroke-dasharray:var(--clen);
  stroke-dashoffset:var(--clen);animation:cdraw 1.1s var(--ease) .1s forwards}
.mkchart .cline.no{animation-delay:.2s;opacity:.62}
@keyframes cdraw{to{stroke-dashoffset:0}}
.endlabs{animation:fadein .5s var(--ease) 1s both}
@keyframes fadein{from{opacity:0}to{opacity:1}}

/* The scrub readout keeps a fixed height so the chart never jumps when it
   appears, and its two halves anchor to opposite edges. */
.mkcread{display:flex;align-items:center;justify-content:space-between;gap:12px;
  height:20px;margin-top:4px;font-size:11.5px;color:var(--dim);
  font-variant-numeric:tabular-nums}
.mkcvals{display:flex;gap:14px}
.mkcyes{color:var(--cash);font-weight:700}
.mkcno{color:var(--chart-no);font-weight:700}

/* The countdown. It is the deadline people are racing, so it gets weight. */
.cdown{font-variant-numeric:tabular-nums;letter-spacing:0;font-weight:800}
.cdown.urgent{color:var(--red)}
.ostat.live .cdown{color:var(--cash)}
.ostat.live .cdown.urgent{color:var(--red);animation:blink 1.1s steps(2,end) infinite}
@keyframes blink{50%{opacity:.45}}

/* Your position: every cell equal, side by side, wrapping only when a cell
   would be too narrow to read rather than at a fixed count. */
.mposgrid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));
  margin-top:12px}
.mposcell{display:flex;flex-direction:column;gap:3px;padding:14px;border-radius:12px;
  background:var(--card2);border:1px solid var(--line);min-width:0;
  animation:poprise .45s var(--ease) both}
.mposcell:nth-child(2){animation-delay:.06s}
.mposcell:nth-child(3){animation-delay:.12s}
.mposcell:nth-child(4){animation-delay:.18s}
@keyframes poprise{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
.mposcell .dlab{font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dim);font-weight:700}
.mposcell b{font-size:21px;font-variant-numeric:tabular-nums;letter-spacing:-.025em;
  line-height:1.15}
.mposcell .dim{font-size:11.5px;line-height:1.4}

/* The outcome table: the chance column is the anchor, so it is fixed-width and
   right-aligned against the buttons. */
.mout td,.mout th{vertical-align:middle}
.mout .ochance{text-align:right;width:34%}
.mout .oacts{width:1%;white-space:nowrap}
.mout tbody tr{transition:background .18s var(--ease)}
.obtn{transition:border-color .15s var(--ease),background .15s var(--ease),
  transform .15s var(--spring)}
.obtn:active{transform:translateY(0)}

/* Cards arrive in order rather than all at once. */
.mmain>*,.mside>*,.mextra>*{animation:cardin .5s var(--ease) both}
.mmain>*:nth-child(2){animation-delay:.07s}
.mmain>*:nth-child(3){animation-delay:.14s}
.mside>*{animation-delay:.1s}
.mextra>*{animation-delay:.16s}
@keyframes cardin{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}

/* The trade panel's summary rows share a baseline and a right edge. */
.mprow{align-items:baseline}
.mprow span{font-size:12.5px}
.mprow b{font-size:14px}
.mprow.big b{font-size:20px}
.mpsum{transition:border-color .2s var(--ease)}
.mpside{transition:border-color .16s var(--ease),background .16s var(--ease),
  transform .16s var(--spring)}
.mpside:active{transform:scale(.98)}
.mtgo{transition:transform .16s var(--spring),filter .16s var(--ease)}
.mtgo:active:not(:disabled){transform:translateY(0)}

/* The header block: eyebrow, title and status on one left edge. */
.mtophead .mckind{letter-spacing:.11em}
.mtophead .ostat{font-size:11px}
.mmeta{align-items:center}


/* Markets whose trading has stopped and which nobody has judged yet. */
.mkwait{margin-bottom:16px;border-color:color-mix(in srgb,var(--orange) 45%,var(--line))}
.mkwaitlist{display:flex;flex-direction:column;gap:9px;margin-top:12px}
.mkwaitrow{display:flex;align-items:center;gap:12px;justify-content:space-between;
  padding:12px 14px;border-radius:11px;background:var(--card2);border:1px solid var(--line)}
.mkwaitmain{display:flex;flex-direction:column;gap:2px;min-width:0}
.mkwaitmain b{font-size:14px;line-height:1.35}
.mkwaitmain .dim{font-size:12px}
.mkwaitrow .btn-ghost{flex:none}


/* Source picker rows: question first, their price as context on the right. */
.kwrow{align-items:flex-start}
.kwmeta{font-size:11px;color:var(--dimmer);line-height:1.4}
.kwprice{display:flex;flex-direction:column;align-items:flex-end;gap:1px;flex:none;
  font-variant-numeric:tabular-nums;font-size:14px;font-weight:800;color:var(--dim)}
.kwprice i{font-style:normal;font-size:9.5px;font-weight:600;text-transform:uppercase;
  letter-spacing:.06em;color:var(--dimmer)}


/* A step with nothing to decide, because the source decides it. */
.mkauto{display:flex;flex-direction:column;gap:5px;padding:15px 17px;border-radius:12px;
  background:var(--card2);border:1px solid color-mix(in srgb,var(--cash) 40%,var(--line))}
.mkauto b{font-size:15px;color:var(--cash)}
.mkauto span{font-size:12.5px;color:var(--dim);line-height:1.55}


/* "Open every outcome" — the choice that turns a yes/no into a pick-a-side. */
.mkall{display:flex;gap:11px;align-items:flex-start;margin-top:12px;padding:13px 15px;
  border-radius:12px;border:1px solid color-mix(in srgb,var(--cash) 38%,var(--line));
  background:var(--card2);cursor:var(--xhp)}
.mkall input{margin-top:2px;flex:none;width:16px;height:16px;accent-color:var(--cash)}
.mkall b{display:block;font-size:14px}
.mkall em{display:block;font-style:normal;font-size:12.5px;color:var(--dim);line-height:1.55;
  margin-top:3px}


/* Outcome chips inside a picker row: what you would be opening. */
.kwlegs{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
.kwleg{display:inline-flex;align-items:baseline;gap:5px;padding:3px 8px;border-radius:99px;
  border:1px solid var(--line);background:var(--bg);font-size:11.5px;color:var(--dim)}
.kwleg b{font-weight:600;color:var(--fg)}
.kwleg i{font-style:normal;font-variant-numeric:tabular-nums;color:var(--cash);font-weight:700}
.kwleg.more{color:var(--dimmer)}
.kwrow{align-items:flex-start;gap:12px}


/* A question with several outcomes: one card, one row per outcome. */
.gcard .grows{display:flex;flex-direction:column;gap:7px;margin-top:auto;padding-top:4px}
.grow{display:grid;grid-template-columns:minmax(0,1fr) 72px auto;align-items:center;gap:10px;
  padding:5px 7px;margin:0 -7px;border-radius:9px;text-decoration:none;color:var(--fg);
  transition:background .15s var(--ease)}
.gname{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;min-width:0}
.gbar{height:4px;border-radius:99px;background:var(--card2);overflow:hidden}
.gbar i{display:block;height:100%;border-radius:99px;background:var(--chart-no)}
.grow:first-child .gbar i{background:var(--cash)}
.gpill{display:inline-flex;align-items:baseline;justify-content:center;gap:1px;min-width:54px;
  padding:5px 9px;border-radius:9px;border:1px solid var(--line);background:var(--bg);
  font-size:14px;font-weight:800;font-variant-numeric:tabular-nums;color:var(--dim)}
.gpill i{font-style:normal;font-size:10px;font-weight:700}
.gpill.lead{color:var(--cash);border-color:color-mix(in srgb,var(--cash) 55%,transparent)}

.gcard.done .gpill,.gcard.done .gbar i{color:var(--dimmer)}


/* Picking between outcomes, then Yes/No on the one you picked. */
.mpick{font-size:13.5px;color:var(--dim);margin-top:7px}
.mpick b{color:var(--cash);font-size:15px}
.mout tr.onthis{background:color-mix(in srgb,var(--cash) 9%,transparent)}
.ohere{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--cash);
  font-weight:700;margin-left:8px}
.owon{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--gold);
  font-weight:700;margin-left:8px}
a.obtn{display:inline-flex;align-items:baseline;gap:5px;text-decoration:none}
.mout .chint.pad{padding:0 16px 14px;margin:0}
.mpout{display:inline-flex;align-items:center;padding:6px 12px;border-radius:99px;
  border:1px solid color-mix(in srgb,var(--cash) 45%,transparent);
  background:rgba(67,201,122,.12)}
.mpout b{font-size:14px;color:var(--cash)}


/* EVERY CARD IN A ROW IS THE SAME HEIGHT, whatever it holds.
   A question with thirty outcomes was stretching its whole grid row and
   leaving the binary cards beside it padded with dead space. The outcome list
   is capped and scrolls its own overflow instead of growing the card. */
.mgrid{align-items:stretch}
.mcard{height:100%}
.gcard .grows{min-height:96px;justify-content:flex-end}
.mcard .orows{min-height:96px;justify-content:flex-end}
.gmore{display:inline-block;align-self:flex-start;font-size:11.5px;color:var(--dim);
  text-decoration:none;padding:2px 8px;border-radius:99px;border:1px solid var(--line);
  margin-top:2px}


/* ---- your positions ---- */
.fol{overflow:hidden}
.folrow{display:grid;grid-template-columns:minmax(0,1fr) auto auto auto;gap:16px;
  align-items:center;padding:14px 17px;border-top:1px solid var(--line);
  text-decoration:none;color:var(--fg);transition:background .15s var(--ease)}
.folrow:first-child{border-top:0}
.folmain{display:flex;flex-direction:column;gap:3px;min-width:0}
.folmain b{font-size:14.5px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.folsub{font-size:12px;color:var(--dim);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.folout{padding:2px 8px;border-radius:99px;background:rgba(67,201,122,.14);color:var(--cash);
  font-weight:700;font-size:11px}
.folnum{display:flex;flex-direction:column;gap:1px;align-items:flex-end;flex:none;min-width:76px}
.folnum b{font-size:15.5px;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.folnum .dlab{font-size:10px}
.folgo{display:flex;align-items:center;gap:9px;flex:none}
.folprice{font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--dim)}
.folsell{padding:6px 13px;border-radius:9px;border:1px solid var(--line);font-size:12.5px;
  font-weight:650;color:var(--dim)}
.fol.done .folrow{opacity:.72}
.folempty b{font-size:16px}
.minego{margin-left:12px;font-size:12.5px;color:var(--cash);font-weight:600;white-space:nowrap}
@media(max-width:719px){
  .folrow{grid-template-columns:minmax(0,1fr) auto;row-gap:9px}
  .folgo{grid-column:1/-1;justify-content:flex-end}
}

/* ---- wallet ---- */
.walside{display:flex;gap:26px;flex-wrap:wrap}
.walstat{display:flex;flex-direction:column;gap:1px}
.walstat b{font-size:22px;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.walstat .dim{font-size:12px}
.walpnl{margin-bottom:20px}
.walpnl .tval.good{color:var(--good)}
.walpnl .tval.bad{color:var(--bad)}


/* Admin markets: three jobs, three sections. */
.mknav{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:18px;padding:4px;border-radius:12px;
  background:var(--card);border:1px solid var(--line);width:fit-content}
.mknavb{padding:9px 16px;border-radius:9px;border:0;background:transparent;color:var(--dim);
  font:inherit;font-size:13.5px;font-weight:650;cursor:var(--xhp);
  transition:background .15s var(--ease),color .15s var(--ease)}
.mknavb.on{background:var(--card2);color:var(--fg)}
.mksec{animation:cardin .35s var(--ease) both}
.mkpeoplehead{margin-bottom:14px}
.pbanned{color:var(--red);font-weight:600}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
}

/* ---- hover effects, for devices that can actually hover ----
   On a touch screen the first tap applies the hover state and the
   second one activates -- which is why buttons needed tapping twice
   on an iPad. Behind a hover query these never reach a finger.
   Selector lists that mixed a hover state with something else
   were SPLIT: the non-hover half stays outside, or states like the
   bell's aria-expanded would stop working on touch. */
/* ---- a rating adjustment ----
   Neither a win nor a loss, so it gets neither colour. Deliberately quiet: it
   is a correction, and a row that shouts would make a tidy record look messy. */
/* Neither a win nor a loss, so it gets neither colour. A three-letter label
   rather than a sign: a lone plus-or-minus in a results column reads as maths,
   not as a category. */
.wl.adj{background:var(--card2);color:var(--dim);border:1px solid var(--line);
  font-size:9.5px;letter-spacing:.06em}
.adjnote{color:var(--dim);font-size:12.5px;display:inline-flex;align-items:center;
  gap:10px;flex-wrap:wrap}
.adjnote b{font-weight:600;color:var(--fg);font-size:12.5px}
.adjnote i{font-style:normal;color:var(--dimmer);font-size:11.5px}
.adjnote form{display:inline}

/* ---- the second ask ----
   A page, not a panel: it takes the profile away and states the one condition
   under which the answer is yes. */
.adjconf{max-width:520px;margin:0 auto}
.adjconfhead{display:flex;align-items:center;gap:13px;margin-bottom:12px}
.adjconfhead h1{margin:0;font-size:22px;letter-spacing:-.015em}
.adjsign.big{width:40px;height:40px;border-radius:12px;font-size:21px}
.adjconflead{margin:0 0 16px;font-size:14.5px;line-height:1.6;color:var(--fg)}
.adjconfrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:12px 14px;border:1px solid var(--line);border-radius:11px;
  background:var(--card2);font-size:13px;margin-bottom:14px}
.adjconfrow b{font-size:13.5px}
/* CANCEL ON THE RIGHT, CONTINUE ON THE LEFT -- the reverse of every other
   dialog here, deliberately. The habit that ends "tap the rightmost button"
   must not be what changes somebody's record. */
.adjconfact{display:flex;gap:10px;align-items:center;margin-top:18px}
.adjconfact form{margin:0}
.adjconfact .btn-ghost{margin-left:auto}
/* The escape hatch, shaped like .pinopt -- the dialog's own idiom for "pick
   this instead" -- because that is exactly what it is: an alternative to
   filling the form in. Squeezed up beside the heading it wrapped onto two
   lines inside a 380px dialog and read as damage rather than as a control. It
   sits directly under the summary, ahead of the map, because "this row is not
   what you think it is" is a question that comes up before the map does. */
.adjopt{display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  padding:11px 13px;border:1px solid var(--line);border-radius:10px;
  background:var(--card2);color:var(--fg);cursor:var(--xhp);font:inherit;
  margin:0 0 16px;
  transition:border-color .15s var(--ease),background .15s var(--ease)}
.adjsign{width:27px;height:27px;flex:none;border-radius:8px;background:var(--bg);
  border:1px solid var(--line);display:flex;align-items:center;justify-content:center;
  font-size:15px;color:var(--dim);line-height:1}
.adjtxt{display:flex;flex-direction:column;gap:2px;min-width:0}
.adjtxt b{font-size:13px;font-weight:600;letter-spacing:-.005em}
.adjtxt i{font-style:normal;font-size:11.5px;color:var(--dimmer);line-height:1.4}

/* ---- the permission matrix ----
   Features down the side, holders across the top. It is inherently wide, so
   the table scrolls inside its own box rather than pushing the page sideways,
   and the first column is stuck to the left edge -- scrolled away, a row of
   ticks means nothing because you cannot see which feature it belongs to. */
/* THE TABLE SCROLLS, AND IT HAS TO LOOK LIKE IT DOES.
   The sticky first column and the sideways scroll both worked from the start;
   what was missing was any sign of it. On a trackpad the scrollbar is an
   overlay that stays hidden until you already know to scroll, so the badges
   past the right-hand edge might as well not have existed.
   A permanent bar, plus a shadow at the edge that fades out once you reach the
   end -- the two gradients are the standard trick: the card-coloured one is
   attached to the CONTENT so it slides over and hides the shadow at the
   extreme, the dark one is attached to the BOX so it stays at the edge. */
/* DELIBERATELY NOT scroll-behavior:smooth. Smooth scrolling turned out to be
   unreliable -- scrollBy with a behavior option did nothing at all in one
   engine, and animating an assignment swallowed rapid clicks because each one
   read a position that was still moving. The arrows exist so the far columns
   can be REACHED; landing exactly where it was told, every time, matters more
   than the glide. */
.pmxwrap{overflow-x:auto;
  border:1px solid var(--line);border-radius:12px;
  background-color:var(--card);
  background-image:linear-gradient(to left,var(--card) 42%,rgba(0,0,0,0)),
    radial-gradient(farthest-side at 100% 50%,rgba(0,0,0,.5),rgba(0,0,0,0));
  background-position:right center,right center;
  background-size:46px 100%,17px 100%;
  background-repeat:no-repeat;
  background-attachment:local,scroll;
  scrollbar-width:thin;scrollbar-color:var(--dimmer) var(--bg)}
.pmxwrap::-webkit-scrollbar{height:11px}
.pmxwrap::-webkit-scrollbar-track{background:var(--bg);border-radius:0 0 11px 11px}
.pmxwrap::-webkit-scrollbar-thumb{background:var(--line);border-radius:7px;
  border:2px solid var(--bg)}
.pmxwrap::-webkit-scrollbar-thumb:hover{background:var(--dimmer)}
.pmxhint{margin:0;font-size:12px;color:var(--dimmer)}
/* ARROWS, BECAUSE A MOUSE CANNOT SCROLL SIDEWAYS.
   The matrix is wider than the page and grows with every badge, so the ones
   at the far end -- Booster, Staff, Owner -- were simply unreachable on a
   desktop: a wheel scrolls the page down, not the table across, and the
   scrollbar is at the bottom of a very tall table. These move it a column at
   a time and grey out at each end so it is obvious when there is no more. */
.pmxbar{display:flex;align-items:center;gap:12px;margin:0 0 10px;flex-wrap:wrap}
.pmxnav{display:flex;gap:6px;margin-left:auto}
.pmxarrow{width:34px;height:30px;border:1px solid var(--line);border-radius:8px;
  background:var(--card2);color:var(--fg);font-size:17px;line-height:1;cursor:var(--xhp);
  display:flex;align-items:center;justify-content:center;padding:0;
  transition:border-color .15s var(--ease),opacity .15s var(--ease)}
.pmxarrow:hover:not(:disabled){border-color:color-mix(in srgb,var(--acc) 60%,var(--line))}
.pmxarrow:disabled{opacity:.32;cursor:var(--xh)}
.pmx{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px}
.pmx th,.pmx td{padding:9px 12px;text-align:center;white-space:nowrap}
.pmx thead th{position:sticky;top:0;background:var(--card2);color:var(--dim);
  font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;font-weight:700;
  border-bottom:1px solid var(--line)}
.pmx th.pmf,.pmx td.pmf{position:sticky;left:0;z-index:2;text-align:left;
  background:var(--card);border-right:1px solid var(--line);min-width:210px}
.pmx thead th.pmf{background:var(--card2);z-index:3}
.pmx tbody tr:not(:last-child) td{border-bottom:1px solid var(--line)}
.pmx td.pmf b{font-weight:600;color:var(--fg)}
.pmx td.pmf i{display:block;font-style:normal;color:var(--dimmer);font-size:11px;
  letter-spacing:.02em}
/* A group heading spans the whole width and is not a data row. */
.pmx tr.pmgrp td{background:var(--bg);color:var(--acc);text-align:left;
  font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;font-weight:700;
  position:sticky;left:0}
/* The cell itself is the label, so the whole square is the hit area -- a 16px
   box is not a comfortable target on a touch screen. */
.pmcell{display:block;padding:2px;cursor:var(--xhp)}
.pmcell input{position:absolute;opacity:0;width:0;height:0;margin:0}
/* ---- the Optimal Index banner ----
   A wide, always-open chart above the bets. Every class is opx-prefixed: this
   sits on the markets page next to several other components and a borrowed
   name is how a badge card once ended up wearing the notification panel's
   header rules. */
.opxband{--opxgut:16px;border:1px solid var(--line);border-radius:16px;
  background:var(--card);overflow:hidden;margin:0 0 18px;position:relative}
/* A hairline of the accent along the top, so the band reads as a live
   instrument rather than another card. */
.opxband::before{content:"";position:absolute;inset:0 0 auto;height:2px;
  background:linear-gradient(to right,var(--teal),var(--acc),var(--pink));opacity:.65}
.opxtop{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  padding:15px 18px 10px;flex-wrap:wrap}
.opxid{display:flex;flex-direction:column;gap:3px;min-width:0}
.opxname{display:flex;align-items:center;gap:9px;font-size:15px;font-weight:700;
  letter-spacing:-.01em}
.opxticker{font-size:10px;font-weight:700;letter-spacing:.1em;color:var(--acc);
  border:1px solid color-mix(in srgb, var(--acc) 40%, var(--line));border-radius:5px;
  padding:2px 6px}
.opxsub{font-size:12px;color:var(--dimmer)}
.opxnow{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.opxval{display:inline-block;transform-origin:left center;
font-size:30px;font-weight:800;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;line-height:1}
.opxchips{display:flex;gap:7px;flex-wrap:wrap}
.opxchip{display:inline-flex;align-items:baseline;justify-content:center;gap:5px;
  min-width:96px;font-size:11px;border:1px solid var(--line);border-radius:999px;
  padding:3px 9px;color:var(--dimmer);font-variant-numeric:tabular-nums}
.opxchip b{font-weight:700}
.opxchip i{font-style:normal;opacity:.75}
.opxchip.up{color:var(--good);border-color:color-mix(in srgb, var(--good) 35%, var(--line))}
.opxchip.dn{color:var(--bad);border-color:color-mix(in srgb, var(--bad) 35%, var(--line))}
/* The plot bleeds to both edges: the chart IS the card, not a picture in it. */

.opxsvg{display:block;width:100%;height:132px}
.opxdot{filter:drop-shadow(0 0 5px currentColor)}
/* An announced multiplier, drawn where it applied. */
.opxevent{fill:var(--acc);opacity:.09}
.opxempty{padding:38px 18px;text-align:center;color:var(--dimmer);font-size:12.5px}
.opxfoot{display:flex;align-items:center;gap:14px;padding:10px 18px 13px;
  border-top:1px solid var(--line);font-size:12px;color:var(--dimmer);flex-wrap:wrap}
.opxlive{display:inline-flex;align-items:center;gap:7px;color:var(--good);font-weight:600}
.opxlive i{width:7px;height:7px;border-radius:50%;background:var(--good);
  box-shadow:0 0 0 0 var(--good);animation:opxpulse 2.4s var(--ease) infinite}
.opxev{color:var(--acc)}
@keyframes opxpulse{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--good) 55%, transparent)}
  70%{box-shadow:0 0 0 7px transparent}100%{box-shadow:0 0 0 0 transparent}}
.opxwhat{cursor:help;border-bottom:1px dotted var(--line)}
.opxgo{margin-left:auto;color:var(--acc);text-decoration:none;font-weight:600}
@media (prefers-reduced-motion:reduce){.opxlive i{animation:none}}
@media (max-width:600px){
  .opxband{--opxgut:13px}
  .opxbookmeta{margin-left:0;text-align:left;flex-basis:100%}
  .opxchip{min-width:0}
  .opxtable td{white-space:normal}
}
@media (max-width:560px){
  .opxval{font-size:25px}
  .opxsvg{height:104px}
  .opxtop{padding:13px 14px 8px}
  .opxfoot{padding:9px 14px 11px;gap:10px}
}

/* ---- the index chart ----
   Kalshi-style: a tight y-axis, prices down the right, timeframe tabs under
   the plot. The first version padded the scale by a fifth of the range and
   showed a flat two days, which squashed a lively index into a straight line. */
.opxmain{margin-bottom:16px}
/* THE CASH MARK IS SIZED IN em, NOT PIXELS. A fixed 17x12 icon beside a 22px
   bold number sits visibly low, because the number's cap height is nearly
   twice the icon's. In em it scales with its neighbour and is aligned once. */
.opxband .cashmark,.opxticket .cashmark{width:1.02em;height:.73em;
  vertical-align:-.035em;margin-right:1px}
.opxmain .opxtable td,.opxmain .opxtable th{padding-left:var(--opxgut)}
.opxmain .opxtable td:last-child,.opxmain .opxtable th:last-child{padding-right:var(--opxgut)}
.opxhead{display:flex;align-items:center;justify-content:space-between;gap:16px;
  row-gap:10px;padding:15px var(--opxgut) 8px;flex-wrap:wrap}
.opxchart{display:block;width:100%;height:260px}
.opxgrid{stroke:var(--line);stroke-width:1;stroke-dasharray:1 6;opacity:.7}
.opxaxis{fill:var(--dimmer);font-size:11px;font-variant-numeric:tabular-nums}
.opxwick{stroke-width:1.4}
.opxwick.up{stroke:var(--good)} .opxwick.dn{stroke:var(--bad)}
.opxcandle.up{fill:var(--good)} .opxcandle.dn{fill:var(--bad)}
/* Your entry, and what it is worth right now. */
.opxentry{stroke-width:1.2;stroke-dasharray:4 5;opacity:.55}
.opxentry.up{stroke:var(--good)} .opxentry.dn{stroke:var(--bad)}
.opxentrytxt{font-size:11px;font-weight:700;font-variant-numeric:tabular-nums}
.opxentrytxt.up{fill:var(--good)} .opxentrytxt.dn{fill:var(--bad)}
/* The live value, pinned to the axis at its own height. */
.opxnowline{stroke-width:1;stroke-dasharray:2 4;opacity:.6}
.opxnowline.up{stroke:var(--good)} .opxnowline.dn{stroke:var(--bad)}
.opxnowpill.up{fill:var(--good)} .opxnowpill.dn{fill:var(--bad)}
.opxnowtxt{fill:var(--bg);font-size:10.5px;font-weight:800;text-anchor:middle;
  font-variant-numeric:tabular-nums}
/* A face where somebody got in, and a purple one where they got out. */
.opxfacering{fill:none;stroke-width:2}
.opxfacering.up{stroke:var(--good)} .opxfacering.dn{stroke:var(--bad)}
.opxfacering.out{stroke:var(--purple)}
.opxfaceblank.up{fill:color-mix(in srgb, var(--good) 30%, var(--card2))}
.opxfaceblank.dn{fill:color-mix(in srgb, var(--bad) 30%, var(--card2))}
.opxfaceblank.out{fill:color-mix(in srgb, var(--purple) 30%, var(--card2))}
.opxfacech{fill:var(--fg);font-size:9.5px;font-weight:700;text-anchor:middle}
/* Timeframe and chart type, under the plot like a trading terminal. */
.opxctl{display:flex;align-items:center;gap:10px;padding:9px var(--opxgut) 12px;
  border-top:1px solid var(--line);flex-wrap:wrap}
.opxtabs{display:flex;gap:2px;flex-wrap:wrap}
.opxtab{padding:5px 11px;border-radius:7px;font-size:11px;font-weight:700;
  letter-spacing:.05em;color:var(--dimmer);text-decoration:none}
.opxtab.on{background:var(--card2);color:var(--fg)}
.opxtypes{display:flex;gap:2px;margin-left:auto}
.opxtype{display:flex;align-items:center;justify-content:center;width:30px;height:26px;
  border-radius:7px;color:var(--dimmer);text-decoration:none}
.opxtype.on{background:var(--card2);color:var(--acc)}
/* Your book, the number people actually watch. */
.opxbook{display:flex;align-items:center;flex-wrap:wrap;row-gap:4px;column-gap:12px;
  margin:0 var(--opxgut) 12px;padding:12px 14px;border:1px solid var(--line);
  border-radius:11px;background:var(--card2)}
.opxbook.up{border-color:color-mix(in srgb, var(--good) 40%, var(--line))}
.opxbook.dn{border-color:color-mix(in srgb, var(--bad) 40%, var(--line))}
.opxbooklab{font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--dimmer);font-weight:700}
.opxbookval{font-size:22px;font-weight:800;font-variant-numeric:tabular-nums;
  line-height:1.1;display:inline-flex;align-items:baseline}
.opxbook.up .opxbookval{color:var(--good)}
.opxbook.dn .opxbookval{color:var(--bad)}
.opxbookmeta{font-size:11.5px;color:var(--dimmer);margin-left:auto;text-align:right}
.opxnone{padding:14px var(--opxgut) 18px;color:var(--dimmer);font-size:12.5px}
.opxmain .opxtable{margin:0 0 6px}
.opxmain .opxoi{margin:0}

/* A LIVE REGION ANIMATES ONCE.
   Table rows across the site fly in with a staggered rise. That is right for a
   page you just opened and wrong for a panel that redraws every few seconds,
   where it reads as the page twitching. The class goes on after the first
   swap, so the first paint still animates. */
.nofx tbody tr,.nofx .rise,.nofx .dr{animation:none !important}
@media (prefers-reduced-motion:reduce){
  #opxhead tbody tr,#opxbook tbody tr,#opxtape tbody tr,#opxticket tbody tr{animation:none}
}

/* The number reacts when it moves.
   The poller only swaps a fragment when the markup actually changed, so a swap
   is news by definition -- worth a beat of colour, not a whole animation. */
@keyframes opxbeat{0%{transform:scale(1)}35%{transform:scale(1.045)}100%{transform:scale(1)}}
.nofx .opxval{animation:opxbeat .42s var(--spring)}
@media (prefers-reduced-motion:reduce){.nofx .opxval{animation:none}}

/* ---- a closed trade, as a card ----
   Modelled on the share cards in the reference: a coloured border, a diagonal
   sheen, and the two numbers that matter set large. Green for a win, red for a
   loss -- the card should be readable from across a timeline. */
.opxcard{position:relative;overflow:hidden;border:1.5px solid;border-radius:14px;
  padding:14px 16px;display:flex;flex-direction:column;gap:12px;max-width:380px;
  background:var(--card2)}
.opxcard.win{border-color:color-mix(in srgb, var(--good) 60%, var(--line));
  background:linear-gradient(150deg,color-mix(in srgb, var(--good) 13%, var(--card2)),var(--card2) 62%)}
.opxcard.loss{border-color:color-mix(in srgb, var(--bad) 60%, var(--line));
  background:linear-gradient(150deg,color-mix(in srgb, var(--bad) 13%, var(--card2)),var(--card2) 62%)}
/* The sheen. Static, not animated: a timeline of these all shimmering at once
   would be unreadable. */
.opxcard::after{content:"";position:absolute;top:-60%;left:-20%;width:60%;height:220%;
  transform:rotate(18deg);pointer-events:none;
  background:linear-gradient(to right,transparent,rgba(255,255,255,.05),transparent)}
.opxcardtop{display:flex;align-items:center;gap:9px;position:relative;z-index:1}
.opxcardmark{font-size:10px;font-weight:800;letter-spacing:.1em;color:var(--acc);
  border:1px solid color-mix(in srgb, var(--acc) 40%, var(--line));border-radius:5px;
  padding:2px 6px}
.opxcardname{font-size:13.5px;font-weight:700;display:flex;align-items:center;gap:8px}
.opxcardname i{font-style:normal}
.opxcardheld{margin-left:auto;font-size:9.5px;font-weight:700;letter-spacing:.09em;
  color:var(--dimmer)}
.opxcardgrid{display:grid;grid-template-columns:1fr 1fr;gap:3px 16px;position:relative;z-index:1}
.opxcardlab{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--dimmer);font-weight:700}
.opxcardnum{font-size:19px;font-weight:800;font-variant-numeric:tabular-nums;
  display:inline-flex;align-items:baseline}
.opxcardpnl{font-size:19px;font-weight:800;font-variant-numeric:tabular-nums;
  display:inline-flex;align-items:baseline}
.opxcard.win .opxcardpnl,.opxcard.win .opxcardpct{color:var(--good)}
.opxcard.loss .opxcardpnl,.opxcard.loss .opxcardpct{color:var(--bad)}
.opxcardsub{font-size:11.5px;color:var(--dimmer);font-variant-numeric:tabular-nums}
.opxcardpct{font-weight:700}
.opxcard.small{max-width:340px;padding:12px 14px}
.opxshare{margin-top:11px}
.opxsay.on .opxcard{margin-bottom:2px}

/* How close a position is to being wiped out. Amber while it is a long way
   off, red once it is close enough to be the thing you should be looking at. */
.opxliq{display:inline-block;margin-left:8px;font-size:10.5px;font-weight:700;
  letter-spacing:.02em;color:var(--dimmer);font-variant-numeric:tabular-nums}
.opxliq.near{color:var(--bad)}
/* A liquidated trade is not the same as a losing one, and the tape should not
   let them read the same. */
.opxcard.wiped{border-color:color-mix(in srgb, var(--bad) 75%, var(--line))}
.opxcardwipe{font-size:9.5px;font-weight:800;letter-spacing:.09em;color:var(--bad);
  border:1px solid color-mix(in srgb, var(--bad) 45%, var(--line));
  border-radius:5px;padding:2px 6px}

/* The tape, as a strip of cards. */
/* A GRID THAT FILLS THE WIDTH, CAPPED, SCROLLING DOWN.
   A single sideways strip left a column of cards down the left and a wall of
   nothing to the right, and a full list ran on forever. Filling the row uses
   the space, and a height cap keeps the tape from owning the page -- there is
   more below, you scroll to it. */
.opxtapecards{display:grid;grid-template-columns:repeat(auto-fill,minmax(244px,1fr));
  gap:11px;padding:2px var(--opxgut,16px) 14px;
  max-height:min(58vh,470px);overflow-y:auto;overscroll-behavior:contain}
.opxtapecards > *{max-width:none}
.opxtapecards::-webkit-scrollbar{width:8px}
.opxtapecards::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.opxtapecards::-webkit-scrollbar-track{background:transparent}
/* A hint that the list keeps going, rather than a hard cut. */
.opxtapewrap::after{content:"";position:absolute;left:0;right:8px;bottom:0;height:34px;
  pointer-events:none;background:linear-gradient(to bottom,transparent,var(--card))}
.opxcardpfp{width:26px;height:26px;border-radius:50%;object-fit:cover;flex:none}

/* The inline message, so a trade never costs you the page. */
.opxsay{max-height:0;overflow:hidden;opacity:0;border-radius:11px;
  transition:max-height .2s var(--ease),opacity .2s var(--ease),margin .2s var(--ease)}
.opxsay.on{max-height:120px;opacity:1;margin:0 0 14px;padding:11px 14px;
  border:1px solid color-mix(in srgb, var(--good) 45%, var(--line));
  background:color-mix(in srgb, var(--good) 8%, transparent);font-size:13px}
.opxsay.on.bad{border-color:color-mix(in srgb, var(--bad) 45%, var(--line));
  background:color-mix(in srgb, var(--bad) 8%, transparent)}
/* THE NAV IS FULL, AND SHOP MUST NOT BE WHAT FALLS OFF THE END.
   Six items on the left plus four on the right overrun a 900px window, and the
   strip scrolls -- so the newest item, sat last, was the one permanently out
   of sight. Below this width the bag stands on its own and the word goes; the
   other tabs give up a little padding at the same time. */
/* THE NAV READS THE SAME EVERYWHERE.
   Two earlier attempts at making it fit changed what it SAYS on smaller
   screens -- first the word Shop vanished and left a bare bag, then
   Leaderboard became Board -- and both times the tablet looked like a
   different site to the desktop. A tab must not change its name at a
   breakpoint.
   The room comes out of the padding instead, which nobody reads. Measured on
   the owner's own nav, which is the widest one because of the Admin tab:
   everything fits with full labels down to roughly 900px, and below that the
   strip scrolls, which it has always done. */
@media (max-width: 1100px){
  .navlinks .tab{padding-left:10px;padding-right:10px}
  .navlinks{gap:4px}
}
/* A sixth destination (Aim) put the strip 55px over on a 768px iPad, where it
   was clipped rather than reachable -- the strip scrolls, but a scroll nobody
   can see is not a way to reach anything. The room comes out of padding and
   the gap between an icon and its word, in that order, because neither is
   read. Labels are untouched: see the rule above. */
@media (max-width: 860px){
  .navin{padding-left:10px;padding-right:10px}
  .navlinks .tab{padding-left:8px;padding-right:8px}
  .navlinks{gap:3px}
  .navlinks .tab svg{margin-right:-1px}
  .navright{gap:7px;padding-left:6px}
}
/* ON A PHONE THE DESTINATIONS GET THEIR OWN ROW.
   At 375px the brand, two words, four icons, the bell and the account need
   about 520px, so the icons sat off the right edge of a strip that scrolls --
   and a scroll nobody can see is not a way to reach anything. Wrapping them
   onto a second row keeps every label exactly as it reads on a desktop (a tab
   must not change its name at a breakpoint), and spreads them across the full
   width so each is a comfortable thumb target. The row costs about 30px of
   sticky height, which is the price of every destination being one tap away. */
/* Matchmaking made it seven destinations, and the owner's right-hand group
   (gear, bell, cash, account) is the widest anyone has: a 768px iPad came up
   111px short and hid Map and Aim off the end. So from iPad width down the
   destinations get their own row too -- every label still reads exactly as it
   does on a desktop. */
@media (max-width:860px){
  .navin{flex-wrap:wrap;row-gap:2px;padding:8px 12px 6px}
  .navleft{order:1}
  .navright{order:2}
  .navlinks{order:3;flex:1 0 100%;justify-content:space-between;gap:0}
  .navlinks .tab{padding:9px 10px}
  .navlinks .navicon{width:42px;height:40px}
}
/* On a phone seven destinations are wider than the glass however tight the
   spacing gets, short of shrinking words below readable. So the row is
   spaced as tightly as a thumb allows, starts at the left rather than spread,
   and FADES at whichever edge has more beyond it -- a row that is cut off with
   no sign of it is a way to lose two destinations, which is the thing this
   whole layout exists to prevent. The fade is drawn by the page script, which
   knows whether there is more to scroll to. */
@media (max-width:559px){
  .navlinks{justify-content:flex-start;gap:2px;scroll-snap-type:x proximity;
    -webkit-overflow-scrolling:touch}
  .navlinks .tab{padding:9px 7px;font-size:14px;scroll-snap-align:start}
  .navlinks .navicon{width:38px;height:40px;scroll-snap-align:start}
  .navlinks.more-r{-webkit-mask-image:linear-gradient(to right,#000 82%,transparent);
    mask-image:linear-gradient(to right,#000 82%,transparent)}
  .navlinks.more-l{-webkit-mask-image:linear-gradient(to left,#000 82%,transparent);
    mask-image:linear-gradient(to left,#000 82%,transparent)}
  .navlinks.more-l.more-r{-webkit-mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent);
    mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent)}
}
@media (max-width:359px){
  .navin{padding-left:8px;padding-right:8px}
  .navlinks .tab{padding:9px 5px}
  .navlinks .navicon{width:34px}
}

/* A day we were not watching yet. Deliberately NOT a short bar -- a short bar
   is a claim about how much was played, and we have no such claim to make. A
   flat dash on the floor reads as absence rather than as a quiet day. */
.bar.nodata .barfill{height:3px;min-height:3px;background:var(--line);
  border-radius:2px;align-self:end;animation:none}
.bar.nodata .barlab{color:var(--dimmer)}
.bar.nodata{opacity:.75}

/* ================== THE GLOBE ==================
   A canvas sphere with real elements floating over it. The canvas draws the
   ball, the land and the activity arcs; the faces are DOM so they can be
   hovered, tapped and linked like anything else on the site.
   gw- prefixed throughout: .gcard already belongs to the upload dialog. */
.globewrap{position:relative;border:1px solid var(--line);border-radius:18px;
  overflow:hidden;background:radial-gradient(circle at 50% 40%,#0a0f1c,#05070c 70%);
  height:min(70vh,620px);touch-action:none;cursor:grab}
.globewrap.grabbing{cursor:grabbing}
.globe{display:block;width:100%;height:100%}
.globepins{position:absolute;inset:0;pointer-events:none}
.gwpin{position:absolute;top:0;left:0;width:30px;height:30px;pointer-events:auto;
  will-change:transform}
.gwdot{width:30px;height:30px;border-radius:50%;padding:0;cursor:var(--xhp);
  border:2px solid var(--acc);background:var(--card2);overflow:hidden;display:block;
  box-shadow:0 0 0 2px rgba(5,6,8,.9),0 0 12px rgba(78,168,240,.5)}
.gwdot img{width:100%;height:100%;object-fit:cover;display:block}
.gwdot i{display:block;width:100%;height:100%;
  background:linear-gradient(140deg,var(--acc),var(--purple))}
/* The card sits above its face and only exists on hover or focus, so four
   hundred of them are not permanently in the way of the map. */
.gwcard{position:absolute;bottom:38px;left:50%;transform:translateX(-50%) scale(.94);
  width:190px;padding:11px 12px;border:1px solid var(--line);border-radius:12px;
  background:color-mix(in srgb,var(--card) 94%,transparent);
  box-shadow:0 12px 34px rgba(0,0,0,.6);opacity:0;pointer-events:none;
  transition:opacity .14s var(--ease),transform .14s var(--ease);z-index:5}
.gwpin:hover .gwcard,.gwpin:focus-within .gwcard{opacity:1;transform:translateX(-50%)}
.gwcardtop{display:flex;align-items:center;gap:9px}
.gwcardtop img{width:28px;height:28px;border-radius:50%;object-fit:cover;flex:none}
.gwcardtop i{width:28px;height:28px;border-radius:50%;flex:none;
  background:linear-gradient(140deg,var(--acc),var(--purple))}
.gwcardtop b{display:block;font-size:12.5px;line-height:1.2}
.gwcardtop span{display:block;font-size:11px;color:var(--dim);margin-top:2px}
.gwcardstat{margin-top:8px;font-size:11.5px;color:var(--dim)}
.gwcardstat b{color:var(--fg);font-variant-numeric:tabular-nums}
.gwcard a{display:block;margin-top:8px;font-size:11.5px;color:var(--acc);
  text-decoration:none}
.gwcard a:hover{text-decoration:underline}
/* Zoom controls, bottom right, out of the way of the sphere. */
.globectl{position:absolute;right:12px;bottom:12px;display:flex;flex-direction:column;
  gap:6px;z-index:6}
.mapzoom{width:32px;height:32px;border-radius:9px;border:1px solid var(--line);
  background:color-mix(in srgb,var(--card) 88%,transparent);color:var(--fg);
  font-size:15px;line-height:1;cursor:var(--xhp);display:flex;align-items:center;
  justify-content:center;padding:0}
.mapzoom:hover{border-color:var(--acc)}
/* ---- the numbers under the globe ----
   A row of quiet tiles that rise in one after another as the page settles.
   Staggered by --i so it reads as one movement rather than five things
   appearing at once. */
.gstgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));
  gap:12px;margin-top:14px}
.gsttile{position:relative;overflow:hidden;padding:15px 16px;border-radius:14px;
  border:1px solid var(--line);background:var(--card);
  animation:gstrise .5s var(--ease) both;animation-delay:calc(var(--i) * 70ms)}
@keyframes gstrise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.gsttile::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 100% 0%,
    color-mix(in srgb,var(--acc) 11%,transparent),transparent 62%)}
.gsttile:hover{border-color:color-mix(in srgb,var(--acc) 40%,var(--line))}
.gstico{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:9px;margin-bottom:10px;color:var(--acc);
  border:1px solid color-mix(in srgb,var(--acc) 30%,var(--line));
  background:color-mix(in srgb,var(--acc) 10%,transparent)}
.gstval{font-size:21px;font-weight:800;line-height:1.15;
  font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
.gstlab{margin-top:3px;font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--dim)}
.gstnote{margin-top:5px;font-size:11.5px;color:var(--dimmer)}
@media (prefers-reduced-motion: reduce){ .gsttile{animation:none} }

/* The rank badge on a globe card, beside the MMR. */
.gwrank{width:16px;height:16px;object-fit:contain;flex:none}
.gwcardstat{display:flex;align-items:center;gap:6px}
.gwcardstat em{font-style:normal;color:var(--dimmer);font-size:10.5px}
/* Zoomed right in, a few cards open on their own -- if you have leaned this
   far into somebody you were going to click them anyway. Only the handful
   nearest the middle get it: six cards already cover a third of the screen. */
.gwpin.opencard .gwcard{opacity:1;transform:translateX(-50%)}
/* "Fill it in for me": offered, never assumed. Quieter than the submit button
   because it is a shortcut, not the point of the form. */
.maploc{display:inline-flex;align-items:center;gap:7px;align-self:flex-start;
  padding:7px 13px;border-radius:9px;cursor:var(--xhp);font-size:12.5px;font-weight:700;
  color:var(--acc);border:1px solid color-mix(in srgb,var(--acc) 40%,var(--line));
  background:color-mix(in srgb,var(--acc) 8%,transparent)}
.maploc:hover:not(:disabled){background:color-mix(in srgb,var(--acc) 16%,transparent)}
.maploc:disabled{opacity:.55;cursor:var(--xh)}
.maplocnote{margin:-4px 0 0;font-size:11.5px;color:var(--dimmer);line-height:1.45}

/* ---- the invitation ----
   Shown over a blurred globe. Friendly on purpose: this asks for something
   personal, so it explains itself before it asks. */
.globewrap.gated .globe{filter:blur(7px) saturate(.6);opacity:.75}
.globewrap.gated{cursor:var(--xh)}
.mapveil{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;padding:20px;overflow:auto;
  background:radial-gradient(circle at 50% 45%,rgba(5,7,12,.55),rgba(5,7,12,.9))}
.mapjoin{width:min(430px,100%);text-align:center;border:1px solid var(--line);
  border-radius:16px;padding:24px 22px;background:color-mix(in srgb,var(--card) 92%,transparent);
  box-shadow:0 20px 60px rgba(0,0,0,.6)}
.mapjoinart{color:var(--acc);margin-bottom:12px;display:flex;justify-content:center}
.mapjoin h2{margin:0 0 8px;font-size:19px}
.mapjoinsub{margin:0 0 16px;font-size:13px;color:var(--dim);line-height:1.5}
.mapwhy{list-style:none;margin:0 0 18px;padding:0;display:flex;flex-direction:column;
  gap:9px;text-align:left}
.mapwhy li{display:flex;gap:9px;align-items:flex-start;font-size:12.5px;
  color:var(--dim);line-height:1.45}
.mapwhy svg{color:var(--cash);flex:none;margin-top:2px}
.mapform{display:flex;flex-direction:column;gap:12px;text-align:left}
.mapfrow{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.mapgo{width:100%;justify-content:center;text-align:center}
.mapfoot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin-top:12px;font-size:12.5px;color:var(--dim);flex-wrap:wrap}
.mapoff{margin:0}
/* Leaving is offered plainly, not dressed up as a warning and not left as a
   bare browser button either. Quiet until you reach for it, then clearly the
   thing that removes you. */
.mapoffbtn{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;
  border-radius:9px;cursor:var(--xhp);font-size:12px;font-weight:700;
  color:var(--dim);border:1px solid var(--line);background:transparent;
  transition:color .15s var(--ease),border-color .15s var(--ease),
    background .15s var(--ease)}
.mapoffbtn:hover{color:var(--bad);background:color-mix(in srgb,var(--bad) 10%,transparent);
  border-color:color-mix(in srgb,var(--bad) 45%,var(--line))}
.mapoffbtn svg{flex:none}
@media(max-width:560px){ .mapfrow{grid-template-columns:1fr} }

/* ---- the aim trainer ----
   The canvas is the page here, so the instructions sit ON it rather than
   above it: a panel that pushed the view down would put the thing being
   aimed at off screen on a phone, which is the one device this has to work
   on. touch-action:none is load-bearing -- without it the browser claims the
   horizontal swipe as a scroll and the gesture never reaches us.
-------------------------------------------------------------------------- */
.aimwrap{
  position:relative; width:100%; height:min(62vh,520px); min-height:320px;
  border-radius:18px; overflow:hidden;
  border:1px solid rgba(120,150,200,.18);
  background:#080b11;
  box-shadow:0 18px 48px rgba(0,0,0,.45);
  touch-action:none; user-select:none; -webkit-user-select:none;
}
.aimcv{ display:block; width:100%; height:100%; cursor:var(--xh); }

.aimstep{
  position:absolute; left:12px; right:12px; bottom:12px;
  padding:14px 16px 16px; border-radius:14px;
  background:rgba(8,11,17,.82);
  border:1px solid rgba(120,150,200,.2);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  animation:aimup .35s cubic-bezier(.2,.8,.3,1) both;
}
@keyframes aimup{ from{ opacity:0; transform:translateY(14px); } to{ opacity:1; transform:none; } }
.aimstep h2{ margin:.35rem 0 .3rem; font-size:1.05rem; letter-spacing:-.01em; }
.aimstep p{ margin:0 0 .35rem; font-size:.83rem; line-height:1.5; color:var(--muted); }
.aimstep b{ color:var(--fg); }

.aimbadge{
  display:inline-block; font-size:.66rem; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase;
  color:#8fb4f0; padding:3px 8px; border-radius:999px;
  background:rgba(96,142,232,.14); border:1px solid rgba(96,142,232,.3);
}
.aimhint{ color:#8fb4f0 !important; font-weight:600; }

.aimdots{ display:flex; gap:7px; margin:.5rem 0 .2rem; }
.aimdots i{
  width:26px; height:5px; border-radius:999px;
  background:rgba(120,150,200,.22); transition:background .25s, transform .25s;
}
.aimdots i.on{ background:#35c9a6; transform:scaleY(1.4); }

.aimredo{ margin-top:.45rem; font-size:.76rem; padding:5px 11px; }

.aimtune{ display:flex; align-items:center; gap:10px; margin:.6rem 0 .1rem; }
.aimtune label{
  display:flex; align-items:center; gap:10px; flex:1;
  font-size:.7rem; text-transform:uppercase; letter-spacing:.07em;
  color:var(--muted); font-weight:700;
}
.aimtune span{
  font-size:.7rem; text-transform:uppercase; letter-spacing:.07em;
  color:var(--muted); font-weight:700;
}
.aimtune input[type=range]{ flex:1; min-width:0; accent-color:#608ee8; }

.aimacts{ display:flex; gap:8px; margin-top:.6rem; }
.aimacts .fbtn{ flex:1; }

.aimread{
  position:absolute; top:58px; left:12px;
  padding:9px 13px; border-radius:12px;
  background:rgba(8,11,17,.8);
  border:1px solid rgba(53,201,166,.3);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  font-size:.78rem; line-height:1.45; max-width:min(260px,58%);
  animation:aimup .4s cubic-bezier(.2,.8,.3,1) both;
}
.aimread b{ color:#35c9a6; font-size:.95rem; }
.aimread span, .aimread em{ display:block; color:var(--muted); font-size:.72rem; font-style:normal; }
.aimread em{ margin-top:.3rem; color:#8fb4f0; }

/* EDGE TO EDGE, OR THE MEASUREMENT IS A LIE.
   In game the thumb starts on the very edge of the glass and crosses the
   whole screen. On the page the canvas is an inset box with padding around
   it, so the same gesture runs out of surface early and every reading comes
   out short -- the player is doing it right and the number is still wrong.
   So measuring happens full screen: no margin, no radius, no border, the
   entire viewport and nothing else. 100dvh rather than 100vh because iOS
   counts its own toolbars out of the smaller one. */
.aimfull{
  position:fixed; inset:0; z-index:400;
  width:100vw; height:100vh; height:100dvh;
  max-width:none; margin:0;
  border:0; border-radius:0; box-shadow:none;
}
.aimfull .aimcv{ width:100%; height:100%; }
body.aimfullbody{ overflow:hidden; }
/* The panel keeps clear of the home indicator. */
.aimfull .aimstep{ bottom:max(10px,env(safe-area-inset-bottom)); }

/* ---- the frame-rate cap ----
   A cap can only ever LOWER the rate. The browser cannot paint faster than
   the display refreshes, so choosing 120 on a 60Hz panel gives 60 -- which
   is why the note beside it reports what is actually being achieved rather
   than what was asked for. */
.aimcap{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.aimcaplab{
  font-size:.68rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.06em; color:var(--muted);
}
/* A segmented control. Shared, because the frame cap and the difficulty are
   the same shape of choice: a few exclusive options, all worth showing. */
.aimseg{
  display:flex; border-radius:10px; overflow:hidden;
  border:1px solid var(--line);
}
.aimseg button{
  padding:7px 16px; border:0; cursor:var(--xhp);
  background:var(--card2); color:var(--dim);
  font-size:.84rem; font-weight:800; font-variant-numeric:tabular-nums;
  border-right:1px solid var(--line);
}
.aimseg button:last-child{ border-right:0; }
.aimseg button:hover{ color:var(--fg); }
.aimseg button.on{ background:var(--acc); color:#04121d; }
.aimcapnote{ font-size:.72rem; color:var(--dim); }

/* ---- the fire button ----
   Big, round, and thumb-reachable, because it is held in the same hand that
   is not swiping. It can be dragged anywhere: where a thumb naturally sits
   differs per person and per grip, and guessing wrong makes the whole
   trainer awkward. touch-action:none so a press never becomes a page scroll.
*/
.aimshoot{
  position:absolute; z-index:8;
  right:max(18px,env(safe-area-inset-right)); bottom:max(18px,env(safe-area-inset-bottom));
  width:88px; height:88px; border-radius:50%;
  display:grid; place-items:center; cursor:var(--xhp);
  touch-action:none; -webkit-user-select:none; user-select:none;
  background:radial-gradient(circle at 38% 32%,rgba(255,255,255,.16),rgba(239,95,74,.30) 60%,rgba(239,95,74,.16));
  border:2px solid color-mix(in srgb,var(--red) 62%,transparent);
  color:#ffd9d2; font-weight:900; letter-spacing:.1em; font-size:.74rem;
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  box-shadow:0 6px 22px rgba(0,0,0,.4);
}
.aimshoot:active{
  transform:scale(.94);
  border-color:var(--red);
  background:radial-gradient(circle at 38% 32%,rgba(255,255,255,.26),rgba(239,95,74,.46) 60%,rgba(239,95,74,.22));
}

/* ---- the score line ---- */
.aimscorebar{
  position:absolute; z-index:7; left:50%; transform:translateX(-50%);
  top:max(52px,calc(env(safe-area-inset-top) + 48px));
  display:flex; gap:14px; padding:6px 14px; border-radius:999px;
  background:rgba(8,11,17,.72); border:1px solid rgba(120,150,200,.2);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  font-size:.62rem; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--dim); white-space:nowrap;
}
#aimdifftag{ color:var(--gold); }
.aimscorebar b{
  color:var(--teal); font-size:.86rem; letter-spacing:0; margin-left:4px;
  font-variant-numeric:tabular-nums;
}

.aimwhyy{
  margin:.6rem 0 0; font-size:.72rem; line-height:1.5; color:var(--dim);
}

/* ---- the menu ----
   A game opens on a menu, not mid-task. The scene idles behind it so the
   trainer reads as one place you move around inside, rather than a series of
   unrelated screens. Back (in the top bar) is always present and always
   leaves for the site -- the one control whose meaning never changes. */
/* Layers: scene HUD 7-8, menu 12, top bar 13 (Back stays reachable over the
   menu), run-over 14, settings sheet 16 (opened FROM the menu, so above it),
   HUD editor 20. The sheet used to sit at 9, under the menu that opens it. */
.aimmenu{
  position:absolute; inset:0; z-index:12;
  display:grid; place-items:center; padding:20px;
  background:radial-gradient(ellipse at 50% 42%,rgba(8,11,17,.72),rgba(4,6,10,.94));
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
  animation:aimfade .22s ease both;
}
.aimmenuin{ width:min(340px,100%); text-align:center; }
.aimmenueyebrow{
  font-size:.64rem; font-weight:800; letter-spacing:.28em;
  text-transform:uppercase; color:var(--gold); margin-bottom:6px;
}
.aimmenutitle{
  margin:0 0 .4rem; font-size:clamp(1.9rem,7vw,2.5rem);
  letter-spacing:-.03em; line-height:1;
}
.aimmenusub{ margin:0 0 22px; font-size:.82rem; color:var(--muted); }
/* The mode list. Each row carries what the mode actually does, because
   "Flick" and "Tracking" mean nothing to someone who has not played an aim
   trainer before, and a name alone would make them guess. */
.aimmodes{ display:flex; flex-direction:column; gap:6px; margin-bottom:14px; }
.aimmode{
  display:flex; align-items:baseline; gap:8px; text-align:left;
  width:100%; padding:9px 12px; border-radius:10px; cursor:var(--xhp);
  background:rgba(17,20,26,.75); border:1px solid rgba(120,150,200,.18);
  color:var(--muted); font-size:.82rem; font-weight:700;
}
.aimmode:hover{ border-color:rgba(120,150,200,.45); color:var(--fg); }
.aimmode.on{
  border-color:var(--acc); color:var(--fg);
  background:color-mix(in srgb,var(--acc) 14%,rgba(17,20,26,.75));
}
.aimmode small{
  margin-left:auto; font-size:.68rem; font-weight:600; color:var(--dim);
  text-align:right; white-space:nowrap;
}
.aimmode.on small{ color:#8fb4f0; }

/* The end of a run. */
.aimover{
  position:absolute; inset:0; z-index:14;
  display:grid; place-items:center; padding:20px;
  background:rgba(4,6,10,.82);
  backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  animation:aimfade .2s ease both;
}
.aimoverin{
  width:min(320px,100%); padding:20px; border-radius:16px; text-align:center;
  background:rgba(9,12,18,.97); border:1px solid rgba(120,150,200,.24);
}
.aimoverhead{
  font-size:.66rem; font-weight:800; letter-spacing:.18em;
  text-transform:uppercase; color:var(--gold); margin-bottom:14px;
}
.aimoverstats{
  display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-bottom:18px;
}
.aimoverstats div{
  font-size:.62rem; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--dim);
}
.aimoverstats b{
  display:block; font-size:1.35rem; letter-spacing:-.02em; color:var(--fg);
  font-variant-numeric:tabular-nums; margin-bottom:2px;
}
.aimover .aimacts{ margin-top:0; }

.aimmenubtns{ display:flex; flex-direction:column; gap:9px; }
.aimmenubtn{
  width:100%; padding:13px 18px; border-radius:12px; cursor:var(--xhp);
  background:rgba(17,20,26,.9); border:1px solid rgba(120,150,200,.26);
  color:var(--fg); font-size:.9rem; font-weight:700; letter-spacing:.02em;
}
.aimmenubtn:hover{ border-color:rgba(120,150,200,.6); background:rgba(24,29,38,.95); }
.aimmenugo{
  background:var(--acc); border-color:var(--acc); color:#04121d;
  font-size:1rem; font-weight:800;
}
.aimmenugo:hover{ background:var(--acc); border-color:var(--acc); color:#04121d; filter:brightness(1.08); }
/* Play stays pressable when it cannot start -- it explains instead of going
   dead, because a button that does nothing teaches nothing. */
.aimmenubtn.aimneedcal{ opacity:.7; }
.aimmenustate{ margin:14px 0 0; font-size:.76rem; min-height:1.1em; color:var(--muted); }
.aimmenustate.warn{ color:var(--gold); }
.aimmenustate.ok{ color:var(--teal); }

/* ---- the crosshair editor ---- */
.aimxh{ display:grid; grid-template-columns:1fr auto; gap:14px; align-items:start; }
.aimxhctl{ min-width:0; }
.aimxhprevwrap{
  border-radius:12px; overflow:hidden; flex:none;
  border:1px solid rgba(120,150,200,.22);
}
.aimxhprevwrap canvas{ display:block; width:120px; height:120px; }
.aimtoggle{
  display:flex; align-items:center; gap:8px; margin:0 0 9px;
  font-size:.72rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.06em; color:var(--muted); cursor:var(--xhp);
}
.aimtoggle input{ accent-color:var(--acc); width:16px; height:16px; flex:none; }
.aimrange input[type=range]:disabled{ opacity:.35; }
@media(max-width:430px){
  .aimxh{ grid-template-columns:1fr; }
  .aimxhprevwrap{ justify-self:center; }
}

/* ---- the HUD editor ----
   The same shape as the game's own customiser: a bar of verbs across the top,
   the controls themselves outlined and draggable, and one panel for whichever
   is selected. The scene stays visible underneath, because a control is only
   in the right place relative to what it sits on top of. */
.aimedit{
  position:absolute; inset:0; z-index:20;
  pointer-events:none;               /* the controls beneath stay draggable */
  background:rgba(4,6,10,.42);
}
.aimeditbar{
  position:absolute; z-index:2; pointer-events:auto;
  top:max(10px,env(safe-area-inset-top)); left:0; right:0;
  display:flex; justify-content:center; gap:8px; flex-wrap:wrap; padding:0 10px;
}
.aimeditbar button{
  display:inline-flex; align-items:center; gap:7px;
  padding:8px 14px; border-radius:10px; cursor:var(--xhp);
  background:rgba(9,12,18,.92); border:1px solid rgba(120,150,200,.3);
  color:var(--muted); font-size:.76rem; font-weight:700;
  letter-spacing:.04em; text-transform:uppercase;
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
}
.aimeditbar button:hover{ color:var(--fg); border-color:rgba(120,150,200,.6); }
.aimeditbar .aimeditgo{
  background:var(--acc); border-color:var(--acc); color:#04121d;
}
.aimeditbar .aimeditgo:hover{ color:#04121d; }

.aimeditpanel{
  position:absolute; z-index:2; pointer-events:auto;
  left:50%; transform:translateX(-50%);
  bottom:max(14px,env(safe-area-inset-bottom));
  width:min(340px,calc(100% - 24px));
  padding:13px 15px 11px; border-radius:14px;
  background:rgba(9,12,18,.95); border:1px solid rgba(120,150,200,.24);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
}
.aimeditname{
  font-size:.68rem; font-weight:800; text-transform:uppercase;
  letter-spacing:.09em; color:#8fb4f0; margin-bottom:10px;
}
.aimedithint{ margin:2px 0 0; font-size:.7rem; color:var(--dim); }

/* An editable control announces itself, and the selected one is unmistakable
   -- otherwise a slider moves something the player is not looking at. */
.aimedittarget{
  outline:1px dashed rgba(143,180,240,.55); outline-offset:3px;
  cursor:grab; touch-action:none;
}
.aimedittarget:active{ cursor:grabbing; }
.aimeditsel{
  outline:2px solid var(--acc); outline-offset:3px;
  box-shadow:0 0 0 5px color-mix(in srgb,var(--acc) 18%,transparent);
}
/* While editing, the fire button must not look like it is about to fire. */
.aimedittarget.aimshoot:active{ transform:none; }

.aimeditopen{ width:100%; margin-bottom:11px; }

/* ---- a labelled slider in the settings sheet ---- */
.aimrange{
  display:grid; grid-template-columns:1fr auto; align-items:center;
  gap:4px 10px; margin-bottom:11px;
  font-size:.68rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.06em; color:var(--muted);
}
.aimrange input[type=range]{ grid-column:1/2; accent-color:var(--acc); min-width:0; }
.aimrange output{
  grid-column:2/3; grid-row:2/3; font-size:.76rem; color:var(--fg);
  font-variant-numeric:tabular-nums; letter-spacing:0; text-transform:none;
}
/* A cap the display cannot reach is still selectable -- it is a real setting
   and the player may move to a device that can -- but it must not look like a
   promise the page can keep. */
.aimseg button.off{ color:var(--dimmer); }
.aimseg button.off.on{ background:color-mix(in srgb,var(--acc) 45%,var(--card2)); color:#0a1520; }

/* The nudge that stops a short measurement before it happens. */
.aimgofull{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-top:.6rem; padding:9px 11px; border-radius:11px;
  background:rgba(240,180,63,.1); border:1px solid rgba(240,180,63,.32);
  font-size:.76rem; color:var(--muted);
}
.aimgofull b{ color:var(--gold); }
.aimgofull .fbtn{ margin-left:auto; padding:5px 13px; font-size:.75rem; }

/* ---- the fields the player copies off the game ---- */
/* X, Y and FOV: typed from the game, then nudged until it feels right. A slider
   for big moves, minus/plus for the last few hundredths. */
.aimdials{ display:flex; flex-direction:column; gap:12px; margin-bottom:9px; }
.aimdial{ display:flex; flex-direction:column; gap:6px; }
.aimdialtop{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
.aimdialtop label{
  font-size:.68rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.06em; color:var(--muted);
}
.aimdialnum{ display:flex; align-items:center; gap:4px; }
.aimdialnum input{
  width:4.6rem; padding:7px 6px; border-radius:9px; text-align:center;
  background:var(--card2); border:1px solid var(--line);
  color:var(--fg); font-size:.95rem; font-weight:700;
  font-variant-numeric:tabular-nums;
}
.aimdialnum input:focus{ outline:none; border-color:var(--acc); }
.aimdialnum button{
  width:32px; height:32px; border-radius:9px; border:1px solid var(--line);
  background:var(--card2); color:var(--fg); font-size:1.05rem; font-weight:700;
  line-height:1; cursor:var(--xhp); touch-action:manipulation;
}
.aimdial input[type=range]{ width:100%; accent-color:var(--acc); min-width:0; }
.aimsetgrid{
  display:grid; gap:9px;
  grid-template-columns:repeat(auto-fit,minmax(130px,1fr));
}
.aimsetgrid label{
  display:flex; flex-direction:column; gap:4px;
  font-size:.68rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.06em; color:var(--muted);
}
.aimsetgrid input{
  width:100%; padding:9px 11px; border-radius:10px;
  background:var(--card2); border:1px solid var(--line);
  color:var(--fg); font-size:1rem; font-weight:700;
  font-variant-numeric:tabular-nums;
}
.aimsetgrid input:focus{ outline:none; border-color:var(--acc); }
.aimsetfoot{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:18px;
}
.aimstate{ margin:0; font-size:.77rem; color:var(--muted); flex:1; min-width:150px; }
.aimstate.ok{ color:var(--teal); }
.aimstate.warn{ color:var(--gold); }

/* ---- the trainer's own chrome ----
   The page is full-bleed, so there is no site nav to leave by. THE WAY OUT
   HAS TO BE ON SCREEN, and it is a labelled Back rather than a bare cross:
   an unlabelled X on a full-screen canvas reads as "close this panel", not
   "leave". Everything here floats over the scene, clear of a notch.
   (This block was once deleted by a careless edit and every control in it
   vanished while still existing in the markup -- invisible, not absent.) */
.aimtop{
  position:absolute; z-index:13;
  top:max(10px,env(safe-area-inset-top));
  left:max(10px,env(safe-area-inset-left));
  right:max(10px,env(safe-area-inset-right));
  display:flex; align-items:flex-start; justify-content:space-between; gap:10px;
  pointer-events:none;
}
.aimtopr{ display:flex; gap:6px; pointer-events:auto; }
.aimicon{
  height:34px; min-width:34px; padding:0 8px;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  flex:none; border-radius:9px; cursor:var(--xhp); text-decoration:none;
  color:var(--dim); font-size:.78rem; font-weight:700;
  background:rgba(8,11,17,.72); border:1px solid rgba(120,150,200,.24);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
}
.aimicon svg{ flex:none; }
.aimicon:hover{ color:var(--fg); border-color:rgba(120,150,200,.5); }
.aimexit{ color:var(--muted); }
.aimexit:hover{ color:var(--fg); border-color:color-mix(in srgb,var(--red) 55%,var(--line)); }

.aimhud{ display:flex; gap:6px; pointer-events:none; }
.aimhudi{
  display:inline-flex; align-items:baseline; gap:3px;
  padding:3px 8px; border-radius:8px;
  background:rgba(8,11,17,.72); border:1px solid rgba(120,150,200,.2);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  font-size:.62rem; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--dim);
}
.aimhudi b{
  font-size:.82rem; letter-spacing:0; color:var(--teal);
  font-variant-numeric:tabular-nums;
}
.aimhudi b.warn{ color:var(--gold); }
.aimhudi b.bad{ color:var(--red); }

/* The settings sheet: a panel over the scene, not a page behind it. */
.aimsheet{
  position:absolute; inset:0; z-index:16;
  display:flex; align-items:stretch; justify-content:flex-end;
  background:rgba(4,6,10,.55);
  backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  animation:aimfade .18s ease both;
}
@keyframes aimfade{ from{ opacity:0 } to{ opacity:1 } }
.aimsheetin{
  width:min(420px,100%); overflow-y:auto; -webkit-overflow-scrolling:touch;
  padding:calc(14px + env(safe-area-inset-top)) 16px
          calc(18px + env(safe-area-inset-bottom));
  background:rgba(9,12,18,.97);
  border-left:1px solid rgba(120,150,200,.2);
  animation:aimslide .22s cubic-bezier(.2,.8,.3,1) both;
}
@keyframes aimslide{ from{ transform:translateX(26px); opacity:0 } to{ transform:none; opacity:1 } }
.aimsheethead{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
.aimsheethead h2{ margin:0; font-size:1.15rem; letter-spacing:-.01em; }

.aimgroup{ margin-top:16px; }
.aimgrouphead{
  font-size:.68rem; font-weight:800; text-transform:uppercase;
  letter-spacing:.09em; color:#8fb4f0; margin-bottom:8px;
  display:flex; flex-direction:column; gap:2px;
}
.aimgrouphead span{
  font-size:.68rem; font-weight:600; text-transform:none;
  letter-spacing:0; color:var(--dim);
}
.aimwhy{
  margin:18px 0 0; padding-top:14px; border-top:1px solid var(--line);
  font-size:.74rem; line-height:1.6; color:var(--dim);
}
.aimwhy b{ color:var(--muted); }

.aimtally{
  margin:.5rem 0 .1rem; padding:7px 10px; border-radius:10px;
  background:rgba(96,142,232,.1); border:1px solid rgba(96,142,232,.26);
  font-size:.78rem; color:var(--muted); font-variant-numeric:tabular-nums;
}
.aimtally b{ color:#8fb4f0; font-size:.92rem; }
.aimtally .aimw{ color:var(--dim); font-size:.72rem; }

.aimlocked{ border-color:rgba(96,142,232,.5); }
.aimlocked .aimcv{ cursor:none; }

.aimsaved{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-top:.6rem; padding:8px 10px; border-radius:11px;
  background:rgba(53,201,166,.09); border:1px solid rgba(53,201,166,.26);
  font-size:.76rem; color:var(--muted);
}
.aimsaved b{ color:#35c9a6; }
.aimsaved .fbtn{ padding:4px 12px; font-size:.74rem; margin-left:auto; }

.aimnote{
  margin:16px 0 0; padding:13px 15px; border-radius:14px;
  background:var(--card); border:1px solid var(--line);
}
.aimnote p{ margin:0; font-size:.8rem; line-height:1.6; color:var(--muted); }
.aimnote b{ color:var(--fg); }

/* On a phone the panel and the reading card together can swallow the whole
   scene, and the scene is the thing being judged. So the canvas grows, the
   panel tightens, and the reading collapses to the one number that matters
   -- the confidence line has already been read by the time it is in the way. */
@media(max-width:560px){
  .aimwrap{ height:min(66vh,500px); border-radius:14px; }
  .aimstep{ left:8px; right:8px; bottom:8px; padding:11px 12px 12px; }
  .aimstep h2{ font-size:.95rem; margin:.3rem 0 .25rem; }
  .aimstep p{ font-size:.77rem; line-height:1.45; margin:0 0 .3rem; }
  .aimbadge{ font-size:.6rem; padding:2px 7px; }
  .aimtune{ margin:.45rem 0 .05rem; gap:8px; }
  .aimacts{ margin-top:.45rem; }
  .aimread{
    max-width:none; right:12px; left:12px; top:56px;
    font-size:.7rem; padding:6px 10px; line-height:1.3;
  }
  .aimread b{ font-size:.82rem; }
  .aimread em{ display:none; }
  .aimread span{ display:inline; margin-left:6px; }
}

/* ---- LOADING ----
   Pages are rendered per request and some of them do real work, so there is a
   gap between the click and the new page. With nothing on screen that reads as
   a dead button, and a dead button gets pressed again -- which is how you end
   up submitting a form twice.
   Three signals, all cheap: a bar across the top that runs while the request
   is out, the brand mark spinning, and the button that was pressed showing it
   is working. */
/* The one in the MIDDLE, which is the one people actually see. A 2px line at
   the very top of the screen is easy to miss on a big monitor and easier still
   on a tablet held at arm's length, and a click that appears to do nothing
   gets clicked again.
   It waits a moment before appearing, so a page that comes back quickly does
   not flash a spinner at you -- and while it is up it takes the pointer, which
   is what actually stops the second click. */
.nload{position:fixed;inset:0;z-index:290;display:flex;align-items:center;
  justify-content:center;opacity:0;pointer-events:none;
  background:color-mix(in srgb,var(--bg) 74%,transparent);
  transition:opacity .2s var(--ease)}
.nload.on{opacity:1;pointer-events:auto}
.nloadbox{display:flex;flex-direction:column;align-items:center;gap:13px}
.nloadmark{width:54px;height:54px;animation:bspin 1s linear infinite;
  filter:drop-shadow(0 6px 20px rgba(0,0,0,.6))}
.nloadtxt{font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;
  color:var(--dim)}
.nprog{position:fixed;top:0;left:0;right:0;height:2px;z-index:300;
  pointer-events:none;opacity:0;transition:opacity .2s var(--ease)}
.nprog.on{opacity:1}
.nprog i{display:block;height:100%;width:0;border-radius:0 2px 2px 0;
  background:linear-gradient(90deg,var(--acc),var(--purple));
  box-shadow:0 0 9px color-mix(in srgb,var(--acc) 70%,transparent)}
/* Creeps most of the way and waits: the page is coming, and pretending to know
   how far along it is would be a lie. */
.nprog.on i{width:92%;transition:width 14s cubic-bezier(.04,.72,.2,1)}
.nprog.done i{width:100%;transition:width .16s var(--ease)}
@keyframes bspin{to{transform:rotate(360deg)}}
.busy .bmark{animation:bspin .85s linear infinite}
/* The pressed button keeps its size and swaps its label for a spinner, so the
   row does not jump while you wait. */
.btnbusy{position:relative;color:transparent!important;pointer-events:none}
.btnbusy::after{content:"";position:absolute;top:50%;left:50%;width:13px;height:13px;
  margin:-7px 0 0 -7px;border:2px solid var(--fg);border-top-color:transparent;
  border-radius:50%;animation:bspin .7s linear infinite;opacity:.85}
@keyframes bpulse{0%,100%{opacity:.35}50%{opacity:1}}
@media (prefers-reduced-motion: reduce){
  .busy .bmark,.btnbusy::after{animation:none}
  /* NOT animation:none -- a frozen logo looks like a page that has died.
     Fading in place is motion nobody gets sick from. */
  .nloadmark{animation:bpulse 1.4s ease-in-out infinite}
  .nprog.on i{width:92%;transition:none}
}

/* ================= THE SHOP =================
   Cash leaves circulation here, so the page has to feel like it is worth
   spending on. Each card is a piece of art with a price under it rather than
   a table row: the tint comes from the item itself (a badge lends its own
   colour), so a shelf of them reads as a set of distinct objects.

   --tint is set per card as an inline style. Everything else derives from it,
   which is why there is no per-item CSS anywhere in this file. */
.shophead{display:flex;align-items:flex-end;justify-content:space-between;
  gap:16px;flex-wrap:wrap;margin:0 0 20px}
.shopbal{display:flex;align-items:center;gap:9px;padding:9px 15px;border-radius:12px;
  border:1px solid color-mix(in srgb, var(--cash) 30%, var(--line));
  background:color-mix(in srgb, var(--cash) 7%, var(--card));
  font-size:19px;font-weight:800;font-variant-numeric:tabular-nums;color:var(--cash)}
.shopbal .cashmark{width:20px;height:15px;flex:none}
.shopbal small{font-size:10.5px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--dim);margin-right:2px}
.shopsec{margin-top:26px}
.shopsec:first-of-type{margin-top:6px}
.shopsech{display:flex;align-items:center;gap:10px;margin:0 0 12px}
.shopsech::after{content:"";flex:1;height:1px;background:var(--line)}
.ncform{margin:0}
.ncpick{display:flex;align-items:center;gap:14px;cursor:pointer}
.ncpick input[type=color]{width:52px;height:40px;padding:0;border:1px solid var(--line);border-radius:10px;background:var(--card2);cursor:pointer}
.ncprev{font-size:20px;font-weight:750}
.shopgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));
  gap:16px;align-items:stretch}
.shopcard{--tint:var(--acc);display:flex;flex-direction:column;position:relative;
  border:1px solid var(--line);border-radius:16px;background:var(--card);
  overflow:hidden;transition:transform .18s var(--ease),border-color .18s var(--ease)}
.shopcard:hover{transform:translateY(-3px);
  border-color:color-mix(in srgb, var(--tint) 45%, var(--line))}
.shopcard.gone{opacity:.55}
.shopcard.gone:hover{transform:none}
/* The art panel. A radial wash of the item's own colour, with its mark sat in
   the middle -- an uploaded picture if it has one, otherwise the badge tick. */
.shopart{position:relative;aspect-ratio:16/10;display:flex;align-items:center;
  justify-content:center;border-bottom:1px solid var(--line);
  background:radial-gradient(circle at 50% 42%,
    color-mix(in srgb, var(--tint) 26%, var(--card2)), var(--card2) 72%)}
.shopart img,.shopart svg{width:104px;height:104px;object-fit:contain;
  filter:drop-shadow(0 6px 18px rgba(0,0,0,.55))}
.shopart .bico{width:104px;height:104px;border-radius:0}
.shopbody{display:flex;flex-direction:column;gap:6px;padding:13px 15px 0;flex:1}
.shopname{font-size:14.5px;font-weight:800;line-height:1.25}
.shopblurb{font-size:12px;color:var(--dim);line-height:1.45}
.shopfoot{display:flex;align-items:center;gap:10px;padding:13px 15px 15px;margin-top:auto}
.shopprice{display:inline-flex;align-items:center;gap:6px;font-size:16px;
  font-weight:800;font-variant-numeric:tabular-nums;color:var(--cash)}
.shopprice .cashmark{width:17px;height:12px;flex:none}
.shopbuy{margin-left:auto;border:0;border-radius:9px;padding:8px 15px;cursor:var(--xhp);
  font-size:12.5px;font-weight:800;letter-spacing:.02em;color:#07090c;
  background:var(--tint);transition:filter .15s var(--ease)}
.shopbuy:hover{filter:brightness(1.12)}
.shopbuy:disabled{background:var(--card2);color:var(--dimmer);cursor:not-allowed;
  filter:none;white-space:nowrap}
/* A corner flag for state the price cannot say: owned, sold out, last few. */
.shopflag{position:absolute;top:11px;right:11px;z-index:1;padding:4px 9px;
  border-radius:999px;font-size:9.5px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;backdrop-filter:blur(4px)}
.shopflag.have{background:color-mix(in srgb, var(--cash) 88%, transparent);color:#07090c}
.shopflag.out{background:rgba(0,0,0,.6);color:var(--dimmer);
  border:1px solid var(--line)}
.shopflag.few{background:color-mix(in srgb, var(--orange) 88%, transparent);color:#07090c}
.shopflag.soon{background:rgba(0,0,0,.55);color:var(--dim);border:1px solid var(--line)}
/* Coming soon reads as a thing that is not ready, not a thing that failed:
   the art is drained of its colour rather than dimmed further. */
.shopcard.gone .shopart{filter:saturate(.25)}
/* The shelf, on the admin screen. One block per item with its controls on the
   row: they used to be the last column of a nine-column table that scrolled
   sideways, so Edit and Remove were off the edge of the page. */
.shopadmlist{display:flex;flex-direction:column;gap:10px}
.shopadm{display:flex;align-items:flex-start;gap:14px;padding:13px 15px;
  border:1px solid var(--line);border-radius:12px;background:var(--card);
  flex-wrap:wrap}
.shopadm.editing{border-color:color-mix(in srgb, var(--acc) 55%, var(--line));
  background:color-mix(in srgb, var(--acc) 6%, var(--card))}
.shopadmart{width:44px;height:44px;flex:none;display:flex;align-items:center;
  justify-content:center;border-radius:9px;background:var(--card2)}
.shopadmart img,.shopadmart svg,.shopadmart .bico{width:30px;height:30px;
  object-fit:contain;border-radius:0}
.shopadmmain{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:6px}
.shopadmname{font-size:14px;font-weight:800}
.shopadmblurb{font-size:12px;color:var(--dim);line-height:1.4}
.shopadmacts{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-left:auto}
.shopadmacts form{display:inline}

/* ---- the receipt ----
   Printed, not designed: a monospaced column with a rule across it, because
   that is what a receipt looks like and it is instantly readable as proof of
   purchase rather than another card. */
.shoprcdlg{max-width:340px}
.shoprc{border:1px solid var(--line);border-radius:12px;background:var(--card2);
  padding:16px 18px;display:flex;flex-direction:column;gap:12px}
.shoprctop{display:flex;align-items:center;justify-content:space-between;
  padding-bottom:10px;border-bottom:1px dashed var(--line)}
.shoprcmark{font-size:10.5px;font-weight:800;letter-spacing:.16em;color:var(--cash);
  border:1px solid color-mix(in srgb, var(--cash) 45%, var(--line));
  border-radius:5px;padding:3px 8px}
.shoprcno{font-size:11px;color:var(--dimmer);font-weight:700;
  font-variant-numeric:tabular-nums;letter-spacing:.06em}
.shoprcname{font-size:16px;font-weight:800;line-height:1.25}
.shoprcrows{display:grid;grid-template-columns:1fr auto;gap:7px 14px;
  align-items:center;font-size:13px}
.shoprcrows span{color:var(--dim)}
.shoprcrows b{font-variant-numeric:tabular-nums;display:inline-flex;
  align-items:center;gap:5px}
.shoprcrows .cashmark{width:15px;height:11px;flex:none}
.shoprcnext{font-size:12.5px;color:var(--dim);line-height:1.45;
  padding-top:11px;border-top:1px dashed var(--line)}
.shoprcfoot{font-size:10.5px;color:var(--dimmer);letter-spacing:.05em;
  text-transform:uppercase;font-weight:700}

/* What you have bought, under the shelf. */
.shopords{display:flex;flex-direction:column;gap:9px;margin-top:12px}
.shopord{display:flex;align-items:center;gap:12px;padding:11px 14px;
  border:1px solid var(--line);border-radius:12px;background:var(--card)}
.shopordt{font-size:13px;font-weight:700}
.shopordm{font-size:11.5px;color:var(--dimmer)}
.shopordtag{margin-left:auto;font-size:10px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;padding:4px 9px;border-radius:999px;border:1px solid var(--line)}
.shopordtag.open{color:var(--gold);border-color:color-mix(in srgb, var(--gold) 40%, var(--line))}
.shopordtag.done{color:var(--cash);border-color:color-mix(in srgb, var(--cash) 40%, var(--line))}
.shopordtag.refunded{color:var(--dim)}
@media (prefers-reduced-motion: reduce){
  .shopcard:hover{transform:none}
}

/* ---- the result popup ----
   A closed trade is the moment the page exists for, and it used to be posted
   into the strip above, which is capped at 120px with overflow hidden: the
   card came out sliced in half. It gets the screen now. */
/* ABOVE THE NAV, which is sticky at 120. At 80 the backdrop dimmed the page
   but left the header sitting brightly on top of it, so the dialog read as a
   panel inside the page rather than in front of it. */
.opxpop{position:fixed;inset:0;z-index:200;display:flex;align-items:center;
  justify-content:center;padding:20px;opacity:0;
  transition:opacity .18s var(--ease)}
.opxpop.on{opacity:1}
.opxpopback{position:absolute;inset:0;background:rgba(0,0,0,.62)}
.opxpopbox{position:relative;display:flex;flex-direction:column;gap:13px;
  width:min(380px,86vw);transform:translateY(12px) scale(.95);
  transition:transform .24s cubic-bezier(.2,.9,.3,1.25)}
.opxpop.on .opxpopbox{transform:none}
.opxpopbox .opxcard{max-width:none;width:100%}
/* Quieter than a primary button: the card is the thing being shown, and a
   full-width saturated blue slab underneath it pulled the eye off the number. */
.opxpopgo{justify-content:center;text-align:center;background:var(--card2);
  color:var(--dim);border:1px solid var(--line);box-shadow:none}
.opxpopgo:hover{background:var(--card);color:var(--fg);
  border-color:color-mix(in srgb, var(--acc) 50%, var(--line))}
/* One sweep across the card as it lands, and the number it is all about
   arrives a beat after the card so the eye goes to it. */
.opxpop.on .opxcard::after{animation:opxsheen .85s var(--ease) .14s both}
@keyframes opxsheen{from{transform:rotate(18deg) translateX(-160%)}
  to{transform:rotate(18deg) translateX(460%)}}
.opxpop.on .opxcardpnl{animation:opxpnl .42s var(--ease) .1s both}
@keyframes opxpnl{0%{transform:scale(.72);opacity:0}
  62%{transform:scale(1.1);opacity:1}100%{transform:none;opacity:1}}
/* The mute switch. Sound you cannot turn off is a bug, so the state is
   visible on the icon itself rather than only in a title. */
.opxsnd{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:26px;border:1px solid var(--line);border-radius:7px;
  background:var(--bg);color:var(--dim);cursor:var(--xhp);padding:0}
.opxsnd:hover{color:var(--fg);border-color:color-mix(in srgb, var(--acc) 55%, var(--line))}
.opxsnd[aria-pressed="true"] .opxsndoff{display:none}
.opxsnd[aria-pressed="false"] .opxsndon{display:none}
.opxsnd[aria-pressed="false"]{color:var(--dimmer)}
/* The balance ticking over after a trade, so the money visibly arrives. */
.cashnum{font-variant-numeric:tabular-nums}
.cashchip.bump{animation:cashbump .5s var(--ease)}
@keyframes cashbump{0%{transform:none}
  35%{transform:translateY(-3px) scale(1.06)}100%{transform:none}}
@media (prefers-reduced-motion: reduce){
  .opxpop,.opxpopbox{transition:none}
  .opxpop.on .opxcard::after,.opxpop.on .opxcardpnl,.cashchip.bump{animation:none}
}
/* ---- buy / sell, as one slider ----
   Radios and sibling selectors, the same pattern as the permission matrix:
   :has() looked right in the DOM and never repainted, so state that has to
   survive a click is always input:checked + something. */
.opxseg{display:inline-flex;position:relative;border:1px solid var(--line);
  border-radius:10px;padding:3px;background:var(--bg);margin-bottom:14px}
.opxsegr{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
.opxsegl{padding:7px 010px;min-width:82px;text-align:center;border-radius:7px;
  font-size:13px;font-weight:700;color:var(--dimmer);cursor:var(--xhp);
  transition:background .15s var(--ease),color .15s var(--ease)}
#opxmode-buy:checked ~ .opxsegl[for="opxmode-buy"]{background:color-mix(in srgb, var(--good) 18%, transparent);color:var(--good)}
#opxmode-sell:checked ~ .opxsegl[for="opxmode-sell"]{background:color-mix(in srgb, var(--bad) 18%, transparent);color:var(--bad)}
/* Only the chosen panel is shown, and the choice lives in the radios. */
.opxpanel{display:none}
.opxticket:has(#opxmode-buy:checked) .opxpanelbuy{display:block}
.opxticket:has(#opxmode-sell:checked) .opxpanelsell{display:block}
.opxsellrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 0;
  border-bottom:1px solid var(--line)}
.opxsellrow:last-of-type{border-bottom:0}
.opxsellmeta{font-size:12.5px;color:var(--dimmer);flex:1;min-width:150px}
.opxsellmeta i{font-style:normal;font-weight:700;margin-left:7px}
.opxsellamt{max-width:104px}

/* ---- scrubbing, and the tape under the chart ---- */
.opxplot{position:relative;line-height:0;touch-action:pan-y;
  transition:opacity .12s var(--ease)}
.opxplot.opxloading{opacity:.55}
.opxchart .hit{cursor:var(--xh)}
.opxchart .cursor{pointer-events:none;transition:opacity .12s var(--ease)}
.opxchart .cx{stroke:var(--dim);stroke-width:1;stroke-dasharray:3 3}
.opxchart .cd{fill:var(--fg);stroke:var(--bg);stroke-width:2}
/* The readout sits over the plot rather than under it, so the number you are
   pointing at is next to the point you are pointing at. */
/* Only while you are pointing at the chart. Left on, it simply repeated the
   big number in the header a few pixels lower, which read as a bug. */
.opxread{position:absolute;top:8px;left:var(--opxgut);display:flex;align-items:baseline;
  gap:9px;font-variant-numeric:tabular-nums;pointer-events:none;line-height:1.2;
  opacity:0;transition:opacity .12s var(--ease);
  background:color-mix(in srgb, var(--bg) 82%, transparent);
  border-radius:7px;padding:3px 8px}
.opxplot.scrubbing .opxread{opacity:1}
.opxread b{font-size:15px;font-weight:800}
.opxread .cdate{font-size:11px;color:var(--dimmer)}
.opxtapewrap{border-top:1px solid var(--line);margin-bottom:18px;position:relative}
.opxtapehead{padding:12px var(--opxgut) 5px;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.07em;color:var(--dimmer);font-weight:700}
.opxtapetbl td{padding:8px 12px}
.opxwho{display:flex;align-items:center;gap:8px;font-size:12.5px;white-space:nowrap}
.opxpfp{width:22px;height:22px;border-radius:50%;object-fit:cover;flex:none}
.opxpfpblank{display:inline-block;background:var(--card2);border:1px solid var(--line)}
.opxpct{display:block;font-style:normal;font-size:10px;opacity:.7;font-weight:600}

/* ---- the index trading page ---- */
.opxoi{display:flex;gap:10px;flex-wrap:wrap;margin:0 0 14px;font-size:12.5px}
.opxoiL,.opxoiS{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--line);
  border-radius:999px;padding:5px 12px;color:var(--dimmer);white-space:nowrap}
.opxoiL b{color:var(--good)}
.opxoiS b{color:var(--bad)}
.opxticket{margin-bottom:16px}
.opxtrow{display:flex;gap:16px;align-items:flex-end;flex-wrap:wrap}
.opxtrow .clfld{min-width:150px}
.opxbtns{display:flex;gap:10px;flex-wrap:wrap;flex:1}
/* Two big, unmistakable choices. A perpetual is entered in a hurry and the one
   thing that must never be ambiguous is which way you just went. */
/* Shape on one shared class, colour on the modifier. Splitting it as
   .opxbuy,.opxsell{...} and then .opxbuy{...} defines each name twice,
   which is exactly the shape the duplicate check is looking for -- and a check
   that is right often enough to be worth keeping is worth writing around. */
.opxside{flex:1;min-width:140px;border-radius:11px;border:1px solid;
  padding:11px 14px;font:inherit;font-weight:700;font-size:14px;cursor:var(--xhp);
  display:flex;flex-direction:column;gap:2px;text-align:left;
  transition:filter .15s var(--ease),transform .12s var(--ease)}
.opxside i{font-style:normal;font-weight:500;font-size:11px;opacity:.75}
.opxside:active{transform:translateY(1px)}
.opxbuy{color:var(--good);border-color:color-mix(in srgb, var(--good) 45%, var(--line));
  background:color-mix(in srgb, var(--good) 12%, transparent)}
.opxsell{color:var(--bad);border-color:color-mix(in srgb, var(--bad) 45%, var(--line));
  background:color-mix(in srgb, var(--bad) 12%, transparent)}
.opxdir{display:inline-block;min-width:52px;text-align:center;font-size:10px;
  font-weight:800;letter-spacing:.07em;border-radius:5px;padding:3px 7px;border:1px solid}
.opxdir.long{color:var(--good);border-color:color-mix(in srgb, var(--good) 40%, var(--line))}
.opxdir.short{color:var(--bad);border-color:color-mix(in srgb, var(--bad) 40%, var(--line))}
.opxtable{width:100%;font-variant-numeric:tabular-nums}
.opxtable th{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;
  color:var(--dimmer);font-weight:700;padding:10px 12px;text-align:left}
.opxtable th.num,.opxtable td.num{text-align:right}
.opxtable td{padding:10px 12px;font-size:13px;white-space:nowrap}
.opxtable tbody tr:not(:last-child) td{border-bottom:1px solid var(--line)}

/* ---- three states per cell, like Discord ----
   Deny, neutral, allow as a small segmented control. Radios rather than a
   checkbox because a checkbox sends NOTHING when it is off, so the form cannot
   tell "denied" from "not mentioned" -- and that is the exact distinction the
   third state exists to make.

   Only the chosen segment is coloured; the other two sit back so a column can
   be read at a glance as a run of ticks, dashes and crosses. */
.pmtri{display:inline-flex;border:1px solid var(--line);border-radius:8px;
  overflow:hidden;background:var(--bg);line-height:0}
.pmopt{display:flex;align-items:center;justify-content:center;width:23px;height:22px;
  cursor:var(--xhp);font-size:12px;color:var(--dimmer);
  transition:background .12s var(--ease),color .12s var(--ease)}
.pmr{position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none}
.pmneutral{border-left:1px solid var(--line);border-right:1px solid var(--line)}
/* THE COLOUR FOLLOWS :checked, NOT A SERVER-RENDERED CLASS.
   It keyed off an "on" class stamped when the page was built, so clicking a
   segment selected the radio and changed nothing on screen -- the control was
   working and looked dead. :has lets the label style itself from the input it
   contains, which is the only version that survives a click. */
.pmr:checked + .pmopt{font-weight:700}
.pmr:checked + .pmdeny{background:color-mix(in srgb, var(--bad) 22%, transparent);
  color:var(--bad)}
.pmr:checked + .pmneutral{background:var(--card2);color:var(--dim)}
.pmr:checked + .pmallow{background:color-mix(in srgb, var(--good) 22%, transparent);
  color:var(--good)}
.pmr:focus-visible + .pmopt{outline:2px solid var(--acc);outline-offset:-2px}

/* The key above the table, so the three glyphs are explained once rather than
   guessed at per cell. */
.pmkey{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-direction:column;gap:6px;
  font-size:12.5px;color:var(--dim)}
.pmkey li{display:flex;align-items:center;gap:9px}
.pmglyph{display:inline-flex;align-items:center;justify-content:center;width:22px;height:21px;
  border:1px solid var(--line);border-radius:7px;font-size:12px;flex:none}
.pmglyph.allow{color:var(--good);background:color-mix(in srgb, var(--good) 20%, transparent)}
.pmglyph.deny{color:var(--bad);background:color-mix(in srgb, var(--bad) 20%, transparent)}
.pmglyph.neutral{color:var(--dim);background:var(--card2)}
/* Everyone reads differently from a badge: it is the floor, not a perk. */
.pmx th.pmall{color:var(--acc)}

/* ---- badge cards ----
   Built for a wall of them: the owner intends to add many, so the card has to
   stay readable at the small end of the grid. Four controls crammed into a
   215px box was the "squished" version -- the icon, the name, what it means,
   how it is earned and three buttons all fighting for the same line. They are
   now four stacked bands with the buttons on their own rule at the bottom. */
/* Which end is which, said on the strip itself rather than only in the
   paragraph above it. The arrows on the cards are meaningless without it --
   "up" and "down" told you nothing about a row that runs sideways. */
.bdgaxis{display:flex;align-items:center;gap:10px;margin:0 2px 8px;
  font-size:10.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--dimmer);
  font-weight:700}
.bdgaxisline{flex:1;height:1px;background:linear-gradient(to right,var(--line),var(--acc))}

/* A LINE, NOT A GRID.
   The cards are a stack with an order, and a wrapping grid hides that: the eye
   reads rows, so nothing says which card is first. In a single scrolling line
   the order IS the layout -- leftmost is the floor, rightmost is the strongest
   -- and the arrows have an obvious meaning because they point along it. */
.bdgstrip{display:flex;gap:12px;overflow-x:auto;padding:2px 2px 10px;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch}
.bdgstrip > *{flex:0 0 246px;scroll-snap-align:start}
/* A thin rail, so it is obvious the row scrolls rather than ending. */
.bdgstrip::-webkit-scrollbar{height:8px}
.bdgstrip::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.bdgstrip::-webkit-scrollbar-track{background:transparent}
/* Position in the stack, so the order can be read off a single card without
   counting along the row. */
.bdgrank{position:absolute;top:10px;right:12px;font-size:10.5px;font-weight:700;
  color:var(--dimmer);font-variant-numeric:tabular-nums}
/* The floor sits apart: nothing to upload, nothing to move. */
.bdgfloor{border-style:dashed}
.bdgnoicon{color:var(--dimmer);font-size:17px}
.bdgcard{border:1px solid var(--line);border-radius:14px;background:var(--card2);
  padding:14px 15px;display:flex;flex-direction:column;gap:10px;min-width:0;
  position:relative}
.bdgcard .bdghead{display:flex;align-items:center;gap:11px;min-width:0}
/* The picture sits in a fixed well, so a tall or wide upload cannot shove the
   name around and every card in the grid lines up. */
.bdgwell{width:38px;height:38px;flex:none;border-radius:11px;background:var(--bg);
  border:1px solid var(--line);display:flex;align-items:center;justify-content:center;
  overflow:hidden}
/* A BADGE PICTURE IS A LOGO, NOT A PORTRAIT.
   Uploads are whatever shape the owner has -- a YouTube mark is roughly 16:9 --
   and there was no object-fit at all, so the width and height attributes on the
   img forced every one of them into a square and stretched it out of shape.
   contain keeps the aspect ratio and letterboxes inside the square, which is
   what a logo wants; cover would crop the ends off a wide mark instead. */
.bico{object-fit:contain;border-radius:5px;vertical-align:middle;flex:none}
.bdgwell .bico{width:32px;height:32px;border-radius:8px}
.bdgwell .vmark{width:22px;height:22px}
.bdgidwrap{min-width:0;display:flex;flex-direction:column;gap:1px}
.bdgcard .bdgname{font-weight:700;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;letter-spacing:-.01em}
.bdgcard .bdgslug{font-size:10.5px;color:var(--dimmer);font-family:var(--mono, ui-monospace, monospace);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bdgcard .bdgdesc{font-size:12px;color:var(--dim);line-height:1.5}
.bdgmeta{display:flex;gap:6px;flex-wrap:wrap}
.bdgpill{border:1px solid var(--line);border-radius:999px;padding:3px 9px;
  font-size:10.5px;color:var(--dim);white-space:nowrap}
.bdgpill b{color:var(--fg);font-weight:700}
.bdgpill.bdgearn{color:var(--acc);border-color:color-mix(in srgb, var(--acc) 40%, var(--line))}
.bdgpill.bdgoff{color:var(--orange);border-color:color-mix(in srgb, var(--orange) 40%, var(--line))}
/* The buttons get their own rule and their own line, so a card with three of
   them reads as a card with actions rather than as a jumble. */
.bdgfoot{display:flex;gap:7px;align-items:center;flex-wrap:wrap;margin-top:auto;
  padding-top:11px;border-top:1px solid var(--line)}
.bdgiconform{display:flex;gap:7px;align-items:center;margin:0}

/* ---- stories ----
   The ring is drawn on a wrapper rather than on the picture: a conic gradient
   cannot live on the same element as the image without covering it, and a
   border cannot hold a gradient at all. Padding makes the gap, and the inner
   element paints the page colour so the ring reads as a ring. */
/* THE RING FOLLOWS THE AVATAR'S OWN SHAPE.
   Avatars here are ROUNDED SQUARES (.mini 9px, .pav .mini 13px, .pfp 21px),
   not circles, so the shape is per-context and the picture keeps its own.

   THE PADDING MUST BE WIDER THAN THE GAP RING, or there is nothing to see:
   2.5px of padding under a 2.5px box-shadow spread painted the page colour
   over the whole gradient. 4px of padding with a 2px gap leaves 2px of colour.

   EVERY MODIFIER IS PREFIXED sr. Plain names do not survive a 160k
   stylesheet: .sring.hero let an unrelated .hero img{height:190px} -- a
   banner component -- match the profile picture through it and blow it up from
   76px to 190px. A prefix makes that collision impossible rather than
   unlikely. cssguard.py fails if any of these names is defined anywhere else. */
.sring{display:inline-block;padding:4px;border-radius:13px;flex:none;line-height:0;
  background:conic-gradient(from 200deg,#f9ce34,#ee2a7b,#6228d7,#f9ce34)}
.sring > *{display:block;box-shadow:0 0 0 2px var(--bg)}
/* Watched: the ring stays, drained of colour, so nothing reflows when the last
   story is opened -- only the meaning changes. --line is the hairline colour
   and reads as no ring at all at this size; --dimmer is muted but present. */
.sring.srseen{background:var(--dimmer)}
/* Circles, for the story tray, where the row reads as faces. */
.sring.srround,.sring.srround > *{border-radius:50%}
/* A feed post's author picture: 44px at 13px, so the ring sits at 17px. */
.pav .sring{border-radius:17px}
/* The profile picture: 76px at 21px, and a slightly heavier ring to match. */
.sring.srface{border-radius:31px;padding:5px}
.sring.srface > *{box-shadow:0 0 0 2.5px var(--bg)}
.sringlink{display:inline-block;line-height:0;text-decoration:none}
.sring.srtiny{padding:3px;border-radius:11px}
.sring.srtiny > *{box-shadow:0 0 0 1.5px var(--bg)}

.stray{display:flex;gap:14px;overflow-x:auto;padding:2px 2px 6px;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.stray::-webkit-scrollbar{display:none}
.sperson{display:flex;flex-direction:column;align-items:center;gap:7px;
  text-decoration:none;color:var(--dim);font-size:11.5px;width:66px;flex:none}
.sperson .sname{max-width:66px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-align:center}
.sperson img,.sperson .letter{width:54px;height:54px;border-radius:50%}
/* One outer size for every face, ringed or not, so the row never jogs. */
.sperson .sring{width:62px;height:62px;box-sizing:border-box}
/* Adding one sits first and is the only square-cornered thing in the row, so
   it does not read as somebody's face. */
.sadd .sring{background:none;padding:0}
.sadd .plus{width:62px;height:62px;border-radius:50%;background:var(--card2);
  border:1.5px dashed var(--line);box-shadow:none;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center;font-size:26px;
  color:var(--acc);font-weight:300;line-height:1}

/* ---- watching one ---- */
.sview{position:fixed;inset:0;z-index:80;background:rgba(8,9,12,.94);
  display:flex;flex-direction:column;align-items:center;justify-content:center;padding:16px}
.sviewbox{width:min(430px,100%);max-height:100%;display:flex;flex-direction:column;gap:10px}
.sbars{display:flex;gap:4px}
.sbar{height:2.5px;border-radius:2px;background:rgba(255,255,255,.28);flex:1}
.sbar.on{background:#fff}
.shead{display:flex;align-items:center;gap:10px;color:#fff;font-size:13px}
.shead .sx{margin-left:auto;font-size:26px;line-height:1;color:#fff;text-decoration:none;
  padding:0 6px;opacity:.8}
.smedia{border-radius:14px;overflow:hidden;background:#000;
  display:flex;align-items:center;justify-content:center;min-height:0}
.smedia img,.smedia video{max-width:100%;max-height:66vh;display:block;object-fit:contain}
.scap{color:#fff;font-size:13.5px;line-height:1.5;text-align:center;
  text-shadow:0 1px 6px rgba(0,0,0,.7)}
.snav{display:flex;gap:10px;align-items:center;justify-content:space-between}
.snav a{color:#fff;text-decoration:none;font-size:13px;opacity:.85;padding:7px 12px;
  border:1px solid rgba(255,255,255,.25);border-radius:9px}
.snav .sgone{opacity:.3;pointer-events:none}
.sseen{color:rgba(255,255,255,.6);font-size:11.5px;text-align:center}

@media (hover: hover) and (pointer: fine){
.adjopt:hover{border-color:var(--acc);background:var(--acc-dim)}
.adjopt:hover .adjsign{color:var(--acc);border-color:var(--acc)}
.lnk:hover{color:var(--acc)}
.btn-sm:hover{transform:translateY(-1px);filter:brightness(1.08)}
.btn-sm.ghost:hover{color:var(--fg);border-color:var(--dim)}
.meBtn:hover{border-color:var(--acc);transform:translateY(-1px)}
.brand:hover .bmark{transform:translateY(-.275em) scale(1.07) rotate(-3deg)}
nav a.tab:hover{color:var(--fg);background:var(--card2)}
form.q button:hover{transform:translateY(-1px)}
.clanlink:hover .b{color:var(--acc)}
.dcbtn:hover{filter:brightness(1.08);transform:translateY(-1px)}
.ctile:hover{border-color:var(--acc);transform:translateY(-3px)}
.clcard:hover{border-color:var(--acc);transform:translateY(-2px)}
.clrp:hover{border-color:var(--acc)}
.cljoin:hover{filter:brightness(1.08)}
.clsec > summary:hover{background:var(--card2)}
.cchip:hover{border-color:var(--dim);color:var(--fg)}
.svcard:hover{border-color:var(--acc);transform:translateY(-2px)}
.mini-btn.danger:hover{border-color:var(--bad)}
.sgrow:hover{background:var(--card2)}
tbody tr:hover{background:var(--card2)}
.tabs button:hover{color:var(--fg);border-color:var(--dim)}
.ftab:hover{color:var(--fg)}
a.fstat:hover{color:var(--fg)}
.fbtn:hover{transform:translateY(-1px)}
.fbtn.on:hover{color:var(--bad);border-color:var(--bad)}
.embcell:hover{border-color:var(--acc);transform:translateY(-2px);color:var(--fg)}
.a2hsX:hover{color:var(--fg)}
.bellbtn:hover{color:var(--fg);border-color:var(--dim)}
.nptoggle:hover{color:var(--fg)}
.pfpflip:hover::after{border-color:var(--acc)}
.mini-btn:hover{color:var(--fg);border-color:var(--dim)}
.mini-btn.bad:hover{color:var(--red);border-color:var(--red)}
.btn:hover{transform:translateY(-1px)}
.seg a:hover{color:var(--fg)}
a.g:hover{border-color:var(--dim);transform:translateX(4px)}
a.g:hover .bg{opacity:.5}
.tile:hover{border-color:var(--dim);transform:translateY(-2px)}
.bar:hover .bartip{
  opacity:1;transform:translate(-50%,0) scale(1)}
.bar:hover .barfill{opacity:1;filter:brightness(1.25)}
.bar:first-child:hover .bartip{transform:translate(0,0) scale(1)}
.bar:last-child:hover .bartip{transform:translate(0,0) scale(1)}
a.tile:hover{border-color:var(--acc);transform:translateY(-3px)}
a.tile:hover .tgo{color:var(--acc);transform:translateX(3px)}
.btn-ghost:hover{border-color:var(--acc);color:var(--acc)}
.drop:hover{border-color:var(--dim)}
.filterbox summary:hover{background:var(--card2)}
.acctlink:hover{transform:translateX(3px)}
.acctlink:hover b{color:var(--acc)}
.filters a:hover{color:var(--fg);border-color:var(--dim)}
.res-row:hover{border-color:var(--acc);transform:translateX(3px);background:var(--card2)}
.ytfeat:hover .ytftitle{color:var(--acc)}
.ytfeat:hover .ytfthumb img{transform:scale(1.05)}
.ytfeat:hover .ytfplay{transform:translate(-50%,-50%) scale(1.1)}
.chpicwrap:hover .chpic{transform:translateY(-2px) scale(1.04)}
.srow:hover{background:var(--card2)}
.post:hover{background:var(--card2)}
.pdelbtn:hover{color:var(--bad);background:color-mix(in srgb,var(--bad) 12%,transparent)}
.ytcard:hover .ytplay{transform:translate(-50%,-50%) scale(1.09)}
.linkcard:hover{border-color:var(--acc)}
.vbtn:hover:not(:disabled){color:var(--acc);background:var(--acc-dim)}
.vbtn.on:hover{background:color-mix(in srgb,var(--good) 14%,transparent)}
.vbtn.dn:hover:not(:disabled){color:var(--bad);background:color-mix(in srgb,var(--bad) 12%,transparent)}
.sortbtn:hover{color:var(--fg)}
.vopt:hover{color:var(--fg);border-color:var(--dim)}
.embcell.used:hover{opacity:1}
.embcell:hover{border-color:var(--acc);background:var(--card);transform:translateY(-2px);
  color:var(--fg)}
a.card:hover{border-color:var(--dim);transform:translateY(-2px)}
.cashchip:hover{border-color:var(--cash);transform:translateY(-1px)}
.dr:hover .fixbtn{opacity:1}
.fixbtn:hover{color:var(--acc);background:var(--card2)}
.pinopt:hover{border-color:var(--dim);background:var(--card2)}
.mapopt:hover{border-color:var(--dim);transform:translateY(-2px)}
.mapopt:hover img{filter:saturate(1) brightness(.9)}
.dr.addrow:hover td{background:var(--card2)}
.dr.addrow:hover .dim{color:var(--acc)}
.upfile::file-selector-button:hover{border-color:var(--acc)}
.dr.un:hover td{opacity:.8}
.dtable tr.lnkrow:hover td{background:var(--card2)}
.mkkind:hover{border-color:var(--dim)}
.mcard:hover{border-color:var(--cash);transform:translateY(-3px)}
.mcard.done:hover{opacity:1;border-color:var(--line)}
.mineband:hover{border-color:var(--cash)}
.backlnk:hover{color:var(--acc)}
.mtside:hover{border-color:var(--dim)}
.mstake:hover:not(:disabled){color:var(--fg);border-color:var(--dim)}
.whorow:hover{background:var(--card2);outline:0}
.mkframe:hover{color:var(--fg)}
.obtn:hover{border-color:var(--cash);background:rgba(67,201,122,.1)}
.mpside:hover{border-color:var(--dim);color:var(--fg)}
.mkpreset:hover{color:var(--fg);border-color:var(--cash)}
.mkcardbox .mcard:hover{transform:none;border-color:var(--line)}
.mkout.yes:hover{border-color:var(--cash);background:rgba(67,201,122,.1)}
.mkout.no:hover{border-color:var(--blue);background:var(--acc-dim)}
.mkout.void:hover{border-color:var(--orange);background:rgba(224,138,74,.1)}
.mkchart:hover .cline.no{opacity:.85}
.navicon:hover{background:color-mix(in srgb,var(--ni) 14%,transparent)}
.mout tbody tr:hover{background:var(--card2)}
.obtn:hover{transform:translateY(-1px)}
.mtgo:hover:not(:disabled){transform:translateY(-1px);filter:brightness(1.05)}
.grow:hover{background:var(--card2)}
.gmore:hover{color:var(--cash);border-color:var(--cash)}
.folrow:hover{background:var(--card2)}
.folrow:hover .folsell{border-color:var(--cash);color:var(--cash)}
.fol.done .folrow:hover{opacity:1}
.mknavb:hover{color:var(--fg)}
}

/* ---- the cursor is a crosshair ----
   Desktop only: hover:hover and pointer:fine is a mouse or trackpad, and a
   phone has no cursor to change. Two crosshairs, because a crosshair that
   looks the same over a button as over plain text would take away the one
   thing a pointer hand tells you -- that it clicks. White is the page; blue
   means clickable. Each is a token, so the 65 rules that used to ask for
   'pointer' now ask for the blue one and every clickable thing agrees.
   Deliberately untouched: grab and grabbing (the globe, the HUD editor),
   help, not-allowed, text in inputs, and 'none' while the aim trainer holds
   the pointer. A dark outline keeps both visible on a light image. */
:root{ --xh:auto; --xhp:pointer; }
@media (hover:hover) and (pointer:fine){
  :root{
    --xh:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.5v6M12 15.5v6M2.5 12h6M15.5 12h6' stroke='%2305070b' stroke-opacity='.7' stroke-width='3.4' stroke-linecap='round'/%3E%3Cpath d='M12 2.5v6M12 15.5v6M2.5 12h6M15.5 12h6' stroke='%23ffffff' stroke-width='1.7' stroke-linecap='round'/%3E%3Ccircle cx='12' cy='12' r='1.9' fill='%23ffffff' stroke='%2305070b' stroke-opacity='.7' stroke-width='1.1'/%3E%3C/svg%3E") 12 12, crosshair;
    --xhp:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.5v6M12 15.5v6M2.5 12h6M15.5 12h6' stroke='%2305070b' stroke-opacity='.7' stroke-width='3.4' stroke-linecap='round'/%3E%3Cpath d='M12 2.5v6M12 15.5v6M2.5 12h6M15.5 12h6' stroke='%234ea8f0' stroke-width='1.7' stroke-linecap='round'/%3E%3Ccircle cx='12' cy='12' r='1.9' fill='%234ea8f0' stroke='%2305070b' stroke-opacity='.7' stroke-width='1.1'/%3E%3C/svg%3E") 12 12, pointer;
  }
}
html{cursor:var(--xh)}
a[href],button:not(:disabled),select,summary,label[for],[role="button"],
input[type="checkbox"],input[type="radio"],input[type="range"],
input[type="submit"],input[type="file"]{cursor:var(--xhp)}

/* ---- a page that is not open yet ---- */
.cmsoon{max-width:520px;margin:clamp(24px,8vh,80px) auto 40px;text-align:center;
  padding:34px 26px 30px;border-radius:20px;background:var(--card);
  border:1px solid color-mix(in srgb,var(--cmsoon) 30%,var(--line))}
.cmsoonicon{width:84px;height:84px;margin:0 auto 16px;border-radius:24px;
  display:grid;place-items:center;color:var(--cmsoon);
  background:color-mix(in srgb,var(--cmsoon) 13%,transparent);
  border:1px solid color-mix(in srgb,var(--cmsoon) 35%,transparent)}
.cmsoonbadge{display:inline-block;padding:4px 11px;border-radius:999px;margin-bottom:10px;
  font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--cmsoon);background:color-mix(in srgb,var(--cmsoon) 12%,transparent)}
.cmsoontitle{margin:0 0 10px;font-size:clamp(28px,6vw,36px);letter-spacing:-.02em}
.cmsoonlead{margin:0 auto;max-width:44ch;font-size:15.5px;line-height:1.55;color:var(--fg)}
.cmsoondetail{margin:10px auto 0;max-width:44ch;font-size:13.5px;line-height:1.6;color:var(--dim)}
.cmsoonacts{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:22px}
.cmsoonacts .btn,.cmsoonacts .btn-ghost{text-decoration:none}
@media (prefers-reduced-motion:no-preference){
  .cmsoonicon{animation:cmsoonpulse 2.6s var(--ease) infinite}
  @keyframes cmsoonpulse{0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--cmsoon) 0%,transparent)}
    50%{box-shadow:0 0 0 10px color-mix(in srgb,var(--cmsoon) 10%,transparent)}}
}

/* ---- guest preview label, beside Sign in ---- */
.guestpill{display:inline-flex;align-items:center;padding:4px 10px;border-radius:999px;
  font-size:12px;font-weight:700;white-space:nowrap;color:var(--gold);
  border:1px solid color-mix(in srgb,var(--gold) 45%,var(--line));
  background:color-mix(in srgb,var(--gold) 10%,transparent)}
@media (max-width:559px){ .guestpill{font-size:11px;padding:3px 8px} }

/* ---- sign out, at the foot of your own profile ---- */
.signoutrow{display:flex;justify-content:center;margin:34px 0 8px;padding-top:22px;
  border-top:1px solid var(--line)}
.signoutbtn{display:inline-flex;align-items:center;gap:8px;padding:10px 20px;
  border-radius:11px;border:1px solid color-mix(in srgb,var(--red) 40%,var(--line));
  background:color-mix(in srgb,var(--red) 7%,transparent);color:var(--red);
  font-size:14px;font-weight:650;cursor:var(--xhp)}
.signoutbtn:focus-visible{outline:2px solid var(--red);outline-offset:2px}
.signoutform{display:inline}
@media (max-width:559px){ .signoutbtn{width:100%;justify-content:center} }

