/* SPAM Meta: the three views (Tier list, Codex, My decks) and the card dialog interior. */

/* a tab's view arrives as one block: a fade and 24px of travel, 280ms on the one curve (TASTE "Enter and exit") */
.view.enter { animation: view-in var(--t-move) var(--curve); }
@keyframes view-in { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
.vhead { display: grid; gap: 8px; margin-bottom: 24px; }
.lede { color: var(--ink-2); max-width: 64ch; font-size: 18px; line-height: 1.5; text-wrap: pretty; }
/* explanations live in the footer (patch.js methodSection; DESIGN.md "Explanations live in the footer"): under the title of a
   ranking view only the small "How it is measured" link (when no banner carries it); the method itself is a text disclosure
   per tab in the footer's Method section, Soft Lavender 16 at the body measure */
.vsub { display: flex; flex-wrap: wrap; align-items: center; gap: 0 24px; }
.vinfo { display: grid; gap: 8px; padding: 4px 0 8px; color: var(--ink-2); }
.vinfo > p { max-width: 68ch; text-wrap: pretty; }
/* the placeholder of a ranking view while its rankings are computed (pending.js; DESIGN.md "Pending view"): a sunken strip
   with a clock and the status (a fact, not a control: no hover, press or focus), then the one action, the way to the Codex */
.pending { display: grid; justify-items: start; gap: 24px; }
.pending-s { display: flex; align-items: center; gap: 12px; max-width: 520px; padding: 16px; border-radius: 8px;
  background: var(--socket); box-shadow: var(--sunken); color: var(--ink); font: 400 18px/1.15 var(--display); letter-spacing: .01em; }
.pending-s .ico { width: 24px; height: 24px; color: var(--muted); }
@media (max-width: 640px) { .pending { gap: 16px; } .pending-s { padding: 12px; } }
/* the deck ranking (tiers.js; DESIGN.md "Deck tier list"). A temporary ranking says so in one line (DESIGN.md "Provisional
   banner"): Panel Lifted with a Line Indigo edge, the clock, "Temporary ranking, being refined." in Cream Lavender, and the small
   link to the footer's Method section. Not dismissible, no motion: the list below never moves. */
.rk-banner { display: grid; grid-template-columns: auto auto auto; justify-self: start; align-items: center; gap: 4px 12px;
  margin-top: 8px; padding: 12px 16px; border-radius: 12px; background: var(--panel-hi); border: 1px solid var(--line); color: var(--ink); }
.rk-banner > .ico { width: 24px; height: 24px; color: var(--ink); }
.rk-banner-t { min-width: 0; max-width: none; margin: 0; color: var(--ink); font: 400 16px/1.5 var(--text); text-wrap: pretty; }
.mlink { position: relative; }
.mlink::after { content: ""; position: absolute; inset: -8px -4px; }      /* a 44px hit area around the 29px line */
@media (max-width: 640px) {
  .rk-banner { grid-template-columns: auto minmax(0, 1fr); justify-self: stretch; align-items: start; }
  .rk-banner .mlink { grid-column: 2; justify-self: start; }      /* under the text, clear of the clock */
}
/* the sort switch and "Ready to play" (DESIGN.md "Sort switch"): under the owned callout, above the card search and the list;
   it stays under the header while the decks scroll (the Card tier list's sticky band, ui.js band()), so the big number of every
   row keeps its name on screen */
.vhead + .callout { margin-top: 0; }
.rk-bar { position: sticky; top: var(--chrome-h); z-index: 12; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  margin: 8px calc(-1 * var(--gut)) 0; padding: 8px var(--gut); }
.rk-bar + .find { margin-top: 8px; }
.rk-list .deck { scroll-margin-top: calc(var(--chrome-h) + 64px); }      /* a deck reached by Enter or a link clears the sort bar */
.rk-sec .rk-list :is(button, a) { scroll-margin-top: 64px; }      /* so does a card or a figure reached by Tab (the page's scroll padding clears the header) */
/* the ranked list (an ordered list, one deck per item) and its empty state when "Ready to play" leaves no deck */
.rk-list { display: grid; margin-top: 8px; }
/* the Deck tier list's decks under the first are laid out and painted only near the screen (64 decks are about 19,000
   elements; a list swap lays out a third as much). Each keeps its height once drawn; before that, the height below stands
   in: a row's usual content height at each layout (its 24 + 16px padding and hairline come on top), 1 row of 4 cards with
   the facts beside it, the facts above, 2 by 2 on a phone. A jump past the list lays every deck out for one frame first
   (ui.js settleRows), so it lands where it aims. Nothing in a deck reaches outside it (paint is clipped to the deck): the
   tooltip and the card view live in the body and the top layer */
.cv-rows > .deck:not(.spot) { content-visibility: auto; contain-intrinsic-block-size: auto 308px; }
.cv-rows.settle > .deck { content-visibility: visible; }
@media (max-width: 1040px) { .cv-rows > .deck:not(.spot) { contain-intrinsic-block-size: auto 580px; } }
@media (max-width: 760px) { .cv-rows > .deck:not(.spot) { contain-intrinsic-block-size: auto 510px; } }
@media (max-width: 640px) { .cv-rows > .deck:not(.spot) { contain-intrinsic-block-size: auto 790px; } }
.rk-empty { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 24px; max-width: none; color: var(--ink-2); }
.rk-empty .btn { height: 36px; padding: 0 16px; font-size: 16px; }
/* the footer's Method sub-sections: the caveats as a short list in the region's own type */
.vinfo-l { display: grid; gap: 4px; max-width: 68ch; padding-left: 20px; list-style: disc; text-wrap: pretty; }
/* under each card, the talent the deck plays with it: the client's talent glyph and its name, two lines at most */
.rk-list .slot { display: grid; gap: 12px; align-content: start; }      /* clear of the rarity gem that overhangs the card */
.slot-tl { display: flex; justify-content: center; align-items: flex-start; gap: 4px; min-width: 0; color: var(--ink-2); font: 600 14px/1.3 var(--text); text-align: center; cursor: help; }
.slot-tl .ab-talent { width: 16px; height: 16px; margin-top: 1px; }
/* the matchup mark (DESIGN.md "Matchup mark"): a talent picked against the opponent, the 14px swap glyph in Dusk Lavender after
   its name; its name and title say the rule; no colour of its own, no box, no motion */
.mu { display: inline-grid; place-items: center; flex: none; width: 16px; height: 16px; margin-top: 1px; color: var(--muted); cursor: help; }
.mu .ico { width: 14px; height: 14px; }
.mu-line .mu { vertical-align: -2px; }
.slot-tl > .mu { display: inline-grid; overflow: visible; }      /* not the talent name's two-line clamp */
.slot-tl > span { min-width: 0; overflow: hidden; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
.slot.miss .slot-tl { opacity: .45; }
.slot.miss:hover .slot-tl, .slot.miss:focus-within .slot-tl { opacity: 1; }

/* ---------------------------------------------------------------- collection bar (Codex and My decks) */
.cbar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 16px 32px; align-items: center; background: var(--panel-hi); }
.cb-main { display: grid; gap: 12px; min-width: 0; }
.cb-fig { display: grid; gap: 8px; }
.cb-h { font: 400 22px/1.15 var(--display); max-width: none; }
.cb-n { font-size: 40px; line-height: 1; }
.cb-t { color: var(--ink-2); }
.cb-txt { color: var(--ink-2); max-width: 60ch; }
.cb-act { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
.cbar > .note { grid-column: 1 / -1; }
/* the hint row: the "how to mark" sentence, then "Saved in this browser only" + Copy my code in the same place */
.cb-say { display: grid; align-items: center; min-height: 32px; }

/* ---------------------------------------------------------------- keeping the collection (keep.js) */
.keep { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-width: 0; }
.keep-t { display: flex; align-items: flex-start; gap: 8px; min-width: 0; max-width: none; color: var(--muted); font: 600 14px/1.4 var(--text); text-wrap: pretty; }
.keep-t .ico { height: 1lh; }
.keep-t > span { min-width: 0; }
/* no storage: said plainly, on its own full-width row of the collection bar */
.cbar > .keep { grid-column: 1 / -1; padding-top: 16px; border-top: 1px solid var(--line); }
.keep.nostore .keep-t { color: var(--ink); font: 400 16px/1.55 var(--text); }
.keep.nostore .keep-t .ico { color: var(--muted); }
.keep-copy { white-space: nowrap; }

/* in-app browser notice: one flat row with a dismiss button; hiding fades it, then the row closes */
.inapp .collapse-in { padding-bottom: 16px; }
.inapp-in { display: flex; align-items: center; gap: 12px; padding: 4px 4px 4px 16px; border-radius: 12px; background: var(--panel); border: 1px solid var(--line);
  transition: opacity var(--t-fade) var(--curve); }
.inapp-in > .ico { color: var(--muted); }
.inapp-in p { flex: 1 1 auto; min-width: 0; max-width: none; padding: 8px 0; color: var(--ink); text-wrap: pretty; }
.inapp.out .inapp-in { opacity: 0; }
.track { position: relative; height: 10px; max-width: 420px; border-radius: 4px; background: var(--socket); box-shadow: var(--sunken); overflow: hidden; }
.track-fill { position: absolute; inset: 0; background: var(--accent); border-radius: 4px; transform-origin: left center; transform: scaleX(0); transition: transform var(--t-move) var(--curve); }

/* ---------------------------------------------------------------- Codex toolbar */
/* the search and the sort, then the filter triggers (filters.css) on their own row; on a phone the Filters button opens them
   in a bottom sheet and the sort takes the second row */
#view-codex .tb-top { margin-top: 24px; }
.tb-top { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 232px; gap: 12px; padding: 8px 0; }
#view-codex .tb-result { margin: 12px 0 20px; }
@media (min-width: 760px) {
  /* the search row and the triggers stay under the header while the 127 cards scroll */
  .tb-top { position: sticky; top: var(--chrome-h); z-index: 12; }
}
.fbtn { display: none; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.tb-result { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
.result { font-weight: 700; color: var(--ink); white-space: nowrap; }
.tb-bulk { display: flex; flex-wrap: wrap; gap: 8px; }
.tb-bulk .btn { height: 36px; font-size: 16px; padding: 0 16px; }
@media (max-width: 759px) {
  .tb-top { grid-template-columns: minmax(0, 1fr) auto; }
  .tb-top .select { grid-column: 1 / -1; grid-row: 2; }
  .fbtn { display: inline-flex; }
}

.grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 32px 24px; align-items: start; }
.snip { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.4; }
.snip b { color: var(--ink); }
mark { background: rgba(70, 211, 255, .28); color: inherit; border-radius: 4px; padding: 0 1px; }
.empty { display: grid; justify-items: center; gap: 12px; text-align: center; padding: 48px 24px; }
.empty p { color: var(--ink-2); }
.empty-ico { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%; background: var(--socket); box-shadow: var(--sunken); color: var(--accent); }
.empty-act { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 8px; }
.grid + .empty { margin-top: 8px; }
.empty-alt { margin-top: 8px; padding-top: 16px; border-top: 1px solid var(--line); color: var(--muted); font: 600 14px/1.4 var(--text); }

/* ---------------------------------------------------------------- Tier list */
.guide-wrap { display: grid; gap: 8px; margin: 24px 0 8px; justify-items: start; }
.guide { display: grid; gap: 12px; padding: 16px 20px; border-radius: 12px; background: var(--panel); border: 1px solid var(--line); color: var(--ink-2); }
.guide ul { display: grid; gap: 8px; padding-left: 20px; list-style: disc; color: var(--muted); }
/* card search row (search.js): the Codex field, then one live line beside it (below it on a phone). It sits right under the
   page heading of the Deck tier list and My decks, above the callout or the collection bar. */
.find { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 8px 16px; align-items: center; margin-top: 24px; }
.vhead + .find, .inapp + .find { margin-top: 0; }
.find + .callout, .find + .cbar { margin-top: 24px; }
.find-say { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0; max-width: none; color: var(--ink-2); font-size: 16px; line-height: 1.4; }
.find-cards { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 8px; min-width: 0; }
.find-hit { display: inline-flex; align-items: center; gap: 4px; }
.find-clear { height: 36px; padding: 0 16px; font-size: 16px; }
/* "Decks with this card": the way from a list's search to the Deck builder, pushed to the end of the line */
.find-more { height: 36px; padding: 0 12px; margin-left: auto; font-size: 16px; }
.guide-wrap + .find { margin-top: 16px; }
@media (max-width: 759px) {
  /* the line keeps its row while empty, so the first letter typed moves nothing */
  .find { grid-template-columns: minmax(0, 1fr); }
  .find-say { min-height: 36px; }
  .find + .callout, .find + .cbar { margin-top: 16px; }      /* the reserved line already gives the row its air */
  .find-more { margin-left: -12px; }                          /* on its own line: the glyph lines up with the text */
}
/* inside a deck that matches, the other cards step back (the icon opacity floor); hover or focus brings one back */
.slot.miss .gc { opacity: .45; }
.slot.miss:hover .gc, .slot.miss:focus-within .gc { opacity: 1; }
.chip.ready { gap: 6px; }

/* A deck of the ranking: a row on the ground, no box; a hairline separates two decks (DESIGN.md "Deck tier list") */
.deck { display: grid; gap: 16px; padding: 24px 0 16px; }
/* a hairline above every deck that follows a shown deck, so a search that hides decks never doubles a line */
.deck:not([hidden]) ~ .deck { border-top: 1px solid var(--line); }
.deck-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 16px; min-height: 36px; }
.rk { font: 400 28px/1 var(--display); color: var(--muted); }
/* a fact about a deck in words, never a box: "likely #1–9" (its likely place in the list), "tied" (the speed list: the same
   rounds as another deck) */
.deck-word { color: var(--muted); font: 600 14px/1.4 var(--text); white-space: nowrap; }
.deck-head .obadge { margin-left: auto; align-self: center; }
.deck-body { display: grid; grid-template-columns: minmax(0, 640px) minmax(0, 1fr); gap: 16px 48px; align-items: start; }
.deck-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; padding: 8px 8px 12px; }
.slot { position: relative; min-width: 0; }
.deck-facts { display: grid; gap: 16px; align-content: start; }
/* a deck's facts on My decks and the Deck builder (decklist.js deckFacts, DESIGN.md "Deck facts"): its rating big, a word that
   explains itself (the figures' grammar: dotted underline at rest, the socket chip with the ring under the pointer, open or
   focused): "Rating" in Title 22, the value in Headline 28, the margin and the AI in Dusk Lavender 14; a fast estimate is the
   quiet state alone. A deck of the Deck tier list adds its speed under it (.rfig, no list active). */
.dfacts { display: grid; gap: 12px; justify-items: start; align-content: start; padding-top: 8px; }
.fig-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: 0; }
.dt-fig { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; margin: -4px -8px; padding: 4px 8px; border: 0; border-radius: 8px;
  background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer; transition: background var(--t-state) var(--curve), box-shadow var(--t-state) var(--curve); }
