/* ---------- daily ---------- */
.daily-intro{padding:26px 40px 0;text-align:center}
.daily-h{font:900 38px/1.06 var(--display);letter-spacing:-.02em;margin:0 0 10px}
.daily-actions{display:flex;gap:12px;justify-content:center;padding:20px 40px 0;
  flex-wrap:wrap}
/* the badge rides inside the deck name, so it needs its own air */
/* UNDER THE NAME, NOT BESIDE IT. Beside a 27px category this ran the card two
   lines wide and "ARCHIVE ONLY" wrapped into the name — "GeographyARCHIVE
   ONLY". Its own line under the title fits every card at every width, and the
   badge reads as a note about the category rather than part of its name. */
.dd-state{display:block;font:700 10.5px/1 var(--mono);letter-spacing:.12em;
  text-transform:uppercase;color:var(--text-muted);margin:7px 0 0;
  white-space:nowrap}
.dd-state.on{color:var(--mint)}
/* NEW. A filled pill rather than another word in the same muted grey the
   today/archive states use — the point is that it catches the eye of somebody
   who has already learned to skim this row of cards, and a fourth item in the
   same style would not. Rides in the deck name beside the state badge, so a
   card can say "new" and "today" at once. */
.dd-new{display:inline-block;font:900 10px/1 var(--display);letter-spacing:.1em;
  text-transform:uppercase;background:var(--gold);color:var(--ink-2,#14121F);
  border-radius:999px;padding:4px 8px;margin-left:9px;white-space:nowrap;
  vertical-align:1px}
.daily-arch{padding:22px 40px 34px}
.daily-arch .share-btn{width:100%}
#dailyArchList{display:none;margin-top:12px}
#dailyArchList.open{display:block}
/* CONTROLS THAT ARE BUTTONS BUT MUST NOT LOOK LIKE ONE.
   These four were <div>s and <span>s with click handlers, which meant the
   archive of past dailies, the friend picker and every username on every
   leaderboard could be used with a mouse and not at all with a keyboard.
   They are <button>s now.

   A button brings its own font, colour, background, border and centred text,
   and all four of these sit inside a layout that already decided those. The
   reset lives here rather than being repeated four times because the next one
   of these will forget a line otherwise — and a control that suddenly renders
   in Arial is the kind of regression that gets "fixed" by turning it back
   into a div. */
.arch-item,.ch-row,.lb-who,.fr-open{
  font:inherit;color:inherit;background:none;border:0;text-align:left;
  /* Buttons do not inherit this, and the ellipsis truncation on the children
     depends on it — without it a long username stops truncating and pushes
     the score off the end of the row. */
  min-width:0;
  /* MEASURED, NOT ASSUMED. A very long username already overflowed its grid
     column by 37px as a <span>; as a <button> that went to 63px, because a
     button will not shrink below its content the way an anonymous run of text
     will. Clipping takes both to zero — so this fixes the regression the
     conversion introduced AND the older overflow that was sitting underneath
     it. The ellipsis lives on the children that have one; this is the floor
     that stops the row growing either way. */
  overflow:hidden}
/* Only the two that ARE their own full-width row. .lb-who and .fr-open sit
   inside a flex or grid row that already sizes them, and 100% there breaks it. */
.arch-item,.ch-row{width:100%}

.arch-item{display:flex;align-items:center;gap:14px;padding:12px 16px;
  background:var(--sheet);border-radius:12px;margin-bottom:8px;cursor:pointer}
.arch-item:hover{background:var(--sheet-2)}
.arch-date{font-size:11px;letter-spacing:.12em;color:var(--text-muted)}
.arch-play{margin-left:auto;font:700 11px/1 var(--mono);letter-spacing:.12em;
  text-transform:uppercase;color:var(--gold)}

/* ---------- boards ---------- */
.lb-panel{background:var(--sheet);border:0;border-radius:16px;padding:18px 22px;
  margin-bottom:16px}
.lb-panel h3{font:900 15px/1 var(--display);letter-spacing:.02em;margin:0 0 12px;
  color:var(--text)}
.hof-sub,.lb-you{font-size:10px;letter-spacing:.12em;color:var(--text-muted);margin-top:10px}
.hof-date{font-size:10px;letter-spacing:.12em;color:var(--text-muted)}
/* Two different rows share this class. The daily board builds a plain
   two-part row (rank+name, then score); the Hall of Fame's `.big` variant
   builds four parts (rank, avatar, name, score). Flex suits the first,
   a four-track grid the second — one grid for both left the score
   wrapping onto its own line. */
.lb-row{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:9px 0;border-bottom:1px solid var(--hair);font-size:14px}
.lb-row:last-child{border-bottom:0}
.lb-row.me{background:rgba(var(--gold-rgb),.09);border-radius:8px;
  padding-left:8px;padding-right:8px}
.lb-row.big{display:grid;grid-template-columns:auto auto 1fr auto;gap:10px}
.lb-rank{font-weight:700;color:var(--text-muted);font-variant-numeric:tabular-nums}
.lb-who{display:flex;align-items:center;gap:9px;min-width:0;cursor:pointer}
.lb-who .who,.lb-name{font-weight:700;color:var(--text);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.lb-who:hover .who,.lb-who:hover .lb-name{color:var(--gold)}
.lb-score{font-weight:700;color:var(--gold);font-variant-numeric:tabular-nums}
.lb-row.big{padding:12px 0}
.lb-row.big .lb-rank{font:900 17px/1 var(--display);color:var(--gold)}
#hofList .lb-panel::before{display:none}
#hofList .lb-row:first-of-type .lb-rank{color:var(--gold)}

/* ---------- modals ---------- */
.modal-bg{background:rgba(6,12,14,.72)}
/* THESE THREE FLOAT ABOVE THE PAGE and were hardcoded #16262B. That was fine
   while there was one palette; with light mode it left dark cards carrying
   `color:var(--text)`, which is near-black there — the auth modal's title came
   out at 1.14:1 against its own background, i.e. invisible, and so did every
   other modal in the game. --overlay flips; --text was already right. */
.modal{background:var(--overlay);border:1px solid var(--border);border-radius:18px;
  padding:26px;box-shadow:0 20px 50px rgba(0,0,0,.6);
  max-height:calc(100vh - 44px);overflow-y:auto}
.modal h2{font:900 24px/1.1 var(--display);letter-spacing:-.02em;margin:0 0 8px;
  color:var(--text)}
/* 16px, not 15. Safari zooms the page on focus for anything smaller and never
   zooms back out, which on the five-field register form puts the submit button
   off screen from the first tap. The base rule sets 16 and this one overrides
   it, so the size has to be repeated here. test_authmarkup.js guards it. */
.modal input{background:var(--field);border:1px solid var(--border);
  border-radius:10px;color:var(--text);font-family:var(--font);font-size:16px;padding:12px 14px}
.modal input:focus,.mp-wrap input:focus{outline:2px solid var(--gold);outline-offset:2px;border-color:var(--gold)}
.modal input::placeholder,.mp-wrap input::placeholder{color:var(--text-muted)}
.modal-card{background:var(--overlay);border-radius:18px;padding:24px}

/* THE PLAYER CARD IS AN OVERLAY, NOT A CARD.

   `#playerModal` is toggled with `.show` and dismissed by clicking its own
   backdrop — overlay behaviour — but its markup carries `.modal`, which is
   the style for the panel INSIDE an overlay. `.modal-bg` is the class that
   owns `display:none` and `.show{display:flex}`, and nothing has ever given
   `#playerModal` either.

   So it has always rendered: an empty bordered panel sitting at the foot of
   the game screen, under the reveal. It predates the redesign — in the old
   light sheet it was an empty white box in the same place — and it only
   became worth chasing when a phone's worth of vertical space started
   mattering, because it is ~100px of nothing between the fact panel and the
   end of the round.

   Fixed here rather than in the markup so the ids and classes the profile
   code and the suites reach for all stay exactly where they are. */
/* ABOVE the other modals, not level with them. A profile is opened FROM
   somewhere — a board row, and now a name in the Friends list — so it is
   always the second sheet on screen. At the shared z-index:100 the stack fell
   to DOM order, and #friendsModal is declared later, so a card opened from the
   friends list rendered behind the list that opened it. Sitting on top also
   means closing it returns you to the list rather than to nothing, which is
   what you want when reading through several friends. */
#playerModal{position:fixed;inset:0;z-index:120;
  background:rgba(6,12,14,.72);
  display:none;align-items:center;justify-content:center;padding:20px;
  border:0;border-radius:0;max-height:none;overflow-y:auto}
#playerModal.show{display:flex}
#playerCard{width:100%;max-width:420px;max-height:calc(100vh - 40px);
  overflow-y:auto}

