/*! Developer notes for this file: docs/frontend-notes.md */
* { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin:0; background:#0b0b0d; font-family:'Inter',system-ui,sans-serif;
       color:rgba(255,255,255,.92); }
a { color:#b98af7; text-decoration:none; }
a:hover { color:#cdaaff; }
input::placeholder { color:rgba(255,255,255,.32); }
input { color-scheme:dark; }
.scr { scrollbar-width:none; }
.scr::-webkit-scrollbar { display:none; }
.vh { position:absolute; width:1px; height:1px; margin:-1px; padding:0;
      overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

.skip { position:absolute; left:-9999px; top:0; background:#141417; color:#fff;
        padding:10px 16px; border-radius:0 0 8px 0; z-index:60; }
.skip:focus { left:0; }

/* --- site nav --- */
/* Lives in static/nav.css, which the home page loads as well. */

/* --- page shell --- */
.page { max-width:1200px; margin:0 auto; padding:34px 28px 60px;
        display:flex; flex-direction:column; gap:34px; }

/* --- masthead --- */
.masthead { position:relative; padding-bottom:20px;
            border-bottom:1px solid rgba(255,255,255,.1); }
/* Room for the artwork behind the heading. Only when there is artwork: a page
   whose snapshot has not run yet keeps the old compact masthead instead of a
   tall empty box. */
.masthead:has(.mast-art) { min-height:340px; }

/* --- masthead artwork --- */
/* The backdrop sits in the corner the text does not use. It reaches past the
   page gutter on the right and up into the top padding, so it reads as part of
   the page rather than as a picture dropped into a box. */
/* right:calc(50% - 50vw) is the page's own offset from the window edge, so the
   artwork runs to the edge of the screen on a wide monitor instead of stopping
   at the 1200px page and reading as a rectangle parked in the margin. */
.mast-art { position:absolute; top:-34px; right:calc(50% - 50vw); bottom:-1px;
            width:clamp(420px,52vw,760px); overflow:hidden; z-index:0;
            pointer-events:none;
            -webkit-mask-image:linear-gradient(180deg,#000 68%,transparent 100%);
            mask-image:linear-gradient(180deg,#000 68%,transparent 100%); }
.mast-art-grid { position:absolute; top:50%; left:50%; translate:-50% -50%;
                 display:grid; grid-template-columns:repeat(2,238px); gap:13px;
                 transform:rotate(-9deg) scale(1.12); opacity:.58; }
.mast-art img { display:block; width:100%; height:auto; aspect-ratio:460/215;
                object-fit:cover; border-radius:9px;
                border:1px solid rgba(255,255,255,.07); }
/* One operator-chosen picture instead of the tiles: it fills the same corner
   and is cropped from the centre, which is where a header image puts its
   subject. */
.mast-art.one img { position:absolute; inset:0; width:100%; height:100%;
                    aspect-ratio:auto; object-fit:cover; object-position:center;
                    border:0; border-radius:0; opacity:.55; }
/* The gradient is what keeps the H1 legible: it is opaque page colour under
   the text and clears by the right edge. The outlined heading has no fill of
   its own, so anything busy behind it has to be put out first. */
.mast-art::after { content:""; position:absolute; inset:0;
                   background:linear-gradient(97deg,#0b0b0d 24%,
                              rgba(11,11,13,.88) 48%,rgba(11,11,13,.55) 100%); }
/* The stat tiles sit over the lightest part of the artwork. They carry an
   opaque panel of their own instead of a text-shadow, so the art can be as
   busy as it likes behind them. */
/* The masthead's own content stacks above the artwork. Listed one by one
   rather than with a child selector, because .mast-tools turns into a sticky
   bar on a phone and a blanket "position:relative" here would quietly
   outrank that. */
.masthead h1, .mast-foot, .mast-tools, .crumb { position:relative; z-index:1; }
/* --- masthead tools: tag search + currency, accented so they read as controls
       rather than decoration --- */
/* z-index above the H1, not merely above the artwork. z-index here makes
   .mast-tools a stacking context, which traps the tag suggestions inside it
   however high their own z-index climbs; sharing z-index:1 with the H1 meant
   the H1 won on document order and painted over the open dropdown. The H1 is
   transparent letters with a stroke, so the dropdown showed through them. */
.mast-tools { display:flex; justify-content:flex-end; align-items:center;
              gap:10px; margin-bottom:14px; flex-wrap:wrap; z-index:3; }
.tagfind { display:flex; }
.tagfind form, .curpick { display:flex; align-items:center; gap:8px;
                          background:#141417; border:1px solid rgba(185,138,247,.42);
                          border-radius:10px; padding:7px 12px; position:relative; }
.tagfind form:focus-within, .curpick:focus-within { border-color:#b98af7; }
.tagfind label, .curpick label { font:600 10px 'Inter',sans-serif; letter-spacing:.08em;
                 text-transform:uppercase; color:#b98af7; }
.tagfind input { width:150px; background:none; border:none;
                 font:600 13px 'JetBrains Mono',monospace; color:#fff; outline:none; }
.curpick select { background:none; border:none; outline:none; cursor:pointer;
                  font:600 13px 'JetBrains Mono',monospace; color:#fff;
                  padding-right:2px; }
.curpick select option { background:#141417; color:#fff; }
.curpick select:disabled { opacity:.5; cursor:progress; }
.tagfind ul { position:absolute; top:calc(100% + 6px); right:0; left:0; margin:0;
              padding:6px; list-style:none; background:#141417;
              border:1px solid rgba(255,255,255,.14); border-radius:10px;
              box-shadow:0 14px 34px rgba(0,0,0,.55); z-index:25; max-height:260px;
              overflow-y:auto; }
.tagfind li a { display:block; padding:7px 10px; border-radius:7px;
                font:500 13px 'Inter',sans-serif; color:rgba(255,255,255,.75); }
.tagfind li a:hover, .tagfind li a:focus { background:rgba(255,255,255,.07); color:#fff; }
.tagfind .none { padding:7px 10px; font:400 12.5px 'Inter',sans-serif;
                 color:rgba(255,255,255,.4); }

/* Breadcrumb: top left, on the same line as the tools on the right. Placed
   absolutely rather than wrapped with the tools in one row, because
   .mast-tools turns sticky on a phone, and a sticky element only sticks
   inside its parent: a one-line wrapper would hold it in place. */
.crumb { position:absolute; top:0; left:0; height:36px; display:flex;
         align-items:center; gap:6px; font:600 12px 'Inter',sans-serif;
         color:rgba(255,255,255,.55); z-index:2; }
.crumb a { color:rgba(255,255,255,.55); }
.crumb a:hover { color:#fff; }
.crumb [aria-current] { color:rgba(255,255,255,.92); }

/* Sized to its length: a short tag gets the full 92px, an operator's long
   H1 ("Best roguelike deckbuilder games on Steam") steps down and wraps
   inside the same width as the intro, so the tiles stay beside it. */
.masthead h1 { margin:0; font:700 clamp(44px,7.5vw,92px)/.86 'Space Grotesk',sans-serif;
               letter-spacing:-.035em; color:transparent;
               -webkit-text-stroke:2px rgba(255,255,255,.68); text-wrap:balance;
               overflow-wrap:break-word; max-width:620px; }
.masthead h1.h1-long { font-size:clamp(40px,5.4vw,64px); line-height:.95; }
.masthead h1.h1-xlong { font-size:clamp(36px,4.4vw,52px); line-height:1;
                        -webkit-text-stroke-width:1.6px; }
.mast-foot { display:flex; align-items:flex-end; justify-content:space-between;
             gap:32px; flex-wrap:wrap; margin-top:18px; }
.mast-text { flex:1 1 520px; min-width:0; display:flex; flex-direction:column; gap:16px; }
/* Inside the column the old flex-basis would be a height (see below). */
.mast-foot .mast-text .intro { flex:none; max-width:620px; }
/* flex-basis is the main axis, so this 480px is a width only while .mast-foot
   is a row. The narrow layout turns it into a column, where the same 480px
   becomes a height and leaves a tall empty box under a short intro; the
   narrow-screen block resets it. */
.mast-foot .intro { flex:1 1 480px; max-width:660px; }
.mast-foot .intro p { margin:0 0 11px; font:400 14.5px/1.8 'Inter',sans-serif;
                      color:rgba(255,255,255,.52); text-wrap:pretty; }
.mast-foot .intro p:last-child { margin-bottom:0; }
/* --- masthead stat tiles --- */
.tiles { flex:1 1 460px; max-width:560px; display:grid;
         grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
.tile { background:#141417; border:1px solid rgba(255,255,255,.08); border-radius:14px;
        padding:14px 16px; display:flex; flex-direction:column; gap:8px; min-width:0;
        color:inherit; }
.tile b, .num { font:700 28px/1 'Space Grotesk',sans-serif; color:#fff;
                font-variant-numeric:tabular-nums; }
.ovl { font:600 10px 'Inter',sans-serif; letter-spacing:.08em; text-transform:uppercase;
       color:rgba(255,255,255,.4); }
a.tile-trend { border-color:oklch(78% 0.13 300 / .55); }
a.tile-trend:hover { border-color:#b98af7; color:inherit; }
.tile-v { display:flex; align-items:baseline; gap:10px; }
.tile-v .up, .tile-v .down { font:600 12px 'Inter',sans-serif; }
.spark { display:block; width:100%; height:24px; overflow:visible; }
.spark polyline { fill:none; stroke:oklch(78% 0.13 300); stroke-width:2;
                  stroke-linecap:round; stroke-linejoin:round;
                  vector-effect:non-scaling-stroke; }
.up { color:oklch(88% 0.13 150); }
.down { color:oklch(85% 0.13 25); }

/* --- jump bar --- */
/* Sized so all ten chips fit on one line in the 1144px desktop column
   (about 1100px measured); phones scroll it instead. */
.jump { display:flex; gap:6px; overflow-x:auto; margin-top:-14px; }
.jump a { font:600 13px 'Inter',sans-serif; color:rgba(255,255,255,.62); padding:8px 11px;
          border-radius:20px; border:1px solid rgba(255,255,255,.14);
          background:rgba(255,255,255,.05); white-space:nowrap; }
.jump a:hover { color:#fff; background:rgba(255,255,255,.07); }
.jump a.new { color:oklch(88% 0.09 300); background:oklch(78% 0.13 300 / .16);
              border-color:oklch(78% 0.13 300 / .55); }
.jump a:focus-visible, .tile-trend:focus-visible, .cal-game:focus-visible,
.pt-movers a:focus-visible { outline:2px solid #b98af7; outline-offset:2px; }
/* Anchored sections land below the sticky nav, not under it. */
.page > section[id], .tw-sub[id] { scroll-margin-top:calc(var(--nav-h,0px) + 16px); }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior:smooth; } }

.page > .sub { margin:0; font:400 12.5px 'Inter',sans-serif;
               color:rgba(255,255,255,.32); }

/* --- rows --- */
.row { display:flex; flex-direction:column; gap:18px; }
.row-head { display:flex; align-items:center; gap:14px; }
.row-head .kicker { font:600 11px 'Inter',sans-serif; letter-spacing:.14em;
                    text-transform:uppercase; color:oklch(80% 0.13 85);
                    flex:none; }
.row-head h2 { margin:0; font:700 22px 'Space Grotesk',sans-serif;
               color:rgba(255,255,255,.92); }
.row-head .rule { flex:1; height:1px; background:rgba(255,255,255,.1); }
.row-head .sub { font:400 12px 'Inter',sans-serif; color:rgba(255,255,255,.32); }
/* The sort note and the row's average price sit together at the right end of
   the header. The price is a pill in the accent, the same border and label
   colour as the currency picker, so it reads as tied to that choice. */
.row-meta { display:flex; align-items:center; gap:12px; flex:none; }
.row-price { display:inline-flex; align-items:baseline; gap:7px;
             padding:4px 10px; border:1px solid rgba(185,138,247,.42);
             border-radius:999px; background:rgba(185,138,247,.08);
             white-space:nowrap; }
.row-price span { font:600 10px 'Inter',sans-serif; letter-spacing:.08em;
                  text-transform:uppercase; color:#b98af7; }
.row-price b { font:700 13px 'JetBrains Mono',monospace; color:oklch(88% 0.09 300); }
.strip { display:flex; gap:22px; overflow-x:auto; overscroll-behavior-x:contain;
         padding:0 0 4px; margin:0; list-style:none; }

/* --- card --- */
.gc { flex:0 0 214px; display:flex; flex-direction:column; gap:11px; }
/* A row holds ten cards and shows four and a half. The half card cut by the
   right edge is the signal that the row goes on, and it needs no explanation
   the way a counter or a label would. The width is a share of the strip, so
   the cut lands mid-card at every desktop width; below 200px a card would be
   too cramped, and the strip just shows fewer. Desktop only: the phone rules
   below keep their own fixed width and swipe. */
@media (min-width: 641px) {
  .gc { flex:0 0 calc((100% - 88px) / 4.5); min-width:200px;
        scroll-snap-align:start; }
  .strip { scroll-snap-type:x proximity; }
  /* The edge fade says the same thing as the half card, and stays after the
     first scroll, when the cut can land between two cards. The classes are set
     by TAG_STRIP_JS from the scroll position, so a row that fits, or one
     scrolled to its end, has no fade on that side. */
  .row.fade-r .strip { -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 90px), transparent);
                       mask-image:linear-gradient(to right, #000 calc(100% - 90px), transparent); }
  .row.fade-l .strip { -webkit-mask-image:linear-gradient(to right, transparent, #000 90px);
                       mask-image:linear-gradient(to right, transparent, #000 90px); }
  .row.fade-l.fade-r .strip {
    -webkit-mask-image:linear-gradient(to right, transparent, #000 90px, #000 calc(100% - 90px), transparent);
    mask-image:linear-gradient(to right, transparent, #000 90px, #000 calc(100% - 90px), transparent); }
}
/* Arrow buttons for a mouse, which cannot scroll sideways without shift. They
   ship hidden and TAG_STRIP_JS shows them only when the row overflows, so a
   page without scripts, or a row that fits, never shows dead controls. */
/* Mouse drag (TAG_STRIP_JS). The grab cursor only where there is something
   to drag to, and only for a fine pointer that hovers, which is what a mouse
   is. Snapping is off mid-drag or the strip would jump under the cursor; it
   comes back on release and settles the row on a card edge. */
@media (min-width: 641px) and (hover: hover) and (pointer: fine) {
  .row.can-drag .strip { cursor:grab; }
  .strip.dragging { cursor:grabbing; scroll-snap-type:none; user-select:none; }
}
.row-nav { display:flex; gap:6px; }
.row-nav[hidden] { display:none; }
.row-nav button { width:30px; height:30px; border-radius:50%; padding:0;
                  display:grid; place-items:center; cursor:pointer;
                  background:transparent; color:rgba(255,255,255,.75);
                  border:1px solid rgba(255,255,255,.18); }
.row-nav button:hover:not(:disabled) { border-color:#b98af7; color:#fff;
                                       background:rgba(185,138,247,.12); }
.row-nav button:disabled { opacity:.3; cursor:default; }
.row-nav svg { width:12px; height:12px; fill:none; stroke:currentColor;
               stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; }
.gc-top { display:flex; align-items:flex-start; gap:8px; }
.gc-rank { font:700 46px/1 'Space Grotesk',sans-serif; color:transparent;
           -webkit-text-stroke:1.5px rgba(255,255,255,.3); flex:none;
           margin-top:-4px; }
.gc-shot { flex:1; min-width:0; aspect-ratio:460/215; border-radius:8px;
           overflow:hidden; position:relative; background:#17171c;
           border:1px solid rgba(255,255,255,.08); display:block; }
.gc-shot img { width:100%; height:100%; object-fit:cover; display:block; }
.gc-badge { position:absolute; top:6px; left:6px; color:#14141a;
            font:700 9px 'Inter',sans-serif; letter-spacing:.03em;
            padding:3px 7px; border-radius:5px; }
.gc-badge.upcoming { background:oklch(78% 0.13 300); }
.gc-badge.gem { background:oklch(80% 0.13 85); }
.gc-badge.new { background:oklch(82% 0.15 150); }
.gc-badge.trending { background:oklch(76% 0.15 40); }
.gc-badge.oneoh { background:oklch(72% 0.17 150); }
.gc-name { font:700 15.5px/1.25 'Space Grotesk',sans-serif; color:#fff; }
.gc-name:hover { color:#fff; text-decoration:underline; }
/* The Steam mark and arrow ride with the last word rather than being pushed to
   the far edge: a title that wraps to two lines would otherwise leave them
   stranded beside the first line. inline-flex keeps the pair together so they
   never break apart across a line end. */
.gc-cta { display:inline-flex; align-items:center; gap:4px; margin-left:6px;
          vertical-align:-2px; line-height:0; white-space:nowrap; }
.gc-steam { width:14px; height:14px; fill:rgba(255,255,255,.75); }
.gc-arrow { width:10px; height:10px; fill:none; stroke:rgba(255,255,255,.6);
            stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.gc-name:hover .gc-steam { fill:#fff; }
.gc-name:hover .gc-arrow { stroke:#fff; }
.gc-stats { display:flex; flex-direction:column; gap:4px;
            font:400 11.5px/1.5 'JetBrains Mono',monospace;
            color:rgba(255,255,255,.45); border-left:2px solid rgba(255,255,255,.12);
            padding-left:9px; }
.gc-stats .rev { color:oklch(85% 0.14 150); }
.gc-tags { display:flex; flex-wrap:wrap; gap:5px; margin:0; padding:0; list-style:none; }
.gc-tags li { border:1px solid rgba(255,255,255,.14); color:rgba(255,255,255,.55);
              border-radius:20px; padding:2px 9px; font:600 10.5px 'Inter',sans-serif; }

/* --- tag combos --- */
/* The "Most common {tag} tag combinations" block (tagrender._combos). It
   reuses .row-head for its header; everything below is its own. */
.combos { display:flex; flex-direction:column; gap:18px; }
/* .combos .row-head reuses the existing .row-head / .kicker / h2 / .rule / .sub rules */
.combos-intro { margin:-4px 0 0; max-width:760px; font:400 14px/1.8 'Inter',sans-serif;
                color:rgba(255,255,255,.55); text-wrap:pretty; }
.combos-intro p { margin:0 0 10px; }
.combos-intro p:last-child { margin-bottom:0; }

.combo-panel { position:relative; overflow:hidden; display:grid;
               grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr));
               gap:12px 40px; align-items:center;
               border:1px solid rgba(255,255,255,.12); border-radius:14px; padding:22px 26px; }

/* background art: one <img> per trio, only the .on one is visible */
.combo-bg { position:absolute; inset:0; z-index:0; pointer-events:none; }
.combo-bg img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
                filter:saturate(1.1); opacity:0; transform:scale(1);
                transition:opacity .9s ease, transform 4s cubic-bezier(.2,.7,.2,1); }
.combo-bg img.on { opacity:.42; transform:scale(1.08); }
/* darker behind the list, lighter behind the graph. Graph sits on the right,
   so the list side (left) is darkest. */
.combo-bg::after { content:""; position:absolute; inset:0;
  background:linear-gradient(90deg, rgba(11,11,13,.94) 0%, rgba(11,11,13,.86) 42%,
                             rgba(11,11,13,.55) 75%, rgba(11,11,13,.7) 100%); }

.combo-graph { position:relative; z-index:1; order:2; display:flex; flex-direction:column;
               align-items:center; gap:14px; }
/* 520 = the 440 drawing plus the label room either side (CG_PAD). */
.combo-graph svg { width:100%; max-width:520px; height:auto; display:block; overflow:visible; }

/* svg parts */
.cg-ring  { fill:none; stroke:rgba(255,255,255,.07); stroke-dasharray:2 5; }
.cg-spoke { stroke:rgba(255,255,255,.06); transition:stroke .3s; }
.cg-spoke.on { stroke:transparent; }
.cg-chord { stroke:rgba(255,255,255,.13); stroke-linecap:round; transition:stroke .3s; }
.cg-chord.on { stroke:transparent; }
.cg-tri { fill:rgba(185,138,247,.13); stroke:#b98af7; stroke-width:1.6; stroke-linejoin:round;
          stroke-dasharray:900; opacity:0; }
.cg-tri.on { opacity:1;
  animation:cgDraw .9s cubic-bezier(.3,.7,.2,1) both, cgFade .35s ease-out both; }
.cg-node { cursor:pointer; }
.cg-node circle.dot { fill:#141417; stroke:rgba(255,255,255,.32); stroke-width:1.5;
                      transition:fill .3s, stroke .3s; }
.cg-node text { font:600 12.5px 'Inter',sans-serif; fill:rgba(255,255,255,.5); transition:fill .3s; }
.cg-node.on circle.dot { fill:#b98af7; stroke:#b98af7; }
.cg-node.on text { fill:#fff; }
.cg-node circle.pulse { fill:#b98af7; r:0; opacity:0; }
.cg-node.on circle.pulse { animation:cgPulse 1.4s ease-out .3s both; }
.cg-hub  { fill:#141417; stroke:rgba(185,138,247,.55); stroke-width:1.5; }
.cg-hub-label { font:700 15px 'Space Grotesk',sans-serif; fill:#fff; }
.cg-count { font:700 13px 'JetBrains Mono',monospace; fill:oklch(88% 0.09 300); }
.cg-count.swap { animation:cgFade .5s ease-out both; }
@keyframes cgDraw  { from { stroke-dashoffset:900; } to { stroke-dashoffset:0; } }
@keyframes cgFade  { from { opacity:0; } to { opacity:1; } }
@keyframes cgPulse { 0% { r:0; opacity:.55; } 100% { r:26px; opacity:0; } }

/* "Most played in this combo" card under the graph */
.combo-spot { display:flex; align-items:center; gap:12px; width:100%; max-width:360px;
              padding:8px 14px 8px 8px; border-radius:12px; background:rgba(20,20,23,.78);
              border:1px solid rgba(185,138,247,.35); color:inherit;
              -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px); }
.combo-spot:hover { border-color:#b98af7; color:inherit; }
.combo-spot img { width:92px; aspect-ratio:460/215; object-fit:cover; border-radius:7px;
                  border:1px solid rgba(255,255,255,.08); flex:none; }
.combo-spot > span { display:flex; flex-direction:column; gap:3px; min-width:0; }
.combo-spot .k { font:600 10px 'Inter',sans-serif; letter-spacing:.1em; text-transform:uppercase;
                 color:oklch(80% 0.13 85); }
.combo-spot .n { font:700 14.5px/1.25 'Space Grotesk',sans-serif; color:#fff;
                 white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.combo-spot .t { font:400 11px 'JetBrains Mono',monospace; color:rgba(255,255,255,.45); }
/* .combo-spot .n carries the same .gc-cta (Steam mark + arrow) the cards use, at 13px/9px */
.combo-spot .gc-steam { width:13px; height:13px; }
.combo-spot .gc-arrow { width:9px; height:9px; }

/* ranked list */
.combo-list { position:relative; z-index:1; margin:0; padding:0; list-style:none;
              display:flex; flex-direction:column; gap:6px; }
.combo-list a { display:grid; grid-template-columns:30px minmax(0,1fr) auto; align-items:center;
                gap:6px 12px; padding:10px 12px; border-radius:10px;
                border:1px solid transparent; background:transparent; color:inherit;
                transition:background .25s, border-color .25s; }
.combo-list a:hover { color:inherit; }
.combo-list .rk { font:700 26px/1 'Space Grotesk',sans-serif; color:transparent;
                  -webkit-text-stroke:1.2px rgba(255,255,255,.3); transition:all .25s; }
.combo-list .trio { display:flex; align-items:center; flex-wrap:wrap; gap:6px; min-width:0; }
.combo-list .base, .combo-list .plus { font:600 12px 'JetBrains Mono',monospace; }
.combo-list .base { color:rgba(255,255,255,.4); }
.combo-list .plus { color:rgba(255,255,255,.28); }
.combo-list .chip { border:1px solid rgba(255,255,255,.14); color:rgba(255,255,255,.7);
                    border-radius:20px; padding:3px 10px; font:600 12px 'Inter',sans-serif;
                    white-space:nowrap; transition:all .25s; }
.combo-list .fig { display:flex; flex-direction:column; align-items:flex-end; gap:2px; }
.combo-list .fig b { font:700 13px 'JetBrains Mono',monospace; color:oklch(88% 0.09 300); }
.combo-list .fig span { font:400 11px 'JetBrains Mono',monospace; color:rgba(255,255,255,.4);
                        white-space:nowrap; }
.combo-list .bar { grid-column:2 / 4; height:3px; border-radius:2px;
                   background:rgba(255,255,255,.07); overflow:hidden; }
.combo-list .bar i { display:block; height:100%; border-radius:2px;
                     background:rgba(255,255,255,.22); transition:background .25s; }
.combo-list li.on a { background:rgba(20,20,23,.72); border-color:rgba(185,138,247,.42); }
.combo-list li.on .rk { -webkit-text-stroke-color:#b98af7; }
.combo-list li.on .chip { border-color:rgba(185,138,247,.55); color:oklch(88% 0.09 300);
                          background:rgba(185,138,247,.1); }
.combo-list li.on .bar i { background:#b98af7; }
/* Phone: the first tap on a row arms it (TAG_COMBO_JS). It takes the accent
   and grows a line saying a second tap opens the recommender with that mix. */
.combo-list li.armed a { background:rgba(185,138,247,.2); border-color:#b98af7;
                         box-shadow:0 0 0 3px rgba(185,138,247,.14); }
.combo-list li.armed .rk { -webkit-text-stroke-color:#fff; }
.combo-hint { grid-column:1 / -1; display:flex; align-items:center;
              justify-content:space-between; gap:12px; margin-top:4px; padding-top:9px;
              border-top:1px solid rgba(185,138,247,.35);
              font:600 13.5px/1.35 'Space Grotesk',sans-serif; color:#fff;
              animation:cgHint .3s ease-out both; }
.combo-hint svg { width:15px; height:15px; flex:none; fill:none; stroke:#b98af7;
                  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
@keyframes cgHint { from { opacity:0; transform:translateY(-4px); } to { opacity:1; transform:none; } }
/* Phone only: a plain way from the combos to the recommender, beside the
   two-tap rows above. Desktop rows are links themselves. */
.combo-more { display:none; }
/* A long page tag in the hub drops a size to stay inside the ring. */
.cg-hub-label.long { font-size:12px; }
/* Hidden while the active trio has no released game to feature. */
.combo-spot[hidden] { display:none; }

/* --- redesign blocks: player trend, this week, tag in numbers --- */
/* min-width:0 throughout: a flex item is as wide as its content by default,
   and the 900px release calendar would otherwise widen the whole page on a
   phone instead of scrolling inside its own box. */
.block, .tw-sub, .cal-scroll { min-width:0; }
.block { display:flex; flex-direction:column; gap:18px; }
.panel { background:#141417; border:1px solid rgba(255,255,255,.08); border-radius:14px; }
.block .sub, .figs .sub { font:400 12px 'Inter',sans-serif; color:rgba(255,255,255,.55); }
.noimg { display:block; aspect-ratio:460/215; border-radius:6px; background:#17171c; }

/* player trend */
.pt-panel { padding:24px 26px; display:grid;
            grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr)); gap:28px 40px; }
.pt-main { grid-column:span 2; min-width:0; display:flex; flex-direction:column; gap:14px; }
.pt-figs { display:flex; gap:28px; flex-wrap:wrap; }
.pt-figs > div { display:flex; flex-direction:column; gap:6px; }
.pt-v { display:flex; align-items:baseline; gap:10px; }
.pt-legend { display:flex; gap:18px; align-items:center; flex-wrap:wrap;
             font:600 12px 'Inter',sans-serif; color:rgba(255,255,255,.62); }
.pt-legend span { display:inline-flex; align-items:center; gap:7px; }
.pt-legend i { width:18px; height:0; border-top:2px solid oklch(78% 0.13 300); border-radius:2px; }
.pt-legend i.lg-prev { border-top:2px dashed rgba(255,255,255,.4); }
.tc { display:block; width:100%; height:auto; overflow:visible; }
.tc-grid line { stroke:rgba(255,255,255,.08); }
.tc-yl text { font:500 11px 'Inter',sans-serif; fill:rgba(255,255,255,.4); text-anchor:end; }
.tc-xl text { font:500 11px 'Inter',sans-serif; fill:rgba(255,255,255,.55); text-anchor:middle; }
.tc-cur, .tc-prev { fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.tc-cur { stroke:oklch(78% 0.13 300); }
.tc-prev { stroke:rgba(255,255,255,.4); stroke-dasharray:5 5; }
.tc-cur-dot, .tc-prev-dot { stroke:#141417; stroke-width:2; }
.tc-cur-dot { fill:oklch(78% 0.13 300); }
.tc-prev-dot { fill:rgba(255,255,255,.4); }
.tc-peak { font:700 12px 'Space Grotesk',sans-serif; fill:#fff; text-anchor:middle; }
.tc-cur-end { font:600 11px 'Inter',sans-serif; fill:rgba(255,255,255,.92); }
.tc-prev-end { font:600 11px 'Inter',sans-serif; fill:rgba(255,255,255,.55); }
.tc-hit { fill:transparent; }
.tc-hit:hover { fill:rgba(255,255,255,.04); }
.pt-movers { display:flex; flex-direction:column; gap:12px; min-width:0; }
.pt-movers ol { margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:6px; }
.pt-movers a { display:grid; grid-template-columns:64px minmax(0,1fr) auto; gap:12px;
               align-items:center; padding:8px; border-radius:10px; background:#0d0d10;
               border:1px solid rgba(255,255,255,.08); color:inherit; }
.pt-movers a:hover { border-color:oklch(78% 0.13 300 / .55); color:inherit; }
.pt-movers img { display:block; width:64px; height:auto; aspect-ratio:460/215;
                 object-fit:cover; border-radius:6px; }
.mv-t { display:flex; flex-direction:column; gap:3px; min-width:0; }
.mv-n { font:700 13.5px 'Space Grotesk',sans-serif; color:#fff; white-space:nowrap;
        overflow:hidden; text-overflow:ellipsis; }
.pt-movers .up, .pt-movers .down { font:600 12px 'Inter',sans-serif; white-space:nowrap; }

/* this week */
.tw { gap:30px; }
.tw-sub { display:flex; flex-direction:column; gap:14px; }
.tw-head { display:flex; align-items:baseline; justify-content:space-between; gap:12px;
           flex-wrap:wrap; }
.tw h3 { margin:0; font:700 17px 'Space Grotesk',sans-serif; color:rgba(255,255,255,.92); }
.tw-count { font:600 12px 'Inter',sans-serif; color:oklch(88% 0.09 300); margin-left:6px; }
.cal-scroll { overflow-x:auto; }
.cal { margin:0; padding:0; list-style:none; display:grid;
       grid-template-columns:repeat(7,minmax(0,1fr)); gap:8px; min-width:900px; }
.cal-day { background:#141417; border:1px solid rgba(255,255,255,.08); border-radius:12px;
           padding:10px; display:flex; flex-direction:column; gap:10px; min-height:210px; }
.cal-h { display:flex; justify-content:space-between; align-items:baseline; gap:6px;
         padding-bottom:8px; border-bottom:1px solid rgba(255,255,255,.08);
         font:500 15px 'Space Grotesk',sans-serif; color:rgba(255,255,255,.55); }
.cal-h b { font-weight:700; color:#fff; }
.cal-flag { font:600 10px 'Inter',sans-serif; letter-spacing:.08em; text-transform:uppercase;
            color:oklch(80% 0.1 220); }
.cal-game { display:flex; flex-direction:column; gap:6px; color:inherit; }
.cal-game:hover { color:inherit; }
.cal-game:hover .cal-n { text-decoration:underline; }
.cal-game img, .cal-game .noimg { display:block; width:100%; height:auto; aspect-ratio:460/215;
                                  object-fit:cover; border-radius:6px;
                                  border:1px dashed oklch(80% 0.1 220 / .55); }
.cal-n { font:700 13px/1.25 'Space Grotesk',sans-serif; color:#fff; }
.cal-w { font:400 11px 'JetBrains Mono',monospace; color:rgba(255,255,255,.55); }
.cal-more { font:600 11px 'Inter',sans-serif; color:oklch(88% 0.09 300); }
.cal-none { margin:auto 0; text-align:center; font:400 12px 'Inter',sans-serif;
            color:rgba(255,255,255,.55); }

/* tag in numbers */
.figs { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,460px),1fr)); gap:16px; }
.figs figure { margin:0; padding:22px 24px; display:flex; flex-direction:column; gap:16px; min-width:0; }
.figs figcaption { display:flex; flex-direction:column; gap:4px; }
.fig-t { font:700 17px 'Space Grotesk',sans-serif; color:#fff; }
.fig-foot { display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
            padding-top:12px; border-top:1px solid rgba(255,255,255,.08); }
.fig-foot b { color:rgba(255,255,255,.92); font-weight:600; }
.fig-foot a { font:600 12px 'Inter',sans-serif; }
.rb { margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:6px; }
.rb li { display:grid; grid-template-columns:168px minmax(0,1fr) 92px; gap:12px; align-items:center; }
.rb-l { font:600 12px 'Inter',sans-serif; color:rgba(255,255,255,.62); white-space:nowrap; }
.rb-bar { height:14px; position:relative; }
/* A 3px floor, so a band of two games is still a visible bar. */
.rb-bar i { position:absolute; left:0; top:0; bottom:0; min-width:3px; border-radius:0 4px 4px 0; }
.rb-n { font:600 12px 'JetBrains Mono',monospace; color:rgba(255,255,255,.92); text-align:right;
        font-variant-numeric:tabular-nums; white-space:nowrap; }
.rb-n span { color:rgba(255,255,255,.55); }
.rb0 { background:oklch(80% 0.16 150); } .rb1 { background:oklch(72% 0.15 150); }
.rb2 { background:oklch(64% 0.12 150); } .rb3 { background:oklch(57% 0.08 150); }
.rb4 { background:rgba(255,255,255,.38); } .rb5 { background:oklch(57% 0.1 25); }
.rb6 { background:oklch(64% 0.15 25); } .rb7 { background:oklch(70% 0.18 25); }
.rb8 { background:oklch(76% 0.18 25); }
.pc { position:relative; height:230px; margin-top:18px; display:grid;
      grid-template-columns:repeat(7,minmax(0,1fr)); gap:2px; align-items:end;
      border-bottom:1px solid rgba(255,255,255,.14); }
.pc-col { height:100%; display:flex; flex-direction:column; justify-content:flex-end;
          align-items:center; gap:6px; }
/* Above the median line, on the panel color, so the line never runs
   through a number. */
.pc-n { position:relative; z-index:1; padding:0 3px; background:#141417;
        font:600 11px 'JetBrains Mono',monospace; color:rgba(255,255,255,.62);
        font-variant-numeric:tabular-nums; }
/* Shares can differ twentyfold between bands. The bars stay proportional, so
   the chart does not exaggerate, but never drop below a visible 3px, and
   every bar carries its number, so a thin one still reads. */
.pc-col i { display:block; width:72%; min-height:3px; border-radius:4px 4px 0 0;
            background:oklch(78% 0.13 300); }
.pc-col i.free { background:oklch(72% 0.17 150); }
.pc-med { position:absolute; top:-18px; bottom:0; border-left:2px dashed rgba(255,255,255,.62);
          pointer-events:none; }
.pc-med span { position:absolute; left:8px; top:-2px; font:600 11px 'Inter',sans-serif;
               color:#fff; white-space:nowrap; }
.pc-med.flip span { left:auto; right:8px; }
.pc-x { display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:2px; margin-top:-6px; }
.pc-x span { text-align:center; font:600 11px/1.3 'Inter',sans-serif; color:rgba(255,255,255,.55); }

/* --- seo block --- */
.seo-grid { border-top:1px solid rgba(255,255,255,.1); padding-top:28px;
            display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
            gap:32px; align-items:start; }
.seo-grid h2 { font:700 21px 'Space Grotesk',sans-serif; margin:0 0 12px; }
.seo-grid p { margin:0 0 12px; font:400 14px/1.8 'Inter',sans-serif;
              color:rgba(255,255,255,.55); }
.seo-grid details { border-bottom:1px solid rgba(255,255,255,.09); }
.seo-grid summary { cursor:pointer; padding:13px 2px;
                    font:600 14px 'Inter',sans-serif; color:rgba(255,255,255,.85);
                    list-style-position:inside; }
.seo-grid details div { padding:0 2px 14px; font:400 13.5px/1.75 'Inter',sans-serif;
                        color:rgba(255,255,255,.58); }
.seo-grid details p { font:inherit; color:inherit; margin:0 0 10px; }

/* --- cta --- */
.cta { display:flex; align-items:center; justify-content:space-between; gap:20px;
       flex-wrap:wrap; border:1px solid rgba(255,255,255,.12); border-radius:14px;
       padding:22px 26px; }
.cta b { font:700 19px 'Space Grotesk',sans-serif; max-width:520px; text-wrap:pretty; }
.cta b em { font-style:normal; color:oklch(78% 0.13 300); }
.cta a { background:oklch(78% 0.13 300); color:#14141a; border-radius:10px;
         padding:13px 24px; font:700 14.5px 'Space Grotesk',sans-serif; }
.cta a:hover { background:oklch(84% 0.13 300); color:#14141a; }

/* --- tag index (/tags) --- */
.tag-index { display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr));
             gap:14px; margin:0; padding:0; list-style:none; }
.tag-index a { display:flex; flex-direction:column; gap:6px; background:#141417;
               border:1px solid rgba(255,255,255,.08); border-radius:12px;
               padding:16px 18px; color:inherit; }
.tag-index a:hover { border-color:oklch(78% 0.13 300 / .5); color:inherit; }
.tag-index b { font:700 17px 'Space Grotesk',sans-serif; }
.tag-index span { font:400 12px 'Inter',sans-serif; color:rgba(255,255,255,.4); }
.tag-index .trunc { color:oklch(84% 0.13 300); font-style:normal; font-weight:700;
                     white-space:nowrap; margin-left:1px; display:inline-flex;
                     align-items:center; gap:2px; }
.tag-index .trunc svg { display:block; color:oklch(84% 0.13 300); }

/* --- draft preview banner: operator-only, never on a public page --- */
.preview-bar { background:oklch(80% 0.13 85); color:#14141a; padding:9px 28px;
               font:700 12.5px 'Inter',sans-serif; display:flex; gap:14px;
               flex-wrap:wrap; align-items:center; }
.preview-bar a { color:#14141a; text-decoration:underline; }

@media (max-width: 900px) {
  .seo-grid { grid-template-columns:minmax(0,1fr); gap:20px; }
}

@media (max-width: 640px) {
  /* The nav's own narrow-screen rules are in static/nav.css. */
  .page { padding:22px 0 40px; gap:26px; }
  /* The rows keep their full-bleed scrollers; everything else gets the gutter
     back individually, because a gutter on .page would clip the scrollers. */
  .masthead, .seo-grid, .cta, .combos, .tag-index, .page > p.sub,
  .pt-panel, .figs, .tw-head { margin-left:16px; margin-right:16px; }
  /* The jump bar and the release calendar scroll full bleed, like the rows,
     with the gutter inside. Block headers get theirs from .row-head. */
  .jump, .cal-scroll { padding:0 16px; }
  .jump { margin-top:-8px; }
  .crumb { position:static; height:auto; margin-bottom:10px; }
  /* Both masthead controls share one sticky bar. The gutter is cancelled with
     negative margins so the bar spans the screen, and put back as padding.
     It docks under the sticky site nav rather than sliding behind it. */
  .mast-tools { position:sticky; top:var(--nav-h,0); z-index:20; background:#0b0b0d;
                padding:10px 16px; margin:0 -16px 14px; gap:8px;
                align-items:stretch; justify-content:flex-start;
                border-bottom:1px solid rgba(255,255,255,.08); }
  .tagfind { flex:1 1 auto; min-width:0; }
  .tagfind form { flex:1; padding:9px 11px; min-width:0; }
  .tagfind input { flex:1; min-width:0; width:auto; }
  /* Grows so that, on a width where the two controls wrap onto separate
     lines, the currency box fills its line instead of floating half-width. */
  .curpick { flex:1 1 auto; padding:9px 11px; }
  .masthead h1 { font:700 44px/.9 'Space Grotesk',sans-serif; letter-spacing:-.03em;
                 -webkit-text-stroke:1.5px rgba(255,255,255,.7); }
  .masthead h1.h1-long { font-size:36px; line-height:.95; }
  .masthead h1.h1-xlong { font-size:31px; line-height:1; }
  /* There is no spare corner on a phone, so the artwork goes behind everything
     and is darkened from the top down instead of from the left. It bleeds
     through the 16px gutter to both screen edges. */
  .masthead:has(.mast-art) { min-height:0; }
  .mast-art { top:0; right:-16px; left:-16px; bottom:0; width:auto;
              -webkit-mask-image:none; mask-image:none; }
  .mast-art-grid { grid-template-columns:repeat(2,190px); gap:10px;
                   transform:rotate(-11deg) scale(1.18); opacity:.55; }
  .mast-art.one img { opacity:.45; }
  .mast-art::after { background:linear-gradient(179deg,rgba(11,11,13,.42) 0%,
                     rgba(11,11,13,.74) 42%,rgba(11,11,13,.95) 82%,#0b0b0d 100%); }
  .mast-foot { flex-direction:column; align-items:flex-start; gap:14px; }
  /* Height now, not width: let the intro be as tall as its own text. */
  .mast-foot .intro { flex:0 1 auto; max-width:none; width:100%; }
  .mast-text { flex:0 1 auto; width:100%; gap:12px; }
  /* Below the intro on a phone, still two by two. */
  .tiles { flex:0 1 auto; width:100%; max-width:none; gap:8px; }
  .tile { padding:12px 13px; gap:6px; }
  .tile b, .num { font-size:22px; }
  .tile-v { flex-wrap:wrap; gap:4px 8px; }
  .pt-panel { padding:18px 14px; gap:22px; }
  .pt-main { grid-column:auto; }
  /* The chart draws at under half size here, so its text is set larger to
     land near 10-11px on screen, as the combos graph does. */
  .tc-yl text, .tc-xl text { font-size:21px; }
  .tc-peak, .tc-cur-end, .tc-prev-end { font-size:22px; }
  .pt-figs { gap:18px; }
  .rb li { grid-template-columns:118px minmax(0,1fr) 74px; gap:8px; }
  .rb-l { white-space:normal; font-size:11px; line-height:1.25; }
  .figs figure { padding:18px 14px; }
  .pc { height:190px; }
  .pc-x span { font-size:10px; }
  .mast-foot .intro p { font:400 13px/1.75 'Inter',sans-serif; }
  .row { gap:12px; }
  .row-head { flex-direction:column; align-items:flex-start; gap:3px;
              padding:0 16px; }
  .row-head h2 { font-size:18px; line-height:1.25; }
  .row-head .rule { display:none; }
  .row-head .sub { font-size:11.5px; }
  /* Sort note and price share one line under the title, wrapping only when a
     long sort note leaves the pill no room. */
  .row-meta { flex-wrap:wrap; gap:6px 10px; margin-top:3px; }
  .row-price { padding:3px 9px; }
  .row-price b { font-size:12.5px; }
  /* A phone swipes; arrows there would only take room from the title. */
  .row-nav, .row-nav[hidden] { display:none; }
  /* Card 1 starts at the container edge and card 2 peeks in, so the swipe
     reads as a swipe. The page itself must never scroll sideways. */
  /* scroll-padding matches the padding, or mandatory snapping pulls card 1
     flush against the screen edge on load. */
  .strip { gap:16px; padding:0 16px 4px; scroll-snap-type:x mandatory;
           scroll-padding-inline:16px; }
  .gc { flex-basis:232px; scroll-snap-align:start; }
  .gc-rank { font-size:38px; margin-top:-3px;
             -webkit-text-stroke:1.5px rgba(255,255,255,.32); }
  .gc-name { font-size:15px; }
  .seo-grid { padding-top:22px; }
  .seo-grid h2 { font-size:18px; }
  .cta { padding:18px 18px; }
  /* Tag combos: graph above the list, overlay darkening downwards. */
  .combo-panel { padding:16px 12px; gap:8px; }
  .combo-graph { order:0; }
  /* The full width: the viewBox already holds the ring labels. */
  .combo-graph svg { max-width:none; }
  .combo-spot { max-width:none; }
  .combo-bg::after { background:linear-gradient(180deg, rgba(11,11,13,.55) 0%,
                     rgba(11,11,13,.8) 40%, rgba(11,11,13,.95) 70%, #0b0b0d 100%); }
  .combo-list a { padding:9px 8px; gap:6px 10px; }
  .combo-list .rk { font-size:22px; }
  .combo-more { display:block; position:relative; z-index:1; margin-top:6px;
                text-align:center; background:oklch(78% 0.13 300); color:#14141a;
                border-radius:10px; padding:13px 18px;
                font:700 14.5px 'Space Grotesk',sans-serif; }
  .combo-more:hover { background:oklch(84% 0.13 300); color:#14141a; }
  /* The graph draws at about 0.64 of its size on a phone and its text with it,
     so the text is set larger here to land near 11-12px on screen. The hub
     grows to hold its bigger label, and the count below moves down with it. */
  .cg-node text { font-size:18px; }
  .cg-hub { r:48px; }
  .cg-hub-label { font-size:19px; }
  .cg-hub-label.long { font-size:15px; }
  .cg-count { font-size:16.5px; transform:translateY(14px); }
  .cta b { font-size:17px; }
  .cta a { width:100%; text-align:center; }
  .tag-index { grid-template-columns:minmax(0,1fr); }
}

/* On a narrow phone the two control labels cost more room than they earn. The
   placeholder names the current tag and the select shows its own symbol and
   code, so both stay self-explanatory; the aria-labels are what a screen
   reader was reading anyway. */
/* 480, not 420: a 430px screen is an ordinary large phone, and with the labels
   shown the two controls wrap onto separate lines and make the sticky bar 107px
   tall before any content is reached. */
@media (max-width: 480px) {
  .tagfind label, .curpick label { display:none; }
  .mast-tools { gap:6px; }
  .tagfind form, .curpick { padding:8px 10px; }
}

/* Phone scroll cues, added by TAG_STRIP_JS: a scroll bar under each row
   and an arrow over the cards' right edge until the first swipe. Desktop has
   the arrow buttons in the row head instead, so both stay hidden there. */
.strip-wrap { position:relative; }
.strip-bar, .strip-hint { display:none; }
@media (max-width: 640px) {
  .strip-bar { display:block; height:3px; margin:10px 16px 0; border-radius:2px;
               background:rgba(255,255,255,.1); overflow:hidden; }
  .strip-bar i { display:block; height:100%; border-radius:2px; background:#b98af7;
                 transition:transform .08s linear; }
  .strip-hint { display:grid; place-items:center; position:absolute; right:8px; z-index:2;
                width:34px; height:34px; margin-top:-17px; padding:0; border-radius:50%;
                border:1px solid rgba(185,138,247,.6); background:rgba(11,11,13,.85);
                color:#fff; box-shadow:0 4px 14px rgba(0,0,0,.55); cursor:pointer;
                animation:strip-nudge 1.4s ease-in-out 1s 3; }
  .strip-hint svg { width:13px; height:13px; fill:none; stroke:currentColor;
                    stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; }
}
@keyframes strip-nudge { 0%, 100% { transform:translateX(0); } 50% { transform:translateX(5px); } }

@media (prefers-reduced-motion: reduce) {
  .strip-hint { animation:none; }
  .cg-tri.on, .cg-node.on circle.pulse, .cg-count.swap, .combo-hint { animation:none; }
  .cg-tri.on { stroke-dasharray:none; }
  html { scroll-behavior:auto; }
  .combo-bg img { transition:opacity .2s; transform:none !important; }
}