.dt-fig:hover, .dt-fig.on, .dt-fig:focus-visible { outline: none; background: var(--socket); box-shadow: var(--ring); }
.fig-k { color: var(--ink-2); font: 400 22px/1 var(--display); letter-spacing: .01em; }
.dt-fig .fig-k { text-decoration: underline dotted var(--edge) 1.5px; text-underline-offset: 4px; transition: text-decoration-color var(--t-state) var(--curve); }
.dt-fig:hover .fig-k, .dt-fig.on .fig-k, .dt-fig:focus-visible .fig-k { text-decoration-color: transparent; }
.dt-fig.fast .fig-k { color: var(--muted); }
.fig-pm, .fig-ai { color: var(--muted); font: 600 14px/1 var(--text); }
/* a listed deck's two figures (decklist.js listFigures, DESIGN.md "Deck figures"): Elo and Speed in two equal columns, the
   lists' order, so they line up on every card. Each is its name (Nunito 600 14 Dusk Lavender, the dotted underline of a word that
   explains itself) over its value (Lilita 18 Soft Lavender; the active list's in Headline 28 Cream Lavender, its unit or margin
   Nunito 600 14 Dusk Lavender 4px after it), then one quiet note when the figure needs it on its face (the AI under the Elo, or
   "not in the 64"); the values of a card share one baseline and so do the notes (the columns are subgrids of its three rows). A
   figure the deck lacks keeps its column with a quiet state (Nunito 600 14 Dusk Lavender, two lines at most). Each is a button, a socket chip with the 2px cyan ring under the pointer, while its tooltip is open and on
   keyboard focus (the keyword chip's states, cards.css); the chip reaches 8px past its text at the sides and 4px above and
   below, outside the column, so the text stays on the grid. */