/* ---------- auth modal: labelled fields, per-field errors ----------
   Rewritten for the cabinet. The previous version of this block hardcoded
   light hex (#EAF2F1, #EDF1EF) against the CONTOUR sheet, which is exactly what
   broke when the sheet was replaced: --abyss went from near-black to #fff, so
   those panels became white-on-white. Everything here reads a variable now, so
   the next reskin costs this block nothing.

   Labels are IBM Plex Mono small caps to match the rest of the cabinet, not the
   Archivo display face. */
.auth-field{margin:0 0 12px}
.auth-field label{display:block;font-family:var(--mono);font-weight:600;
  font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--text-muted);margin-bottom:6px}
.auth-field input{margin-bottom:0}
.auth-field.bad input{border-color:var(--red)}
.auth-field.bad label{color:var(--red)}
.auth-hint{font-size:11.5px;color:var(--text-muted);line-height:1.4;margin-top:5px}
/* :empty matters. .modal .err reserves min-height for one message, which is
   right for one and wrong for five — reserving all five would add ~90px of dead
   height to the tallest view on the smallest screen. */
.auth-fe{color:var(--red);font-size:12.5px;line-height:1.35;margin-top:5px}
.auth-fe:empty{display:none}
.auth-row{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  margin-top:2px}
.auth-row a{font-size:11.5px;color:var(--gold);cursor:pointer;font-weight:700;
  text-decoration:underline;text-underline-offset:3px;
  display:inline-block;padding:6px 0}          /* padding = tap target */