.rfig { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto auto auto; gap: 4px 24px; width: min(100%, 288px); }
.rf { grid-row: span 3; justify-self: start; display: grid; grid-template-rows: subgrid; justify-items: start; min-width: 0; max-width: calc(100% + 16px); margin: -4px -8px; padding: 4px 8px; border: 0; border-radius: 8px;
  background: none; color: var(--ink-2); font: inherit; text-align: left; cursor: pointer; transition: background var(--t-state) var(--curve), box-shadow var(--t-state) var(--curve); }
.rf:hover, .rf.on, .rf:focus-visible { outline: none; background: var(--socket); box-shadow: var(--ring); }
.rf-k { max-width: 100%; color: var(--muted); font: 600 14px/1.4 var(--text); white-space: nowrap; text-decoration: underline dotted var(--edge) 1.5px; text-underline-offset: 4px;
  transition: text-decoration-color var(--t-state) var(--curve); }
.rf:hover .rf-k, .rf.on .rf-k, .rf:focus-visible .rf-k { text-decoration-color: transparent; }
.rf-n { align-self: baseline; max-width: 100%; white-space: nowrap; }
.rf-v { font: 400 18px/1 var(--display); letter-spacing: .01em; }
.rf.act { color: var(--ink); }
.rf.act .rf-v { font-size: 28px; }
.rf-u { color: var(--muted); font: 600 14px/1 var(--text); }
.rf-s { display: block; color: var(--muted); font: 600 14px/1.15 var(--text); white-space: normal; text-wrap: balance; }
.rf-x { max-width: 100%; color: var(--muted); font: 600 14px/1.15 var(--text); text-wrap: balance; }
/* under the figures: the tox the deck bought most and its variants (DESIGN.md "Tox line", "Variants"); on one column they follow
   the cards (the figures come first, so the numbers are read before the fold) */
.dmore { display: grid; gap: 4px; justify-items: start; align-content: start; min-width: 0; }
.tox { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; column-gap: 12px; min-width: 0; max-width: 432px; }
.tx-k { margin: 0 -8px; padding: 4px 8px; border: 0; border-radius: 8px; background: none; color: var(--muted); font: 600 14px/1.4 var(--text); cursor: pointer;
  text-decoration: underline dotted var(--edge) 1.5px; text-underline-offset: 4px; transition: background var(--t-state) var(--curve), box-shadow var(--t-state) var(--curve), text-decoration-color var(--t-state) var(--curve); }
.tx-k:hover, .tx-k.on, .tx-k:focus-visible { outline: none; background: var(--socket); box-shadow: var(--ring); text-decoration-color: transparent; }
.tx-l { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 0; padding: 0; list-style: none; }
.tx { display: inline-flex; align-items: center; gap: 4px; min-height: 28px; white-space: nowrap; cursor: help; font: 600 14px/1.15 var(--text); }
.tx-gem { flex: none; width: 16px; height: 16px; background-size: contain; background-repeat: no-repeat; background-position: center; }
.tx-n { color: var(--ink-2); }
.tx-r { color: var(--muted); }      /* the rarity word, in its rarity text colour: two tox of one family differ by it */
.tx-r.ra-common { color: var(--r-common); } .tx-r.ra-rare { color: var(--r-rare); } .tx-r.ra-epic { color: var(--r-epic); }
.tx-r.ra-legendary { color: var(--r-legendary); } .tx-r.ra-divine { color: var(--r-divine); }
.tx-s { color: var(--muted); font-variant-numeric: tabular-nums; }
.tdisc.tx-more { position: relative; height: 28px; padding: 0 8px; }
.tdisc.tx-more::after { content: ""; position: absolute; inset: -8px -2px; }      /* a 44px hit area on a 28px control */
.vr { display: grid; justify-items: start; min-width: 0; width: 100%; }
.vr-b { margin-left: -12px; }      /* its label lines up with the tox label */
.vr-l { display: grid; gap: 8px; margin: 0; padding: 4px 0 8px; list-style: none; }
/* one variant per line, read as a sentence that wraps like text; a hairline between two variants */
.vr-l li { color: var(--muted); font: 600 14px/32px var(--text); }
.vr-l li + li { padding-top: 8px; border-top: 1px solid var(--line); }
.vr-l .cc { margin: 0; }
.vr-sep { margin: 0 8px; }
.tdisc.vr-all { position: relative; height: 28px; margin: 0 0 8px -8px; padding: 0 8px; }
.tdisc.vr-all::after { content: ""; position: absolute; inset: -8px -2px; }      /* a 44px hit area on a 28px control */
.vr-t { display: inline-flex; align-items: center; gap: 4px; margin: 0 4px; color: var(--ink-2); line-height: 1.4; vertical-align: middle; cursor: help; }
.vr-t .ab-talent { width: 16px; height: 16px; }
/* a group of decks after the list, under its own heading (My decks and the Deck builder: the fast estimates) */
.rk-cut { margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--line); }
.rk-cut h2, .rk-cut h3 { margin: 0; color: var(--ink-2); font: 400 22px/1.15 var(--display); letter-spacing: .01em; }
.rk-cut p { margin: 8px 0 0; color: var(--muted); font: 600 14px/1.4 var(--text); }
.deck.spot .deck-body { grid-template-columns: minmax(0, 1fr); }
/* the first deck's figures above its four big cards, so they are read before the fold; its tox and variants after the cards */
.deck.spot .deck-facts { display: contents; }
.deck.spot .dfacts { order: -1; }
.deck.spot .deck-cards { gap: 24px; padding: 12px 12px 16px; }
/* the way to the overlay: one line after the list, on the ground, no box; its hairline runs across the column like the decks' */
.ov-tease { max-width: none; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); color: var(--muted); }
.ov-tease .link { font-weight: 700; }
.vhead .dnote { margin-top: 4px; }