.auth-note{font-size:13px;color:var(--text-muted);line-height:1.55;margin:0 0 14px}
.auth-ok{border-left:3px solid var(--gold);background:var(--panel-3);
  padding:12px 14px;font-size:13.5px;line-height:1.55;margin:0 0 16px;
  color:var(--text);border-radius:0 8px 8px 0;word-break:break-word}
.auth-lock{background:var(--field-lock) !important;color:var(--text-muted) !important}
/* ---------- the end-of-round popup ---------- */
/* The streak is the headline, so it is sized like one. Everything else in the
   box is deliberately quieter than the number. */
.rp-cap{font:900 10.5px/1 var(--display);letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-muted);text-align:center;margin-bottom:14px}
.rp-streak{text-align:center;margin:0 0 4px}
.rp-n{font:900 54px/1 var(--display);color:var(--gold);font-variant-numeric:tabular-nums;
  display:block;letter-spacing:-.02em}
/* A cold streak must not wear the flame. Zero is the state where somebody has
   just come back after missing a day, and celebrating that with the same gold
   as a thirty-day run reads as mockery. */
.rp-streak.cold .rp-n{color:var(--text-muted)}
.rp-days{font:900 12px/1 var(--display);letter-spacing:.14em;text-transform:uppercase;
  color:var(--text-muted);display:block;margin-top:8px}
.rp-note{font-size:12.5px;color:var(--text-muted);text-align:center;line-height:1.5;
  margin:12px 0 0}
.rp-note a{color:var(--gold);cursor:pointer;text-decoration:underline}
/* The share block inside the popup.

   EVERY SIDE GETS PADDING. This used to say `padding:0` with a padding-top
   added back, on the theory that the card was a plain section needing only a
   rule above it. It is not: .share-card carries a border on all four sides and
   a 16px radius, so zero horizontal padding ran the title, the grid and the
   buttons flat into the border, and hardest into the rounded corners where the
   frame cuts furthest in. The bottom is the one that showed worst — the copy
   button carries a 5px drop shadow (see .share-btn) and with no bottom padding
   it hung through the border and out of the box.

   Declared outright rather than tweaked, so it does not depend on which of the
   two base .share-card rules wins here. */
#rpBody .share-card{background:transparent;border:1px solid var(--border);
  border-radius:14px;margin-top:16px;padding:15px 15px 17px}
#rpBody .rp-cap + .share-card{margin-top:12px}