/* how many of a deck's cards the visitor owns: words and chips on the ground, no pill; all four owned adds the cyan check */
.obadge { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-height: 36px; color: var(--ink-2); font: 600 14px/1.3 var(--text); }
.obadge.full { color: var(--ink); }
.obadge.full .ico { color: var(--accent); }


/* ---------------------------------------------------------------- My decks */
.mdsec { display: grid; gap: 16px; margin-top: 48px; }
.mdsec .sub { margin-top: -8px; }
.cbar + .guide-wrap { margin-top: 16px; }
.dr-miss { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
/* every deck row (the Deck tier list, My decks, the Deck builder): its facts, then a "Missing:" line, 12px apart */
.rk-list .deck-facts { gap: 12px; }
.more { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 16px; }

/* ---------------------------------------------------------------- Deck builder */
.fd-pick { display: grid; gap: 12px; }
.fd-field { max-width: 420px; }
.field.off { opacity: .5; cursor: default; }
.field.off:hover { box-shadow: var(--sunken), inset 0 0 0 1px var(--edge); }
/* the line under the field: matches, "often with" or popular cards, as add chips; it keeps one row while it changes */
.fd-sug { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-height: 36px; max-width: none; color: var(--ink-2); }
.fd-sug-l { color: var(--muted); font: 600 14px/1.4 var(--text); }
.fd-add { padding: 0 12px 0 8px; }
.fd-add .cc-art { width: 18px; height: 24px; border-radius: 4px; object-fit: cover; }
.fd-add .ico { color: var(--muted); }
.fd-add:hover .ico { color: var(--ink); }
/* four pick slots, always drawn: a pick is a sunken cell with the card (opens it) and a remove button; an empty one adds */
.fd-slots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-top: 4px; }
.fd-slot { display: flex; align-items: center; min-width: 0; height: 44px; border-radius: 8px; background: var(--socket); box-shadow: var(--sunken), inset 0 0 0 1px var(--line); }
.fd-slot.on { box-shadow: var(--sunken), inset 0 0 0 1px var(--edge); }
.fd-card { display: flex; flex: 1 1 auto; align-items: center; gap: 8px; min-width: 0; height: 100%; padding: 0 4px 0 8px; border: 0; border-radius: 8px 0 0 8px; background: transparent; color: var(--ink);
  font: 700 16px/1.2 var(--text); text-align: start; cursor: pointer; transition: background var(--t-state) var(--curve); }
.fd-card:hover { background: rgba(255, 255, 255, .08); }
.fd-art { flex: none; width: 24px; height: 34px; border-radius: 4px; object-fit: cover; }
.fd-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fd-x { position: relative; display: inline-grid; place-items: center; flex: none; width: 32px; height: 32px; margin-right: 8px; border: 0; border-radius: 50%; background: transparent; color: var(--ink-2); cursor: pointer;
  transition: background var(--t-state) var(--curve), color var(--t-state) var(--curve); }
.fd-x::after { content: ""; position: absolute; inset: -6px; }
.fd-x:hover { background: rgba(255, 255, 255, .1); color: var(--ink); }
.fd-x:active { background: rgba(0, 0, 0, .35); }
.fd-empty { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; height: 100%; border: 0; border-radius: 8px; background: transparent; color: var(--muted);
  font: 600 14px/1 var(--text); cursor: pointer; transition: background var(--t-state) var(--curve), color var(--t-state) var(--curve); }
.fd-empty:hover { background: rgba(255, 255, 255, .08); color: var(--ink-2); box-shadow: var(--ring); }
.fd-slot.idle { justify-content: center; color: var(--muted); opacity: .5; }
.fd-res { margin-top: 48px; }
.fd-res:empty { display: none; }
.fd-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
.fd-head h2 { scroll-margin-top: calc(var(--chrome-h) + 24px); }
.fd-head h2:focus { outline: none; }
.fd-head h2:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
.fd-head + .guide-wrap { margin: 8px 0 16px; }
.fd-none { color: var(--ink-2); font-size: 18px; line-height: 1.5; margin-bottom: 24px; }
.fd-res > .fd-none:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- Without these cards (search.js outRow: the Deck builder, My
   decks), in the builder's order: the label, the field, one reserved line (the hint at rest, "Leave out:" and cards while typing),
   then the cards left out */