/* SHARE IS THE SMALL ONE. Both buttons were the same 52px tall — a share sheet
   is a shortcut for people who already have one, while copying is what every
   player can do — and at equal size the pair was 347px wide inside a 305px
   card, so they wrapped onto two lines and made the box taller than it needed
   to be. Sized down, the two sit on one row with room to spare. */
   The padding is trimmed to what puts the pair on ONE row at 360px, which is
   where a great many Android phones sit — at the button's shipped 34px sides
   they needed 247px against 237px of card and broke onto two lines for the
   sake of ten. Below 360 they still wrap rather than overflow; wrapping is the
   graceful end of this, not the failure. */
#rpBody .share-actions{gap:7px;align-items:center;margin-top:13px}
#rpBody #rpCopy{padding:13px 15px;font-size:14.5px}
#rpBody #rpSheet{padding:7px 9px;font-size:11.5px;font-weight:700;
  border-radius:8px;box-shadow:none;line-height:1.2}
/* The shadow is what gives these buttons their press; removing it from the
   small one means removing its travel too, or it would sink into nothing. */
#rpBody #rpSheet:active{transform:none}
/* Smaller than on the end screen so a ten-question deck round fits on ONE line
   inside a 360px modal — at the card's 22px it wrapped nine-then-one, which
   reads as a mistake rather than as a result. break-all so a longer grid still
   wraps cleanly instead of pushing the modal wider. */
#rpBody .share-grid{text-align:center;word-break:break-all;
  font-size:18px;letter-spacing:1px;line-height:1.45}
#rpBody .share-title,#rpBody .share-sub{text-align:center}
#rpBody .share-actions{justify-content:center}

.modal-x{position:absolute;top:10px;right:12px;background:none;border:0;
  font-size:15px;line-height:1;color:var(--text-muted);cursor:pointer;padding:9px}
.modal-x:hover{color:var(--text)}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:62px}
.pw-eye{position:absolute;right:8px;top:50%;transform:translateY(-50%);
  background:none;border:0;cursor:pointer;font-family:var(--mono);
  font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gold);padding:9px 6px}

/* ---------- the "add an email" nudge ----------
   Quieter than a site banner: this is an invitation to grandfathered accounts,
   not an announcement. Sits under the nav bar. */
.nudge{position:relative;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  background:var(--panel-3);border-left:3px solid var(--gold);
  border-radius:0 8px 8px 0;padding:10px 34px 10px 13px;margin:0 0 14px;
  font-size:13px;color:var(--text-muted);line-height:1.45}
.nudge a{color:var(--gold);cursor:pointer;font-weight:700;white-space:nowrap;
  text-decoration:underline;text-underline-offset:3px}
.nudge-x{position:absolute;right:6px;top:6px;background:none;border:0;
  cursor:pointer;color:var(--text-muted);font-size:12px;padding:7px}
.nudge-x:hover{color:var(--text)}
/* `min-width:0` so a grid tile may shrink, and `overflow-wrap` because one of
   these values is a deck name — "entertainment" is wider than its tile and
   was spilling out of the card. */
.stat{background:var(--sheet);border-radius:12px;padding:13px 15px;min-width:0}
.sv{font:900 21px/1.05 var(--display);color:var(--gold);overflow-wrap:anywhere}
.sl{font:700 8.5px/1.3 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-muted);margin-top:5px}
.prof-section h4,.prof-sec h4{font:700 10px/1 var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--text-muted);margin:18px 0 9px}
.prof-cat{display:flex;justify-content:space-between;font-size:13.5px;padding:6px 0;
  border-bottom:1px solid var(--hair)}
.prof-head{display:flex;align-items:center;gap:14px}
.prof-head h2{margin:0}
.trophy{background:var(--sheet);border-radius:12px;padding:13px;text-align:center}
.trophy .ti{font-size:22px}
.trophy .tn{font:700 10px/1.3 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-soft);margin-top:6px}
.trophy .ts{font-size:11px;color:var(--text-muted);margin-top:3px}
.award-banner{background:rgba(var(--gold-rgb),.12);border:1px solid rgba(var(--gold-rgb),.35);
  border-radius:12px;padding:13px 16px}
.aw-lbl{font-size:9.5px;letter-spacing:.14em;color:var(--gold)}