.out { display: grid; gap: 8px; }
.fd-pick + .out { margin-top: 32px; }
.find + .out { margin-top: 24px; }
/* a field's label, not a heading: the Method sub-section's label step (Nunito 600 16 Soft Lavender), quieter than the picks */
.out-l { justify-self: start; color: var(--ink-2); font: 600 16px/1.4 var(--text); }
.out .field { max-width: 420px; }
.out-sug { display: flex; align-items: center; min-height: 36px; max-width: none; color: var(--muted); font: 600 14px/1.4 var(--text); }
/* the offers keep the one row at every width: they shrink and cut their names rather than wrap (typing moves nothing) */
.out-m { display: flex; flex-wrap: nowrap; align-items: center; gap: 8px; min-width: 0; color: var(--ink-2); }
.out-m .fd-sug-l { flex: none; }
.out-add { flex: 0 1 auto; min-width: 0; padding: 0 12px 0 8px; }
.out-add .chip-l { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.out-add .ico { flex: none; color: var(--muted); }
.out-add:not(:disabled):hover .ico { color: var(--ink); }
/* every line of chips is 44px (their hit area), so a second line only grows downward */
.out-list { display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px; min-width: 0; }
.out-list > li { display: flex; align-items: center; min-height: 44px; min-width: 0; }
/* a card left out: the card chip's size (28px, its 18 x 24 art) on the active filters' removable chip; the whole chip brings it back */
.out-chip { gap: 4px; padding: 0 8px 0 4px; max-width: 100%; }
.out-chip .cc-art { margin-right: 4px; }
/* nothing left: the cards that, brought back alone, show decks again (the Codex's nearest searches); the name gives way to the count */
.out-back { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 24px; }
.out-back .btn { max-width: 100%; min-width: 0; padding: 0 16px 0 12px; }
.ob-t { display: flex; min-width: 0; white-space: pre; }
.ob-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ob-d { flex: none; }
.md-out-none { margin-top: 48px; }
.mdsec h2 { scroll-margin-top: calc(var(--chrome-h) + 24px); }
/* ability orb and talent glyph (card dialog, Card tier list pinned card); the card dialog itself lives in card.css */
.ab-orb, .ab-talent { width: 24px; height: 24px; flex: none; background-size: contain; background-repeat: no-repeat; background-position: center; }
/* data notice: where a value comes from, before the numbers it qualifies; a caption line, no box, never an error colour (DESIGN.md) */
.dnote { display: flex; align-items: flex-start; gap: 8px; max-width: none; color: var(--muted); font: 600 14px/1.4 var(--text); text-wrap: pretty; }
/* the glyph box is one text line tall, so the glyph centres on the first line however the sentence wraps */
.dnote .ico { height: 1lh; }
.dnote > span { min-width: 0; }
/* the suggested talent's tag: a quiet outline one step brighter than .tag.soft, never cyan (it is not an action) */
.tag.sugg { background: none; box-shadow: inset 0 0 0 1px var(--edge); color: var(--ink-2); cursor: help; }

/* ---------------------------------------------------------------- patch marks (patch.js, DESIGN.md "Patch mark") */
/* the one glyph: a diamond, filled when the card's values changed in the last patch, hollow for talents or texts only */
.pglyph { display: inline-block; flex: none; width: 8px; height: 8px; margin: 0 2px; transform: rotate(45deg); background: var(--ink-2); }
.pglyph.hollow { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink-2); }
.tag.ptag { gap: 8px; }
/* the patch notice of the ranking views: plain text inside the intro line's "About the numbers" region (owner, 2026-10-18:
   too much text above the list), Soft Lavender 16 at the body measure */
.pnotice { max-width: 68ch; color: var(--ink-2); text-wrap: pretty; }

/* ---------------------------------------------------------------- About and collection code */
.about, .codebox { display: grid; gap: 24px; padding: 32px; }
.about section { display: grid; gap: 12px; }
.about h2, .codebox h2 { font-size: 28px; padding-right: 40px; }
.about h3, .codebox h3 { font-size: 22px; }
.about .lead { font-size: 18px; color: var(--ink-2); }
.about .lead b { color: var(--ink); }
.about ul { display: grid; gap: 8px; padding-left: 20px; list-style: disc; color: var(--ink-2); }
.stages { display: grid; gap: 12px; list-style: none; counter-reset: stage; }
.stages li { display: grid; gap: 2px; padding-left: 40px; position: relative; counter-increment: stage; color: var(--ink-2); }
.stages li::before { content: counter(stage); position: absolute; left: 0; top: 0; display: grid; place-items: center; width: 28px; height: 28px; border-radius: 8px; background: var(--socket); box-shadow: var(--sunken); font: 400 16px/1 var(--display); color: var(--ink); }
.stages b { color: var(--ink); }
.legal { color: var(--muted); font-size: 14px; padding-top: 16px; border-top: 1px solid var(--line); }
.codebox section { display: grid; gap: 8px; }
.code-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: start; }
.code { width: 100%; resize: none; padding: 10px 12px; border: 0; border-radius: 8px; background: var(--socket); box-shadow: var(--sunken), inset 0 0 0 1px var(--edge); color: var(--ink); font: 600 16px/1.5 ui-monospace, "Cascadia Mono", Consolas, monospace; letter-spacing: .04em; overflow-wrap: anywhere; }
.code { field-sizing: content; min-height: 44px; }
.code:focus { outline: none; box-shadow: var(--sunken), inset 0 0 0 1px var(--accent), var(--ring); }
.code::placeholder { color: var(--muted); opacity: 1; letter-spacing: 0; font-family: var(--text); font-weight: 400; }
.code-act { display: flex; flex-wrap: wrap; gap: 8px; }
.msg { min-height: 22px; font-size: 14px; color: var(--muted); }
.msg.err { color: var(--loss); }
.msg.ok { color: var(--ink-2); }
.noscript { padding-block: 32px; }

/* ---------------------------------------------------------------- tablet and phone */
@media (max-width: 1040px) {
  .deck-body { grid-template-columns: minmax(0, 1fr); }
  /* one column: the facts right under the rank, before the cards */
  .rk-list .deck-facts { display: contents; }
  .rk-list .dfacts { order: -1; }
  .dfacts { padding-top: 0; }
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .about, .codebox { padding: 24px 16px; }
  .cbar { grid-template-columns: minmax(0, 1fr); }  .cb-act { justify-content: flex-start; }
}
@media (max-width: 640px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 12px; }
  .cell { padding: 6px 4px 8px; }
  .gc-ab, .gc-pa { font-size: max(9px, calc(var(--u) * 5.6)); }
  .gc-ab.long, .gc-pa.long, .gc-ab.xlong, .gc-pa.xlong { font-size: max(8.5px, calc(var(--u) * 4.4)); }
  .deck-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; max-width: 360px; }
  .deck.spot .deck-cards { gap: 16px 12px; max-width: 420px; }
  .tb-bulk .btn { flex: 1 1 auto; }
  .deck-head .obadge { margin-left: 0; }
  .fd-slots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fd-field { max-width: none; }
  /* a phone: the label on its own line, the four cards two by two, long names cut */
  .fd-sug { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto 36px 36px; align-content: start; }   /* the rows stay while typing */
  .fd-sug.full { grid-template-rows: auto; min-height: 0; }      /* four picks: nothing to suggest, nothing reserved */
  .fd-sug > span { grid-column: 1 / -1; }
  .fd-add { min-width: 0; }
  .fd-add .chip-l { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .fd-add .ico { margin-left: auto; }
  /* a pick's name wraps to two lines instead of being cut */
  .fd-name { font-size: 14px; line-height: 1.15; white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
  /* without these cards: the field full width; while typing two cards share the one reserved row evenly, the field's label
     above saying the verb (the line's "Leave out:" stays for screen readers); a two-line hint or "No card named" fits the row */
  .fd-pick + .out { margin-top: 24px; }
  .find + .out { margin-top: 16px; }
  .out .field { max-width: none; }
  .out-sug { min-height: 44px; }
  .out-m { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .out-m .fd-sug-l { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .out-m .out-no { grid-column: 1 / -1; }
  .out-add .ico { margin-left: auto; }
}