/* ---------- end of round ---------- */
.end{padding:30px 40px 40px;text-align:center}
.final-lbl,.share-title{font-size:10.5px;letter-spacing:.14em;color:var(--text-muted)}
.final{font:900 68px/1 var(--display);letter-spacing:-.03em;color:var(--gold);
  margin:8px 0;font-variant-numeric:tabular-nums}
.recap-row{display:flex;justify-content:space-between;gap:12px;padding:9px 0;
  border-bottom:1px solid var(--hair);font-size:14px;text-align:left}
.share-card{background:var(--sheet);border-radius:16px;padding:20px}
/* Three to a row: the profile ships these in blocks of three, and a
   two-column track left the last one stranded on its own line. */
.stats-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
.stats-grid+.stats-grid{margin-top:10px}
.rings{display:flex;gap:18px;justify-content:center;flex-wrap:wrap}
.ring-val{font:900 20px/1 var(--display);color:var(--gold)}
.hearts{display:flex;gap:5px}
.hrt .hb{fill:var(--sheet-2)}
.hrt .hg{fill:var(--rust)}

/* ---------- decks ---------- */
/* The picker is a grid of cards with the label, blurb, back link and error
   line spanning it. A <button> sizes to its content, so the card is told to
   fill its track or the rows come out ragged. */
.deck-pick{padding:26px 40px 34px;display:grid;gap:14px;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.deck-pick > .deck-lbl,.deck-pick > .deck-intro,
.deck-pick > .deck-back,.deck-pick > .deck-err,
/* The footer holding the two doors, for exactly the reason the rejoin banner
   below needs it: a direct child of this grid lands in ONE 240px column unless
   told otherwise, so "archives" was pushed to the right of a narrow track
   rather than to the right of the screen — 920px short of the edge that "back
   to modes" sits 40px from. Spanning every column puts the two at opposite
   ends of the same line, each inset by the picker's own padding. */
.deck-pick > .deck-foot,
/* The rejoin banner is a full-width notice, not a card in the row. Inserted
   from JS as a direct child, it was landing in one 280px column and being
   squeezed to a third of its height. */
.deck-pick > .dx-rejoin{grid-column:1/-1}

/* THE DUELS PICKER IS A GRID LIKE EVERY OTHER PICKER.
   #duelDecks is a mount point, not a layout box -- it exists so the fetch can
   write the deck list somewhere after the screen is already on. But a wrapper
   is one grid ITEM, so all seven duel decks were being laid out inside a
   single 280px column: an 847px-tall stack down the left of a 1240px screen
   with three empty columns beside it, while the unlimited picker, whose cards
   are direct children, filled its row and stood 323px tall.

   display:contents removes the wrapper's box and promotes its children to
   items of .deck-pick, so the duel decks now flow through exactly the same
   auto-fit columns as every other picker -- at every width, without this
   file having to name a column count twice. The div stays in the DOM, so
   the JS that fills it and queries it is untouched. */
#duelDecks{display:contents}
.deck-lbl{font-size:10.5px;letter-spacing:.14em;color:var(--text-muted);margin:0;
  display:block;text-align:center}
.deck-intro{text-align:center;color:var(--text-soft);font-size:14.5px;line-height:1.55;
  margin:0 auto;max-width:60ch}
/* BIGGER BOXES, NOW THAT THE SUBTITLE HAS GONE. A card that used to hold a
   name, a sentence and a call to action holds a name and a call to action, and
   at 20px of padding it collapsed to a thin strip — a list of links rather
   than a rack of things to choose between. The floor gives it back the
   presence it had, and the name is centred in it for the same reason. */
.deck-card{background:var(--sheet);border:0;border-radius:16px;padding:26px 22px 20px;
  text-align:center;cursor:pointer;color:var(--text);display:flex;flex-direction:column;
  gap:10px;box-shadow:0 5px 0 rgba(0,0,0,.3);font-family:var(--font);
  width:100%;align-items:center;justify-content:center;min-height:132px;
  transition:transform .1s,box-shadow .1s}
.deck-card:hover{transform:translateY(-2px);box-shadow:0 7px 0 rgba(0,0,0,.3)}
.deck-card:active{transform:translateY(2px);box-shadow:0 2px 0 rgba(0,0,0,.3)}
.deck-card::before{display:none}
.deck-card:disabled{opacity:.4;cursor:default;transform:none}
/* THE CATEGORY IS THE CARD. Up from 19px, which was the size it had when a
   sentence sat underneath explaining it — that sentence is gone again (see the
   card function in nav.js), so this is the only thing on the box a player
   reads. `margin:auto 0 0` lets it sit in the middle with the call to action
   held at the foot. */
.deck-name{font:900 clamp(21px,2.4vw,27px)/1.1 var(--display);letter-spacing:-.01em;
  margin:auto 0 0}
/* Kept, unused by the picker: CAT_TREE still carries the copy and a screen
   that wants it back is one line rather than a rewrite of the catalogue. */
.deck-desc{font-size:13px;line-height:1.5;color:var(--text-soft)}
.deck-go{font-size:10px;letter-spacing:.14em;color:var(--gold);margin-top:auto}
.deck-back{display:inline-block;margin-top:16px;color:var(--gold);cursor:pointer;
  font-weight:700;font-size:13.5px}
/* The two doors sit on one line, one at each end, and wrap rather than collide
   on a narrow screen. */
.deck-foot{display:flex;justify-content:space-between;align-items:center;
  gap:16px;flex-wrap:wrap}
.deck-back-r{margin-left:auto}
.deck-err{color:var(--red);font-size:13.5px;margin-top:10px}

/* ---------- avatars, levels ---------- */
.av{border-radius:50%;background:#254047;display:flex;align-items:center;
  justify-content:center;font-family:var(--display);font-weight:900;color:var(--text);
  overflow:hidden;position:relative;flex:none}
.av.xs{width:22px;height:22px;font-size:9px}
.av.sm{width:28px;height:28px;font-size:11px}
.av.md{width:38px;height:38px;font-size:14px}
.av.lg{width:54px;height:54px;font-size:19px}
.av.xl{width:76px;height:76px;font-size:26px}
.av[data-rank]{box-shadow:0 0 0 2px var(--gold)}
.av[data-rank="purple"]{box-shadow:0 0 0 2px #A97BE0}
.av[data-rank="dark green"]{box-shadow:0 0 0 2px var(--m-daily)}
.av[data-rank="black"]{box-shadow:0 0 0 2px #0B0B0B}
.av[data-rank="rainbow"]{box-shadow:0 0 0 2px var(--rust)}
/* An emoji IS the avatar now, so it is sized to fill the disc. The font sizes
   on .av above are for initials sitting behind a photograph -- 9px inside a
   22px circle -- which left a speck in the middle of an empty ring once the
   photographs went away. About 60% of the diameter reads as an icon.
   line-height:1 keeps the glyph centred; several of these emoji carry a
   variation selector and sit low on their own baseline otherwise. */
/* Flags are pictures again, so the two layers they need come back. Only
   flags carry an <img>; the other three groups are the emoji span alone. */
.av .av-fb{position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;font-size:15px}
.av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .2s}
.av img.on{opacity:1}
.av.emoji{line-height:1}
.av.xs.emoji{font-size:13px}
.av.sm.emoji{font-size:17px}
.av.md.emoji{font-size:23px}
.av.lg.emoji{font-size:32px}
.av.xl.emoji{font-size:45px}
.av-pick{margin-top:14px}
.av-group{margin-bottom:14px}
.av-glabel{font:700 9.5px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--text-muted);margin-bottom:8px}
.av-grid{display:flex;flex-wrap:wrap;gap:8px}
.av-btn{background:var(--sheet);border:0;border-radius:10px;padding:7px;
  cursor:pointer;font-size:19px;line-height:1}
.av-btn:hover{background:var(--sheet-2)}
.av-btn.on{background:var(--gold)}

.lvl-chip{display:inline-flex;align-items:center;
  font:700 10px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  background:var(--sheet-2);border-radius:999px;padding:5px 10px;color:var(--gold);
  /* Its own height, so a container with a tight line-height cannot squeeze the
     pill into the text it sits next to. */
  min-height:20px;white-space:nowrap}
.lvl-chip[data-rank="purple"]{color:#C4A2F0}
.lvl-chip[data-rank="dark green"]{color:#6FD3A4}
.lvl-chip[data-rank="black"]{color:#CBD9D6}
.lvl-chip[data-rank="rainbow"]{color:var(--rust-text)}
.lvl-ring{display:inline-flex;align-items:center;justify-content:center;
  position:relative;width:30px;height:30px}
.lvl-ring svg{width:30px;height:30px;transform:rotate(-90deg)}
.lvl-ring .trk{fill:none;stroke:var(--sheet-2);stroke-width:3}
.lvl-ring .arc{fill:none;stroke:var(--gold);stroke-width:3;stroke-linecap:round}
.lvl-ring .n{position:absolute;font:900 11px/1 var(--display);color:var(--on-accent)}
.lvl-ring.big{width:64px;height:64px}
.lvl-ring.big svg{width:64px;height:64px}
.lvl-ring.big .trk,.lvl-ring.big .arc{stroke-width:5}
.lvl-ring.big .n{font-size:22px}
.lvl-wrap{background:var(--sheet);border-radius:14px;padding:15px 17px;margin-top:14px}
.lvl-top{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
/* THE RANK CHIP SITS BESIDE THE LEVEL, not on top of it. This was a plain
   inline span holding an inline chip with 5px of vertical padding, inside a
   line box only 15px tall (line-height:1) — so the chip's rounded background
   stood ~20px and spilled over the text above and below it. Padding on an
   inline element grows the box it paints without growing the line it sits on.

   A flex row fixes the cause rather than the symptom: the chip becomes a flex
   item, its full height is part of the row, and the gap gives it real space
   instead of the word-space it was borrowing. Wraps on a narrow profile rather
   than pushing the points off the end. */
.lvl-name{font:900 15px/1 var(--display);color:var(--text);
  display:inline-flex;align-items:center;gap:9px;flex-wrap:wrap;
  row-gap:6px}
.lvl-pts{font:700 10.5px/1 var(--mono);letter-spacing:.1em;color:var(--text-muted)}
.lvl-track{height:8px;background:var(--sheet-2);border-radius:99px;overflow:hidden;
  margin:11px 0 7px}
.lvl-fill{height:100%;border-radius:99px;background:var(--gold)}
.lvl-fill[data-rank="purple"]{background:#A97BE0}
.lvl-fill[data-rank="dark green"]{background:var(--mint)}
.lvl-fill[data-rank="black"]{background:#4A5A5C}
.lvl-fill[data-rank="rainbow"]{background:linear-gradient(90deg,var(--rust),var(--gold),var(--mint))}
.lvl-foot{font-size:12px;color:var(--text-muted)}

.lvlup-back{position:fixed;inset:0;background:rgba(6,12,14,.78);display:none;
  align-items:center;justify-content:center;z-index:120;padding:20px}
.lvlup-back.show{display:flex}
.lvlup{background:var(--overlay);border-radius:20px;padding:30px;text-align:center;
  max-width:400px;width:100%;box-shadow:0 22px 60px rgba(0,0,0,.65)}
/* A PILL, not a circle. This held the rank NAME in a fixed 78px circle at
   30px — and every one of the five overflows that, not just the short one:
   "Newbie" needs about 110px and "Trivia Truthseeker" nearly 300. A shape
   with a fixed width cannot hold a label whose length is data.
   Hugging the text means it fits by construction, at any length, in any
   language, and it matches .lvl-chip above, which solved the same problem
   for the profile. `max-width` keeps the longest name inside the card;
   `text-wrap:balance` splits it evenly if it ever does need two lines. */
.lvlup-badge{display:inline-flex;align-items:center;justify-content:center;
  max-width:100%;margin:0 0 18px;padding:12px 24px;border-radius:999px;
  background:var(--gold);color:var(--ink-2);
  font:900 18px/1.25 var(--display);letter-spacing:.005em;
  text-align:center;text-wrap:balance}
.lvlup-badge[data-rank="purple"]{background:#A97BE0;color:var(--on-accent)}
.lvlup-badge[data-rank="dark green"]{background:var(--m-daily);color:var(--on-accent)}
.lvlup-badge[data-rank="black"]{background:#111;color:var(--on-accent)}
.lvlup-badge[data-rank="rainbow"]{background:linear-gradient(135deg,var(--rust),var(--gold),var(--mint));color:var(--on-accent)}
.lvlup-n{font:900 44px/1 var(--display);color:var(--gold);margin:6px 0}
.lvlup-t{font:900 21px/1.2 var(--display);color:var(--text)}
.lvlup-sub{font-size:14px;color:var(--text-soft);margin-top:9px;line-height:1.5}
.lvlup-go{margin-top:20px}

