[hidden] { display: none !important; }

/* The palette. Every one of these is written again by themes.js, in a <style>
   it appends to the head - later in the document, same specificity, so the
   theme wins the tie and this block is what the app looks like with no theme
   chosen and no script run. Keep them in step: this is the Bear Magic theme,
   spelled twice, and the test in tests/themetest.mjs is what says so. */
:root {
  /* One tile width, and the factor that fits a 300px card face into it. Kept
     together because they are one decision: --pt-face-k is --pt-w / 300. */
  --pt-w: 84px;
  --pt-face-k: .28;
  --bg: #16150f;
  --surface: #201e17;
  --surface-2: #2b291f;
  --line: #3a382c;
  --text: #eae6d8;
  --muted: #a8a394;
  --accent: #c8853b;
  --accent-ink: #1b1305;
  --radius: 12px;
  --pad: 16px;
  /* The page's measure. `main` and the sticky topbar both use it, so a
     heading and the thing it is a heading for line up. */
  --measure: 1100px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: max(env(safe-area-inset-top), 12px) var(--pad) 12px;
  /* The bar spans the window — it is sticky, and a background that stopped at
     1100px would leave the page showing through beside it. What is *written*
     in it lines up with the page instead, by growing the side padding until
     the content box is the same measure `main` uses.

     Done here rather than by wrapping every header in a div: this is fifteen
     pages, and a rule on the children loses a specificity argument with
     `.topbar h1` and half a dozen others that set their own margins.

     It showed on the search page first because that header holds a full-width
     <input>, which stretched to the window while the results below it sat in
     a 1100px column. Every other page had the same gap and only looked
     tidy — short text does not reveal a missing measure.

     The `+ var(--pad)` is not a fudge. `main` is `max-width: --measure` with
     its padding *inside* that, so its text starts one pad in from --measure.
     The topbar has no max-width to put padding inside, so the pad is added to
     the calc — without it the bar lines up with main's border box and sits a
     pad wider than the text it is supposed to sit over, which reads as a
     mistake rather than as a margin. */
  padding-inline: max(var(--pad),
                      calc((100% - var(--measure)) / 2 + var(--pad)));
}
.topbar h1 { margin: 0 0 8px; font-size: 18px; font-weight: 600;
  display: flex; align-items: center; flex-wrap: wrap; }
/* Section nav — plain sibling links, same set and same order on every page.
   These were a mix of "‹ Home" and "Collection ›", where the arrows read as
   browser back/forward even though every one is an ordinary link to a section.
   Genuine back links (add.html, playtest.html) still use .back and keep the ‹. */
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-bottom: 6px; }
/* same icons the home page's tiles use, so a destination looks the same
   wherever it's linked from */
.crumbs a { display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; color: var(--muted); text-decoration: none; }
.crumbs a > span { font-size: 15px; line-height: 1; }
/* painted icons rather than emoji: same slot, but they carry the house style
   and render identically on every platform instead of per-OS emoji fonts */
/* The gap between an icon and the words after it is written as
   margin-inline-end, not margin-right. There is no mirrored stylesheet behind
   this app, and there does not need to be — flexbox and grid reverse
   themselves under dir="rtl" on their own. What does not reverse is a physical
   margin, and in Arabic the app logo sat on top of its own title until these
   few were made logical. */
.crumb-ic { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 5px;
  object-fit: cover; }
.crumbs a:hover { color: var(--accent); }
.crumb-act { margin-inline-start: auto; }   /* Playtest is an action, not a section */
.app-logo { width: 28px; height: 28px; border-radius: 50%; margin-inline-end: 8px;
  object-fit: cover; }
/* deck page only: the logo carries the bracket, so it needs room to read */
.deck-logo { width: 52px; height: 52px; margin-inline-end: 12px; flex: none;
  border: 1px solid var(--line); box-shadow: 0 2px 10px rgba(0,0,0,.25); }
.user-chip { position: absolute; top: max(env(safe-area-inset-top), 12px); right: var(--pad);
  font-size: 12px; color: var(--muted); }
/* In the nav it's an ordinary flex item, so it can't sit on top of Playtest.
   The auto margin holds it at the right edge; after .crumb-act it doesn't need
   one, because that link's own auto margin already carries it there — two auto
   margins would split the gap and strand Playtest mid-row. */
.crumbs .user-chip { position: static; margin-left: auto; white-space: nowrap; }
.crumbs .crumb-act ~ .user-chip { margin-left: 0; }
.user-chip a { color: var(--accent); text-decoration: none; }
.user-chip a:hover { text-decoration: underline; }
/* --- the section nav on a phone ------------------------------------------- */
/* Fifteen destinations with an icon apiece is one line on a desktop and four
   wrapped rows on a 400px screen. With the heading and the mascot under them,
   the page opened on four fifths of a window's worth of chrome — which is how
   it was reported, in those words. menu.js MOVES the nav into a sheet below
   this width and moves it back above it; nothing is duplicated, and with the
   script unavailable the wrapped row is still there and still works.

   760px rather than the 560 most of this file uses: the row is what has to
   fit, and at fifteen links it stops fitting long before a phone. */
.menu-btn { display: none; }
@media (max-width: 760px) {
  .menu-btn {
    display: inline-flex; align-items: center; gap: 8px;
    /* 40px tall, which is the smallest thing this app asks a thumb to hit. */
    min-height: 40px; padding: 6px 12px; margin-inline-end: 10px;
    border: 1px solid var(--line); border-radius: 10px;
    background: transparent; color: var(--text);
    font: inherit; font-size: 14px; font-weight: 500; cursor: pointer;
  }
  .menu-btn:hover { border-color: var(--accent); color: var(--accent); }
  .menu-bars { font-size: 17px; line-height: 1; }
}
/* Two columns, because fifteen rows at a thumb's height is a sheet that
   scrolls, and a menu you have to scroll to see is the thing this replaced. */
.menu-sheet .crumbs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 12px; margin: 12px 0 0;
}
.menu-sheet .crumbs a {
  font-size: 15px; color: var(--text); gap: 10px;
  padding: 11px 6px; border-radius: 8px;
}
.menu-sheet .crumbs a:hover { background: var(--surface-2); color: var(--accent); }
.menu-sheet .crumb-ic { width: 26px; height: 26px; }
/* Support, Playtest and the account line were all holding an end of a row that
   no longer exists — their auto margins would strand them mid-grid. Full width
   instead, which is also the shape they want: two of the three are not
   destinations. */
.menu-sheet .crumbs .top-kofi,
.menu-sheet .crumbs .crumb-act,
.menu-sheet .crumbs .user-chip {
  grid-column: 1 / -1; margin: 0; padding: 11px 6px;
}
/* Reordered rather than re-listed. In the bar, Support is prepended and the
   account chip appended, which is left end and right end of one line; stacked
   into a sheet that reading order turns into "Support" first and the fifteen
   places you actually came here for underneath it. The page's own action —
   Playtest, on the deck page — goes to the top for the same reason. */
.menu-sheet .crumbs .crumb-act { order: -1; }
.menu-sheet .crumbs .top-kofi { order: 1; }
.menu-sheet .crumbs .user-chip { order: 2; }
.menu-sheet .crumbs .user-chip {
  position: static; font-size: 13px; border-top: 1px solid var(--line);
  margin-top: 6px;
}
/* Support, at the left end of the bar (footer.js puts it there). Shaped like a
   crumb so it belongs to the row, but in the accent colour rather than muted:
   it is the one link in the bar that leaves the app, and while it lived in the
   footer's copyright line nobody arrived at it except on the way out. */
.top-kofi { display: inline-flex; align-items: center; font-size: 13px;
  color: var(--accent); text-decoration: none; white-space: nowrap; }
.top-kofi:hover { text-decoration: underline; }
/* --- the mascot ----------------------------------------------------------- */
/* One bunny per page load, in the header, pokeable. bunnies.js says which and
   why. In flow rather than pinned: every free corner of this app already
   belongs to something (the announcement toast, the undo bar, the hover card),
   and a fixed mascot is one that sits on top of a card list.

   `order` rather than a margin, because auth.js appends the user chip
   asynchronously and this is appended on DOMContentLoaded — whichever lands
   first, the bunny is last in the row. An auto margin would have been the
   obvious reach and is the wrong one: .user-chip already carries one, and two
   auto margins split the gap between them rather than stacking. */
.bunny {
  /* Doubled from 48. At that size the drawings read as a beige blob: they are
     full-body bunnies with an expression, a costume and a scarf, and none of
     that survives being 48 pixels tall. The header row grows to match, which is
     the cost, and the mascot being legible is worth it. */
  width: 96px; height: 96px;
  /* No circle, no frame, no background. The drawings are full-body cut-outs on
     a transparent ground, so they want to sit ON the page rather than in
     something. A round avatar was the first thing tried and it clipped the
     ears and the feet off every one of them — the art fills its square almost
     edge to edge, and a 50% radius takes the corners of that square away.
     `contain` for the same reason: `cover` would crop rather than fit if a
     drawing ever arrives that is not square. */
  object-fit: contain;
  flex: none; order: 99;
  cursor: pointer;
}
.bunny:not([src]) { visibility: hidden; }
/* It has no frame to light up, so the hover is the bunny itself leaning in.
   Motion, and therefore off where motion is off — a repaint per pointer move is
   the single worst thing to ask of an e-ink panel, which is the same reason
   CardHover checks EInk before it draws anything. */
.bunny { transition: transform 120ms ease-out; }
.bunny:hover { transform: scale(1.12); }
@media (prefers-reduced-motion: reduce) {
  .bunny { transition: none; }
  .bunny:hover { transform: none; }
}
html.eink .bunny { transition: none; }
html.eink .bunny:hover { transform: none; }
/* The far end of the title row. `margin-inline-start` and not `margin-left`,
   for the reason the crumbs give a few rules up: there is no mirrored
   stylesheet behind this app, and a physical margin is the one thing flexbox
   does not reverse under dir="rtl" — the app logo already sat on top of its own
   title in Arabic once. */
.topbar h1 .bunny { margin-inline-start: auto; }
/* Except on the home page, whose title is centred rather than a row with two
   ends. An auto margin there would push the name off centre, so the bunny just
   sits beside it: bear logo, name, bunny. */
.home-top h1 .bunny { margin-inline-start: 10px; width: 88px; height: 88px; }

/* The home page's header is centred and carries no nav, so there is no row to
   join — pinned to the left edge instead, mirroring .user-chip on the right.
   The bar is `position: sticky`, which is what these both position against. */
.home-top .top-kofi { position: absolute; left: var(--pad);
  top: max(env(safe-area-inset-top), 12px); }

/* --- sign-in page --- */
.signin-body { display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 20px; }
.signin-card { background: var(--surface); border: 1px solid var(--line);
  border-radius: 18px; padding: 32px 28px calc(env(safe-area-inset-bottom) + 28px);
  max-width: 380px; width: 100%; text-align: center; }
.signin-logo { width: 200px; height: 200px; border-radius: 50%; object-fit: cover;
  display: block; margin: 0 auto 18px; box-shadow: 0 8px 40px rgba(200,133,59,.25); }
.signin-title { margin: 0 0 22px; font-size: 24px; font-weight: 700; }
.signin-title span { color: var(--accent); font-weight: 500; }
.signin-buttons { display: flex; flex-direction: column; gap: 10px; }
.signin-btn { display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 12px 18px; font-size: 15px; font-weight: 500; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); text-decoration: none; cursor: pointer; }
.signin-btn:hover { border-color: var(--accent); color: var(--accent); }
.signin-ic { font-weight: 700; }
.signin-note { color: var(--muted); font-size: 13px; margin: 0 0 4px; }
.signin-foot { color: var(--muted); font-size: 12px; margin: 22px 0 0; }

#searchForm { margin: 0; }
#q {
  width: 100%;
  padding: 12px 14px;
  font-size: 16px;                /* 16px prevents iOS zoom-on-focus */
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
#q:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

.hint { margin: 8px 0 0; font-size: 12px; color: var(--muted); }
.hint code {
  background: var(--surface-2);
  padding: 1px 5px;
  border-radius: 5px;
  font-size: 11px;
}

main { padding: var(--pad); max-width: var(--measure); margin: 0 auto; }
.status { color: var(--muted); text-align: center; padding: 24px 0; }

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  text-align: left;
  padding: 0;
  color: inherit;
  font: inherit;
  transition: border-color .12s ease;
}
.card:hover, .card:focus-visible { border-color: var(--accent); outline: none; }
.card .art {
  width: 100%;
  aspect-ratio: 626 / 457;        /* Scryfall art_crop ratio */
  object-fit: cover;
  background: var(--surface-2);
  display: block;
}
.card .meta { padding: 8px 10px; }
.card .name { font-size: 14px; font-weight: 500; }
.card .sub { font-size: 12px; color: var(--muted); margin-top: 2px;
             display: flex; justify-content: space-between; gap: 8px; }

.more {
  display: block;
  margin: 20px auto;
  padding: 10px 20px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 15px;
}

/* --- Detail / art-picker sheet --- */
.sheet { position: fixed; inset: 0; z-index: 20; display: flex; }
.sheet-scrim { position: absolute; inset: 0; background: rgba(0,0,0,.55); }
.sheet-panel {
  position: relative;
  margin-top: auto;
  width: 100%;
  max-height: 88vh;
  background: var(--surface);
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  border-top: 1px solid var(--line);
  padding: 16px var(--pad) calc(env(safe-area-inset-bottom) + 20px);
  overflow-y: auto;
}
@media (min-width: 720px) {
  .sheet { align-items: center; justify-content: center; }
  .sheet-panel { margin: 0; max-width: 640px; border-radius: 18px; border: 1px solid var(--line); }
}

.sheet-head { display: flex; align-items: center; justify-content: space-between; }
.sheet-head h2 { margin: 0; font-size: 18px; }
.sheet-type { margin: 2px 0 4px; color: var(--muted); font-size: 13px; }
.sheet-text { margin: 0 0 12px; font-size: 14px; line-height: 1.5; white-space: pre-wrap; }
.icon-btn {
  background: none; border: none; color: var(--muted);
  font-size: 20px; cursor: pointer; padding: 4px 8px;
}
.pick-label { font-size: 13px; color: var(--muted); margin: 4px 0 10px; font-weight: 500; }
/* The version-order toggle rides on the "Choose a printing" line rather than
   taking a row above the grid: it belongs to that list, and a row of its own
   pushes the printings further down a sheet already tall on a phone. */
#printOrder { margin-left: 8px; vertical-align: 1px; font-weight: 400; }

.print-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
}
/* A cell in a grid row is as tall as the row, but the tile inside it was only
   as tall as its own contents — so a foil chip on one printing, or the
   "cheapest" mark on another, left every star in that row at a different
   height. The column here is what makes the tile fill the cell it was given. */
.print-grid > li { display: flex; flex-direction: column; }
.print-grid > li > .print { flex: 1 1 auto; }
.print {
  background: var(--surface-2);
  border: 2px solid transparent;
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  padding: 0;
  text-align: left;
  color: inherit;
  font: inherit;
  /* A button is inline-block and sizes to its content, and the content here is
     an <img width:100%> with nothing to be 100% OF — so each tile came out as
     wide as whatever picture had loaded into it. With every printing that is
     invisible, because they are all the same shape; the moment one tile in the
     row held something else, they stopped lining up. The cell is the width. */
  display: block;
  width: 100%;
}
.print[aria-pressed="true"] { border-color: var(--accent); }
.print .art { width: 100%; aspect-ratio: 626 / 457; object-fit: cover; display: block; }
.print .meta { padding: 6px 8px; font-size: 12px; }
.print .set { text-transform: uppercase; font-weight: 500; letter-spacing: .03em; }
.print .price { color: var(--muted); }
.print .rarity-m { color: var(--accent); }
.any-print { display: flex; align-items: center; justify-content: center; min-height: 96px; }
.any-print .meta { text-align: center; }

/* Which language this printing was printed in, on the tiles that aren't
   English. The corpus is every language Wizards prints in, so one card can be
   two hundred tiles reading "5ED 349" over the same painting, and the only
   thing telling them apart used to be a watermark on the placeholder image
   that Scryfall serves when it has no localised scan.

   A chip rather than more of the set line: it is a different fact from the
   set and the number, and at 12px in a 130px tile the two run together. */
.print-lang {
  display: inline-block;
  margin-left: 4px;
  padding: 0 4px;
  border: 1px solid var(--line);
  border-radius: 4px;
  font-size: 10px;
  letter-spacing: .04em;
  color: var(--muted);
  vertical-align: 1px;
}

/* "Cheapest" used to be a word with no number beside it, over a grid of numbers
   from a different feed — so a deck line reading $9.02 had no tile under it
   saying $9.02, and no way to find out which of two hundred versions it meant.
   The "Any printing" tile now names the version it is quoting and that version
   is marked in the grid, so the two ends of the claim are both on screen. */
.print-which { color: var(--muted); font-size: 11px; }
.any-print .print-which { margin-top: 2px; }
.print-cheapest .price { color: var(--text); }
.print-cheapest .print-which { color: var(--accent); }

/* The painted token sits in the version picker beside the printings and wears
   the same tile: it is a picture of the same shape, and a row of pictures is
   what the picker is for. Only the label says it is not a printing — it has no
   set and no number to show, so it says where it came from instead. */
.bear-print .set { color: var(--accent); }

/* --- deck view (P3) --- */
.back { color: var(--muted); text-decoration: none; font-size: 14px; display: inline-block; margin-bottom: 4px; }
.export-panel { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.export-panel button {
  padding: 8px 14px; font-size: 14px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
}
.export-panel button:hover { border-color: var(--accent); }
/* The rendered tiles in the deck toolbar. Sized to the text beside them rather
   than to the source image: these are 128px renders standing in for what were
   emoji, so they have to sit on the same line as a 14px label without pushing
   the row taller. */
.tb-ic { width: 20px; height: 20px; border-radius: 4px; vertical-align: -5px;
         margin-right: 7px; }
.export-panel button, .export-panel .tt-link { display: inline-flex; align-items: center; }

/* a button whose panel is currently open */
.export-panel button.on { border-color: var(--accent); color: var(--accent); }
/* hairline between groups of actions — settings | panels | destructive */
.act-sep { width: 1px; align-self: stretch; min-height: 24px; background: var(--line); margin: 0 4px; }
/* an outbound link dressed as one of the buttons beside it */
.tt-link { display: inline-flex; align-items: center; gap: 7px; padding: 6px 14px 6px 8px;
  font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); text-decoration: none; }
.tt-link:hover { border-color: var(--accent); }
/* same medallion treatment as the crumb icons, one size up */
.tt-ic { width: 22px; height: 22px; border-radius: 5px; display: block; }

/* --- collapsible deck sections -------------------------------------------- */
/* This used to be bare text with a chevron, and it read as a heading rather
   than something you could press — so nobody pressed it. It is a button, so it
   looks like one. */
.sec-bar { display: flex; align-items: center; gap: 9px; width: 100%; margin: 0 0 10px;
  padding: 7px 11px; cursor: pointer; text-align: left;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 600; color: var(--accent); }
.sec-bar:hover { background: var(--surface); border-color: var(--accent); }
.sec-bar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the chevron gets its own disc, so it reads as the affordance it is */
.sec-chev { flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 400; color: var(--accent);
  background: var(--surface); border: 1px solid var(--line); }
.sec-bar:hover .sec-chev { border-color: var(--accent); }
.sec-label { flex: 1 1 auto; }
.sec-n { color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums;
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  padding: 1px 8px; font-size: 11px; }
/* say what pressing it does, on the side you'd read last */
.sec-act { color: var(--muted); font-weight: 400; font-size: 11px;
  letter-spacing: .03em; text-transform: uppercase; opacity: 0; }
.sec-bar:hover .sec-act, .sec-bar:focus-visible .sec-act { opacity: 1; }
.sec.collapsed > .sec-bar .sec-act { opacity: .75; }
.sec.collapsed > *:not(.sec-bar) { display: none; }
.sec.collapsed .sec-bar { margin-bottom: 0; }
/* #deckBody is bare markup, not a panel, so its bar needs the breathing room */
#deckBody > .sec-bar { margin-top: 6px; }
.cat-head { font-size: 15px; font-weight: 600; margin: 18px 0 6px; color: var(--accent); }
.cat-sub { font-size: 13px; font-weight: 500; margin: 10px 0 2px 8px; color: var(--muted); }
#hoverCard { position: fixed; z-index: 60; width: 260px; border-radius: 12px;
  box-shadow: 0 10px 32px rgba(0,0,0,.6); pointer-events: none; background: var(--surface-2); }
.cardlist { list-style: none; margin: 0; padding: 0; }
.cardlist li {
  display: flex; gap: 10px; align-items: baseline;
  padding: 6px 4px; border-bottom: 1px solid var(--line);
}
.cardlist .q { width: 24px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.cardlist .nm { flex: 1; }
.cardlist .pr { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
/* A row that takes a press has to look like one. The whole row is the target —
   the name inside it is a tenth of the width, and aiming at the word was the
   difference between the Rulings page working and appearing to do nothing. */
.cardlist li.pickable { cursor: pointer; }
.cardlist li.pickable:hover { background: var(--surface-2); }
.cardlist li.pickable:hover .nm a { color: var(--accent); }
.cardlist li[aria-current] { background: rgba(200, 133, 59, .12);
  border-left: 3px solid var(--accent); padding-left: 6px; }

/* --- salt summary (#8) --- */
.salt-panel { background: var(--surface); border: 1px solid var(--line);
              border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.salt-head { display: flex; align-items: baseline; gap: 10px; }
.salt-num { font-size: 26px; font-weight: 600; color: var(--accent);
            font-variant-numeric: tabular-nums; }
.salt-cap { color: var(--muted); font-size: 13px; }
.salt-list { list-style: none; margin: 8px 0 0; padding: 0; }
.salt-list li { display: flex; gap: 8px; align-items: baseline; padding: 3px 0; font-size: 14px; }
.salt-list .s { color: var(--accent); width: 40px; text-align: right;
                font-variant-numeric: tabular-nums; font-size: 13px; }
.salt-src { margin: 8px 0 0; font-size: 11px; color: var(--muted); }

/* --- analytics (#14) --- */
.an-panel { background: var(--surface); border: 1px solid var(--line);
            border-radius: var(--radius); padding: 14px; margin-bottom: 16px; }
.an-stats { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 6px; }
.an-stats div { display: flex; flex-direction: column; }
.an-stats b { font-size: 22px; font-weight: 600; color: var(--accent); font-variant-numeric: tabular-nums; }
.an-stats span { font-size: 12px; color: var(--muted); }
.an-grid { display: grid; gap: 18px; grid-template-columns: 1fr; margin-top: 10px; }
@media (min-width: 640px) { .an-grid { grid-template-columns: repeat(3, 1fr); } }
.an-h { font-size: 13px; font-weight: 500; color: var(--muted); margin: 4px 0 8px; }
.an-row { display: grid; grid-template-columns: 34px 1fr 28px; gap: 8px; align-items: center; margin: 3px 0; }
.an-k { font-size: 12px; color: var(--muted); text-align: right; }
.an-v { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.an-bar { background: var(--surface-2); border-radius: 4px; height: 12px; overflow: hidden; }
.an-bar > span { display: block; height: 100%; background: var(--accent); border-radius: 4px; min-width: 2px; }

/* --- combos (Commander Spellbook) --- */
/* --- test hand (inside the hands & odds panel) ---------------------------- */
.hand-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 6px 0 10px; }
.hand-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
.hand-grid button { display: block; width: 100%; padding: 0; background: none; cursor: default;
  border: 2px solid transparent; border-radius: 10px; }
.hand-grid img { width: 100%; aspect-ratio: 488/680; object-fit: cover;
  display: block; border-radius: 8px; background: var(--surface-2); }
/* while a London mulligan is owed, the cards are a choice — say so */
.hand-grid.picking button { cursor: pointer; }
.hand-grid.picking button:hover, .hand-grid.picking button:focus-visible {
  border-color: var(--accent); outline: none; }
.hand-cap { font-size: 11px; color: var(--muted); margin: 10px 0 4px; }
.hand-note { font-size: 12px; color: var(--accent); }

.combos-panel { background: var(--surface); border: 1px solid var(--line);
                border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.combos-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 6px; }
.cb-num { font-size: 26px; font-weight: 600; color: var(--accent); font-variant-numeric: tabular-nums; }
.cb-cap { color: var(--muted); font-size: 13px; }
.cb-h { font-size: 13px; color: var(--muted); font-weight: 500; margin: 12px 0 6px; }
.combo-list { list-style: none; margin: 0; padding: 0; }
.combo-list li { padding: 6px 0; border-bottom: 1px solid var(--line); display: flex;
                 flex-direction: column; gap: 2px; }
.combo-list a { color: var(--text); font-size: 14px; font-weight: 500; text-decoration: none; }
.combo-list a:hover { color: var(--accent); text-decoration: underline; }
.cb-cards { font-size: 12px; color: var(--muted); }
.cb-tmpl { color: var(--accent); }
.cb-miss { font-size: 12px; color: var(--accent); }
.combo-list.almost a { font-weight: 400; }
/* the combos panel's own <details> toggle is gone — sections fold as a group */
.cb-add { color: var(--accent); text-decoration: none; }
.cb-add:hover { text-decoration: underline; }
.cb-add[data-done] { color: var(--muted); cursor: default; text-decoration: none; }

/* --- collection + ownership --- */
.nav-link { font-size: 13px; font-weight: 400; color: var(--muted); text-decoration: none; margin-left: 8px; }
.nav-link:hover { color: var(--accent); }
.import-btn { padding: 8px 14px; font-size: 14px; color: var(--accent-ink); background: var(--accent);
             border-radius: var(--radius); cursor: pointer; font-weight: 500; }
.import-mode { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
#collSearchForm { margin: 0 0 12px; }
#collQ { width: 100%; padding: 10px 12px; font-size: 16px; color: var(--text);
         background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); }
.own-panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
             padding: 12px 14px; margin-bottom: 16px; }
.own-head { display: flex; align-items: baseline; gap: 10px; }
.own-num { font-size: 26px; font-weight: 600; color: var(--accent); font-variant-numeric: tabular-nums; }
.own-bar { background: var(--surface-2); border-radius: 4px; height: 10px; overflow: hidden; margin: 8px 0; }
.own-bar > span { display: block; height: 100%; background: var(--accent); }

/* --- offline bar --- */
.offline-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
               margin-top: 8px; font-size: 12px; color: var(--muted); }
.off-ok { color: var(--accent); }
.off-meta { color: var(--muted); }
.off-btn { padding: 4px 10px; font-size: 12px; color: var(--text);
           background: var(--surface-2); border: 1px solid var(--line);
           border-radius: 6px; cursor: pointer; }
.off-btn:hover { border-color: var(--accent); }

/* --- view controls (#12) --- */
.view-controls { display: flex; gap: 12px; flex-wrap: wrap; margin: 4px 0 14px; }
.view-controls label { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.view-controls select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; }

/* --- tokens (#16) --- */
.tokens-panel { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.token-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.token { background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.token .art { width: 100%; aspect-ratio: 488/680; object-fit: cover; display: block; background: var(--surface); }
.tk-meta { padding: 8px; }
/* The token art page. The grid and the tile are the deck panel's, because they
   are the same object seen from a different page. */
/* `.token .art` above is two classes and would win on specificity whatever the
   order here, so this has to be two as well or the words sit in the corner. */
.token .art-none { display: flex; align-items: center; justify-content: center;
  font-size: 11px; color: var(--muted); background: var(--surface); }
.tk-pip { font-style: normal; display: inline-block; width: 13px; height: 13px;
  line-height: 13px; text-align: center; border-radius: 50%; font-size: 9px;
  font-weight: 700; color: #1b1a17; background: #cfc7b4; vertical-align: middle; }
.tk-pip[data-c="W"] { background: #f6f0dc; }
.tk-pip[data-c="U"] { background: #9fd3ef; }
.tk-pip[data-c="B"] { background: #a79f9a; }
.tk-pip[data-c="R"] { background: #f0a08a; }
.tk-pip[data-c="G"] { background: #a4ceab; }
/* Said on the tile rather than left to be asked: this is the answer to "why is
   there no Scryfall version of this one". */
.tk-never { font-size: 10px; padding: 0 4px; border-radius: 4px;
  background: var(--accent); color: var(--accent-ink); }
.tk-slug { opacity: .6; font-size: 10px; }
/* A drawn face does NOT size itself from the width it is given, and assuming it
   did was the bug. `.cf` asks for 5:7, but aspect-ratio yields to content, and
   the content is a name bar, an art window, a type bar and a text box with real
   padding and real type in them. Squeezed to 84px wide it came out 84 by 310 in
   a tile 84 by 117 — spilling nearly two hundred pixels down the board and over
   whatever was beneath it.

   So it is drawn at the size it was designed for and scaled into the tile,
   rather than being asked to fold itself up. Every proportion survives, the type
   shrinks with the frame instead of overflowing it, and the answer cannot drift
   from the tile because both come from --pt-w.

   The two numbers are tied by hand because scale() needs a unitless factor and
   dividing one length by another is not something every browser will do in
   calc(). If --pt-w changes, --pt-face-k is 84/300 of it. */
.pt-face {
  position: absolute; inset: 0; overflow: hidden;
  /* Nothing here is clickable — the tile underneath takes every press, exactly
     as it does for the <img> a printed card gets. */
  pointer-events: none;
}
.pt-face .cf {
  width: 300px; max-width: none;
  transform: scale(var(--pt-face-k, .28));
  transform-origin: top left;
}
/* The gallery has no fixed height, so a face there is free to be as tall as it
   is and the tile grows with it. Only the sandbox has a box to fit. */
.tk-face { width: 100%; }
.tk-face .cf { width: 100%; }
/* The prompt, as written. Wrapped rather than scrolled sideways: it is one long
   sentence and reading it is the only thing this box is for. */
.tk-prompt { white-space: pre-wrap; word-break: break-word; margin: 0 0 12px;
  font: inherit; font-size: 12px; line-height: 1.5; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px; max-height: 50vh; overflow: auto; }
.tk-why { margin-left: 6px; }
/* A file input with nothing to show is not a control. The label is the button
   and the input behind it never renders. */
.tk-pick { display: inline-block; margin-top: 6px; padding: 3px 8px; font-size: 11px;
  border: 1px solid var(--line); border-radius: 6px; cursor: pointer; color: var(--text); }
.tk-pick:hover { border-color: var(--accent); color: var(--accent); }
.tk-name { font-size: 13px; font-weight: 500; }
.tk-src { font-size: 11px; color: var(--muted); margin: 2px 0 6px; }
/* which printing this tile is showing — a button when there's a choice to make */
.tk-ver, .tk-ver-1 { display: inline-block; font-size: 11px; color: var(--muted);
  margin-bottom: 6px; letter-spacing: .02em; }
.tk-ver { background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 8px; cursor: pointer; font-family: inherit; }
.tk-ver:hover { color: var(--text); border-color: var(--accent); }
.tk-buy { display: flex; gap: 8px; }
.tk-buy a { font-size: 12px; color: var(--accent); text-decoration: none; }
.tk-buy a:hover { text-decoration: underline; }

/* --- preconstructed decks: its own page --- */
.precon-pointer a { display: inline-flex; align-items: center; gap: 5px; color: var(--accent); }
.precon-pointer .crumb-ic { width: 18px; height: 18px; border-radius: 4px; }
.precon-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
/* a product is a box on a shelf, so it gets a tile rather than a table row */
.pc-tile { display: flex; flex-direction: column; gap: 3px; width: 100%; height: 100%;
  padding: 11px 13px; cursor: pointer; text-align: left; font-family: inherit;
  color: var(--text); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); }
.pc-tile:hover { border-color: var(--accent); background: var(--surface-2); }
.pc-name { font-size: 14px; font-weight: 600; line-height: 1.25; }
.pc-sub { font-size: 12px; color: var(--muted); }
.pc-foot { display: flex; justify-content: space-between; gap: 8px; margin-top: auto;
  padding-top: 8px; font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums; }

/* --- preconstructed decks (shared controls) --- */
.precon-box { margin: 0 0 18px; padding: 12px 14px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); }
.precon-box .cat-head { margin-top: 0; }
.precon-box .hint { margin: 0 0 10px; }
.precon-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.precon-row label { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.precon-row select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; }
.precon-row input[type="search"] { flex: 1 1 240px; min-width: 180px; padding: 8px 10px;
  font-size: 16px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); }
.precon-box .ac-results { position: static; margin-top: 8px; max-height: 340px; }
/* the count line sits between the controls and the list it describes */
.precon-box #preconCount { margin: 8px 0 0; }
.precon-box .more { margin-top: 8px; }
.precon-pick { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 10px;
  padding-top: 10px; border-top: 1px solid var(--line); }
.precon-pick-info { display: flex; flex-direction: column; flex: 1 1 220px; }
.precon-box details { margin-top: 10px; }
.precon-box summary { cursor: pointer; }
.precon-box .cardlist { max-height: 320px; overflow-y: auto; margin-top: 6px; }

/* --- wishlists (#2) --- */
.wl-new { display: flex; gap: 8px; margin: 8px 0 0; }
.wl-new input { flex: 1; padding: 8px 10px; font-size: 16px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); }

/* --- inline row editing (decks + wishlists) --- */
.row-step { display: flex; align-items: center; gap: 2px; }
.row-btn {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px;
  color: var(--text); font-size: 13px; line-height: 1; padding: 4px 7px; cursor: pointer;
}
.row-btn:hover { border-color: var(--accent); }
.row-del { color: var(--muted); border-color: transparent; background: none; }
.row-del:hover { color: var(--accent); }
.got-btn { font-size: 11px; white-space: nowrap; }
.cardlist .nm a, .cardlist a.nm { color: var(--text); text-decoration: none; }
.cardlist .nm a:hover, .cardlist a.nm:hover { color: var(--accent); }
.danger:hover { border-color: var(--bad); color: var(--bad); }

/* --- deck actions + add-card search --- */
.bracket-pick { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.bracket-pick select, #acBoard {
  font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px;
}
.add-card { position: relative; display: flex; gap: 8px; align-items: center; margin: 0 0 14px; }
.add-card input {
  flex: 1; padding: 10px 12px; font-size: 16px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius);
}
.add-card input:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.ac-results {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 15;
  list-style: none; margin: 4px 0 0; padding: 4px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,.4); max-height: 320px; overflow-y: auto;
}
.ac-results button {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  background: none; border: none; color: var(--text); font: inherit;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
}
.ac-results button:hover, .ac-results button:focus-visible { background: var(--surface-2); outline: none; }
.ac-nm { font-size: 14px; font-weight: 500; }
.ac-sub { flex: 1; font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ac-pr { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* --- card detail (deck edit sheet + wishlist sheet) --- */
.cd-detail { display: flex; gap: 14px; align-items: flex-start; margin: 8px 0 14px; }
/* perspective makes the flip read as a card turning over rather than squashing */
.cd-figure { position: relative; width: 168px; max-width: 42%; flex: none; perspective: 900px; }
.cd-figure .cd-img { backface-visibility: hidden; will-change: transform; }
.cd-img { width: 168px; max-width: 42%; border-radius: 9px; display: block; background: var(--surface-2); }
.cd-figure .cd-img { width: 100%; max-width: none; }
.cd-info { flex: 1; min-width: 0; }

/* --- tategaki (縦書き) ---
   Japanese set the way it is set in a novel: columns top to bottom, advancing
   right to left. Switched on in Settings (Locale.setVertical) and applied only
   to a block app.js has marked data-tate — text a card was really printed with
   in Japanese, never the interface around it.

   The axes swap in vertical-rl, which is the thing to hold on to when editing
   this: `height` is now the line length and `width` is how many columns deep
   the block runs. So capping the HEIGHT is what makes the text wrap into
   columns at all, and overflow runs leftwards.

   text-orientation: mixed keeps Latin lying on its side, which is how a
   Japanese book prints an English word. text-combine-upright stands short runs
   of digits back up, which is how it prints "2/2" and a year. */
html.tategaki [data-tate] {
  writing-mode: vertical-rl;
  text-orientation: mixed;
  text-combine-upright: digits 2;
  max-height: min(58vh, 340px);
  overflow-x: auto;
  overflow-y: hidden;
  line-height: 1.75;
}
/* The type line is the first element, so in a right-to-left block flow it is
   the rightmost column — where a Japanese reader starts. The gap between it
   and the rules text is therefore to its left, and stays a physical margin:
   the logical properties resolve against the *inline* axis here, which is now
   vertical, and would put the space above it instead. */
html.tategaki [data-tate] .sheet-type { margin: 0 0 0 12px; }
html.tategaki [data-tate] .sheet-text { margin: 0; }
.cd-info .sheet-type { margin-top: 0; }
@media (max-width: 420px) { .cd-img, .cd-figure { width: 132px; } }

/* format filter under the search box */
.fmt-bar { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; flex-wrap: wrap; }
/* the sort's direction control sits with the dropdown it belongs to */
.fmt-bar #sortDir { padding: 6px 10px; font-size: 13px; }
/* The result count is standing text under the search bar, not a one-off
   "Searching..." message, so it doesn't get the full status block's padding. */
.status.count { padding: 10px 0 2px; text-align: left; font-size: 13px; }
.fmt-bar label { font-size: 12px; color: var(--muted); }
.fmt-bar select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; }
.fmt-bar select:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* --- jump-to-section rail + back to top --- */
/* The rail is fixed, so it needs a gutter of its own: main is a centred 1100px
   column and would otherwise sit underneath it. Hidden on narrow screens, where
   the page is one column anyway and back-to-top does the job. */
.deck-nav {
  position: fixed; left: 10px; top: 50%; transform: translateY(-50%);
  z-index: 15; display: none; flex-direction: column; gap: 1px;
  width: 128px; max-height: 82vh; overflow-y: auto;
  padding: 8px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
}
.deck-nav a {
  font-size: 12px; color: var(--muted); text-decoration: none;
  padding: 5px 8px; border-radius: 7px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.deck-nav a:hover, .deck-nav a:focus-visible { background: var(--surface-2); color: var(--text); outline: none; }
.deck-nav a.on { color: var(--accent); background: var(--surface-2); font-weight: 600; }
@media (min-width: 1000px) {
  body.has-deck-nav .deck-nav { display: flex; }
  body.has-deck-nav { padding-left: 150px; }
}

.to-top {
  position: fixed; right: 16px; bottom: max(env(safe-area-inset-bottom), 16px);
  z-index: 16; width: 42px; height: 42px; border-radius: 50%; cursor: pointer;
  font-size: 18px; line-height: 1; color: var(--text);
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: 0 4px 14px rgba(0,0,0,.45);
}
.to-top:hover, .to-top:focus-visible { color: var(--accent); border-color: var(--accent); outline: none; }

/* side decks (dungeons / attractions / stickers) — shown only when in use */
.side-panel { margin: 14px 0; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface); }
.side-panel .cat-head { margin-top: 0; }
.side-panel .add-card { margin: 8px 0 6px; }

/* flip control for double-faced cards — sits over the bottom of the art */
.flip-btn {
  position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%);
  font-size: 11px; font-weight: 600; white-space: nowrap;
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  color: var(--text); background: rgba(0,0,0,.72);
  border: 1px solid var(--line);
}
.flip-btn:hover, .flip-btn:focus-visible { background: rgba(0,0,0,.9); outline: none; border-color: var(--accent); }

/* --- legality flags --- */
.chip { display: inline-block; font-size: 10px; font-weight: 600; line-height: 1.4;
  padding: 0 6px; border-radius: 7px; margin-left: 6px; vertical-align: 1px;
  text-transform: uppercase; letter-spacing: .03em; }
/* The ground is mixed from the signal colour and the panel it sits on rather
   than written down, because it has to be a dark red on a dark theme and a pale
   one on paper - the literal here was a near-black brown, which on Foolscap was
   a bruise. The literal stays in front of it as the fallback for a browser with
   no color-mix; it is the value this chip had for two years. */
.chip-bad { background: #4a2320; background: color-mix(in srgb, var(--bad) 18%, var(--surface));
  color: var(--bad); border: 1px solid color-mix(in srgb, var(--bad) 45%, var(--surface)); }
.chip-gc { background: #443a1e; background: color-mix(in srgb, var(--warn) 18%, var(--surface));
  color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, var(--surface)); }
.legality-panel { background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--bad) 45%, var(--surface));
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 14px; }
.leg-row { margin: 4px 0; font-size: 13px; }
.leg-bad { color: var(--bad); }
/* A caution, not a violation. Zirda's condition is the one that can't be
   settled from structured data, and a check that says "I couldn't prove this"
   must not read the same as one that says "this is wrong". */
.leg-warn { color: var(--warn); }
.leg-gc { color: var(--warn); }
.leg-row b { font-weight: 600; }
.ac-lock { font-size: 12px; color: var(--muted); display: flex; align-items: center;
  gap: 5px; white-space: nowrap; }

/* --- bulk add page --- */
.bulk-target { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; margin: 0 0 8px; }
.bulk-target label { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.bulk-target select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; max-width: 240px; }
.add-li { position: relative; display: flex; flex-direction: column; }
.add-tile { position: relative; flex: 1; }
.add-tile.added { border-color: var(--accent); }
/* Reads as a control, not a caption. It was 11px muted grey saying "versions",
   which is why nobody found it. */
.ver-btn { margin-top: 4px; font-size: 12px; padding: 5px 8px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 7px;
  cursor: pointer; font-family: inherit; width: 100%; }
.ver-btn:hover { border-color: var(--accent); color: var(--accent); }
/* a version has been chosen — the tile will add that printing */
.ver-btn.ver-set { border-color: var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--surface-2)); }

/* --- the foreign-language promos, in the settings language section ---
   Wraps rather than scrolls: six is few enough to see at once on a desktop and
   two rows of three on a phone, and a strip that scrolls sideways hides the
   last two from anybody who does not think to push it. */
.promo-langs { list-style: none; display: flex; flex-wrap: wrap; gap: 10px;
  margin: 8px 0 12px; padding: 0; }
.promo-langs li { width: 96px; }
.promo-langs button { display: block; width: 100%; padding: 0; border: 0;
  background: none; color: inherit; font: inherit; text-align: center;
  cursor: pointer; border-radius: 8px; }
.promo-langs button:focus-visible { outline: 2px solid var(--accent);
  outline-offset: 3px; }
.promo-langs img { width: 96px; height: 134px; object-fit: cover;
  border-radius: 6px; display: block; background: var(--surface-2);
  transition: transform 120ms ease; }
.promo-langs button:hover img { transform: translateY(-2px); }
/* The endonym is the label, because the point of the note is what the card
   itself says. The English name is underneath it and smaller — you need it to
   know what you are looking at, and not before.
   `-nm` is not decoration: i18n.js skips any element whose class carries it,
   and Ελληνική is already in its own language. The gloss below it has no
   such marker on purpose, so it arrives in the reader's. */
.promo-lang-nm { display: block; font-size: 13px; margin-top: 5px;
  line-height: 1.25; }
.promo-lang-en { display: block; font-size: 11px; color: var(--muted); }

/* --- EDHREC links --- */
.edh-links { margin: 4px 0 0; font-size: 12px; color: var(--muted); }
.edh-links a { color: var(--accent); text-decoration: none; }
.edh-links a:hover { text-decoration: underline; }

/* --- rulings --- */
.rul-list { list-style: none; margin: 6px 0 0; padding: 0; }
.rul-list li { font-size: 13px; line-height: 1.5; padding: 6px 0;
  border-bottom: 1px solid var(--line); }
.rul-date { display: inline-block; color: var(--accent); font-size: 11px;
  font-variant-numeric: tabular-nums; margin-right: 8px; }
.added-badge { position: absolute; top: 6px; right: 6px; background: var(--accent);
  color: var(--accent-ink); font-size: 12px; font-weight: 700; padding: 1px 7px;
  border-radius: 10px; }
.recent-box { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 14px; }
.recent-list { list-style: none; margin: 6px 0 0; padding: 0; display: flex;
  gap: 6px 12px; flex-wrap: wrap; }
.recent-list li { display: flex; align-items: center; gap: 4px; font-size: 13px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  padding: 2px 4px 2px 10px; }

/* --- category assign mode --- */
#assignBtn.on { border-color: var(--accent); color: var(--accent); }
.assign-bar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--accent); border-radius: var(--radius);
  padding: 10px 12px; margin: 0 0 14px; }
.assign-bar input { flex: 1; min-width: 180px; padding: 8px 10px; font-size: 16px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 8px; }
.assign-bar .hint { flex-basis: 100%; margin: 0; }
.cardlist li.in-cat { background: rgba(200, 133, 59, .12); border-left: 3px solid var(--accent);
  padding-left: 6px; }
.card.in-cat { border-color: var(--accent); }

/* --- remove mode ---
   A marked card reads as marked at a glance in either view, and deliberately
   does not look like the assign-mode highlight: one of these adds a label and
   the other is about to delete the card, so telling them apart matters more
   than a consistent accent. */
.cardlist li.picked { background: rgba(190, 60, 60, .16); border-left: 3px solid #b64545;
  padding-left: 6px; }
.card.picked { border-color: #b64545; box-shadow: 0 0 0 2px rgba(190, 60, 60, .35); }
.pick-all { margin-left: 8px; font: inherit; font-size: 11px; font-weight: 500;
  padding: 1px 8px; border-radius: 999px; cursor: pointer; vertical-align: middle;
  color: var(--muted); background: none; border: 1px solid var(--line); }
.pick-all:hover { color: var(--text); border-color: var(--accent); }
.pick-all.on { color: #fff; background: #b64545; border-color: #b64545; }
.pick-count { font-size: 13px; color: var(--muted); min-width: 120px; }
.undo-bar { border-color: #b64545; }
.undo-bar #undoMsg { flex: 1; min-width: 140px; font-size: 13px; }

/* --- card edit sheet --- */
.edit-rows { display: flex; flex-direction: column; gap: 12px; margin: 8px 0 16px; }
.edit-row { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 14px; color: var(--muted); }
.edit-row select, .edit-row input[list], .edit-row input[type="number"] {
  font-size: 15px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px;
}
.edit-row input[list] { flex: 1; max-width: 60%; }
.foil-row { justify-content: flex-start; }
.stepper { display: flex; align-items: center; gap: 6px; }
.stepper input { width: 58px; text-align: center; }
.stepper button {
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px;
  color: var(--text); font-size: 16px; padding: 6px 12px; cursor: pointer;
}
.stepper button:hover { border-color: var(--accent); }
.edit-acts { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* --- primer editor + deck import --- */
.primer-edit, .import-box {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; margin-bottom: 16px;
}
.primer-edit textarea, .import-box textarea {
  width: 100%; font: 13px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 8px; padding: 10px 12px; resize: vertical;
}
.primer-edit textarea:focus, .import-box textarea:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.primer-acts { display: flex; gap: 10px; align-items: center; margin-top: 10px; flex-wrap: wrap; }

/* --- flip group ----------------------------------------------------------- */
.flip-panel { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.flip-panel .cb-cap { display: block; margin-bottom: 10px; max-width: 70ch; }
.flip-row { display: flex; gap: 10px; flex-wrap: wrap; }
/* each side is a card-sized target, and the one showing looks pressed rather
   than merely highlighted — you should be able to tell at a glance which deck
   is on the table */
.flip-side { display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  min-width: 190px; padding: 10px 14px; cursor: pointer; text-align: left;
  font-family: inherit; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); }
.flip-side:hover:not(.on) { border-color: var(--accent); }
.flip-side.on { border-color: var(--accent); background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--accent); cursor: default; }
.flip-side[disabled] { opacity: .6; cursor: progress; }
.flip-name { font-size: 14px; font-weight: 600; }
.flip-cmd { font-size: 12px; color: var(--muted); }
.flip-state { font-size: 11px; color: var(--muted); letter-spacing: .03em;
  text-transform: uppercase; margin-top: 4px; }
.flip-side.on .flip-state { color: var(--accent); }
/* the side is a card holding controls now, not one big button */
.flip-pick { display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  width: 100%; padding: 0; background: none; border: 0; cursor: pointer;
  text-align: left; font-family: inherit; color: inherit; }
.flip-side.on .flip-pick { cursor: default; }
.flip-lists { display: flex; gap: 6px; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--line); width: 100%; }
.flip-list-btn { flex: 1; padding: 5px 8px; font-size: 11px; cursor: pointer;
  color: var(--muted); background: var(--surface); border: 1px solid var(--line);
  border-radius: 6px; font-family: inherit; }
.flip-list-btn:hover { color: var(--text); border-color: var(--accent); }

/* the list sheet */
.fl-panel .fl-sum { margin: 0 0 10px; }
.fl-list { max-height: 52vh; overflow-y: auto; }
.fl-own { font-size: 11px; color: var(--muted); margin-left: auto; }
.fl-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.fl-acts select { font-size: 13px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; }

/* Printing a list: the sheet becomes the page. Everything else stands aside
   rather than being screenshotted around. */
@media print {
  body.printing-list > *:not(#flipListSheet) { display: none !important; }
  body.printing-list #flipListSheet { position: static; display: block; }
  body.printing-list .sheet-scrim, body.printing-list .fl-acts,
  body.printing-list .icon-btn { display: none !important; }
  body.printing-list .sheet-panel { max-height: none; box-shadow: none; border: 0;
    background: #fff; color: #000; max-width: none; width: auto; }
  body.printing-list .fl-list { max-height: none; overflow: visible; columns: 2; }
  body.printing-list .fl-list li { break-inside: avoid; border-color: #ddd; }
  body.printing-list .nm, body.printing-list .q, body.printing-list .pr,
  body.printing-list .fl-sum, body.printing-list h2 { color: #000; }
}

.flip-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
/* the "which side survives" step: destructive, so it looks it */
.flip-off { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.flip-off .leg-row { margin: 0 0 10px; }
.flip-off .flip-side { border-color: var(--bad, #d0503b); }
.flip-off .flip-side:hover { background: var(--surface-2); }

/* --- the primer, rendered ------------------------------------------------- */
.primer-panel { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 18px 18px; margin-bottom: 16px; }
/* the section bar carries the title, so this row holds only the Edit button */
.pr-head { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
/* A primer is prose: a reading measure, and room between the parts. */
.primer-doc { max-width: 68ch; font-size: 14px; line-height: 1.65; color: var(--text); }
.primer-doc h2 { font-size: 17px; margin: 22px 0 6px; }
.primer-doc h3 { font-size: 15px; margin: 18px 0 4px; }
.primer-doc h4, .primer-doc h5 { font-size: 13px; margin: 14px 0 4px;
  text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.primer-doc > :first-child { margin-top: 0; }
.primer-doc p { margin: 0 0 10px; }
.primer-doc ul, .primer-doc ol { margin: 0 0 12px; padding-left: 22px; }
.primer-doc li { margin-bottom: 5px; }
.primer-doc strong { color: var(--text); font-weight: 600; }
.primer-doc code { font: 12px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 5px; }
.primer-doc pre { background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 8px; padding: 10px 12px; overflow-x: auto; margin: 0 0 12px; }
.primer-doc pre code { background: none; border: 0; padding: 0; }
.primer-doc blockquote { margin: 0 0 12px; padding: 2px 0 2px 12px;
  border-left: 3px solid var(--line); color: var(--muted); }
.primer-doc hr { border: 0; border-top: 1px solid var(--line); margin: 18px 0; }
.primer-doc a { color: var(--accent); }
/* the live preview inside the editor */
.primer-edit .primer-doc { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 12px; }

/* --- rulings -------------------------------------------------------------- */
.ruling-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0 4px; }
.ruling-acts .off-btn { text-decoration: none; }
/* Space on both sides, not just above. A box that only carries margin-top
   leans on whatever follows it to leave room, and on the trade page what
   follows is `.grid`, which has `margin: 0` — so the moment the binder had
   cards in it the tiles sat flush against the promo box's bottom border and
   read as tucked underneath it. Between two ruling boxes the two margins
   collapse to one 16px gap, so this changes nothing on the pages that stack
   them. */
.ruling-box { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin: 16px 0; }
.ruling-head { display: flex; gap: 14px; align-items: flex-start; }
.ruling-head .cat-head { margin: 0 0 2px; }
.ruling-art { width: 140px; border-radius: 8px; flex: 0 0 auto; }
.ruling-row { font-size: 14px; line-height: 1.55; color: var(--text);
  margin: 10px 0; padding-top: 10px; border-top: 1px solid var(--line); }
.ruling-date { color: var(--muted); font-size: 12px; margin-inline-end: 8px;
  font-variant-numeric: tabular-nums; }
@media (max-width: 560px) {
  .ruling-head { flex-direction: column; }
  .ruling-art { width: 100%; max-width: 220px; }
}

/* --- trade ---------------------------------------------------------------- */
/* the ⇄ toggle on a collection row: quiet until it's on */
.trade-btn { color: var(--muted); border-color: transparent; background: none; }
.trade-btn:hover { color: var(--accent); border-color: var(--accent); }
.trade-btn.on { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }

.trade-list { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 18px; }
.trade-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.trade-head .cat-head { margin: 0 auto 0 0; }
.trade-total { font-size: 16px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums; }
.trade-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }

/* --- a scanned line, before it is owned ------------------------------------
   One row per card the photo read. Wraps rather than scrolls, because this is
   read on a phone standing over the cards it is about. */
.scan-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 10px; border-bottom: 1px solid var(--line);
}
.scan-row:last-child { border-bottom: 0; }
.scan-name { flex: 1 1 200px; min-width: 0; }
/* The edition. Given room, because "which printing is this" is the one thing
   the photograph could not answer and the whole reason this review exists. */
.scan-print { flex: 0 1 300px; min-width: 0; max-width: 100%; }
.scan-unsure {
  font-style: normal; font-size: 11px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--accent); opacity: .85;
}
/* A name that matched no card. Marked rather than removed: it is far more
   likely a misread than a card nobody printed, and knowing which line it was
   is the difference between fixing it and scanning the shelf again. */
.scan-miss { opacity: .8; }
.scan-miss .scan-name { color: var(--muted); font-style: italic; }

/* --- format rules --------------------------------------------------------- */
.rule-grid { display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }
.rule-card { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; }
.rule-card h2 { margin: 0 0 10px; font-size: 16px; font-weight: 600; }
/* label/value pairs: the four questions you ask about any format */
.rule-grid-in { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px;
  font-size: 13px; align-items: baseline; }
.rule-k { color: var(--muted); }
.rule-v { color: var(--text); }
.rule-pool, .rule-note { font-size: 13px; color: var(--muted); line-height: 1.5;
  margin: 10px 0 0; }
.rule-pool b { color: var(--text); font-weight: 600; }
.rule-links { display: flex; gap: 12px; flex-wrap: wrap; margin: 10px 0 0; font-size: 12px; }
.rule-links a { color: var(--accent); text-decoration: none; }
.rule-links a:hover { text-decoration: underline; }
.rule-asof { margin: 6px 0 0; font-size: 11px; color: var(--muted); opacity: .7; }

/* --- banned & restricted -------------------------------------------------- */
.fmt-note { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 16px; }
.fmt-note p { margin: 0 0 6px; font-size: 14px; color: var(--muted); line-height: 1.5; }
.fmt-note p:last-child { margin-bottom: 0; }
.fmt-note b { color: var(--text); }
.bl-bar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 8px 0 4px; }
.bl-bar select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; max-width: 60%; }

/* --- EDHREC picks on the bulk-add page ------------------------------------ */
.edh-box { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.edh-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.edh-head .cb-h { margin: 0 auto 0 0; }
.edh-cat { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 4px; }
.edh-cat > summary { cursor: pointer; padding: 6px 0; font-size: 14px; font-weight: 600; }
.edh-cat > summary::marker { color: var(--muted); }
.edh-cat .grid { margin-top: 10px; }
.edh-stat { font-size: 11px; color: var(--muted); }
/* already in the deck — still addable (a second copy of a basic, say), just
   clearly not a suggestion you need to act on */
.edh-have .add-tile { outline: 1px solid var(--accent); }
.edh-have .art { opacity: .5; }

/* --- wishlists detail --- */
.wl-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.wl-head .cat-head { margin-right: auto; }
.wl-fill { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0; }
.wl-fill select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; max-width: 60%; }
.wl-buyall { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 10px 0; }

/* Per-card vendor compare. Replaced a plain TCG/CK pair of name searches and a
   single price: each chip now carries that store's price for the printing this
   row is about, and links straight to it. The cheapest of the three is marked,
   and a store with nothing in stock shows a dash rather than a stale number. */
.wl-prices { display: flex; gap: 6px; align-items: baseline; }
.vp { font-size: 11px; color: var(--muted); text-decoration: none; white-space: nowrap;
      border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px;
      font-variant-numeric: tabular-nums; }
.vp b { font-weight: 600; opacity: .7; margin-inline-end: 2px; }
.vp:hover { border-color: var(--accent); color: var(--accent); }
.vp.best { color: var(--text); border-color: var(--accent); }
.vp.best b { opacity: 1; color: var(--accent); }
.vp-out { opacity: .45; }
/* A price for a DIFFERENT printing of the same card — only the local shop can
   produce one, because it is the only vendor joined by card rather than by
   printing (see the LATERAL in wishlists.py). Dashed rather than dimmed: the
   number is real and worth reading, it just answers a slightly different
   question from the chips beside it, and the asterisk in the text is what
   survives being screenshotted or read aloud. */
.vp-other { border-style: dashed; }
.own-acts { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.own-acts select { font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; max-width: 60%; }

/* --- playtest sandbox --- */
.pt-body { overscroll-behavior: none; }
.pt-bar { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 12px;
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding: max(env(safe-area-inset-top), 10px) 14px 10px; }
.pt-name { font-size: 15px; font-weight: 500; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-life { display: flex; align-items: center; gap: 8px; }
.pt-life b { font-size: 20px; color: var(--accent); font-variant-numeric: tabular-nums; min-width: 30px; text-align: center; }
.pt-btn { padding: 6px 12px; font-size: 13px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 8px; cursor: pointer; }
.pt-btn:hover { border-color: var(--accent); }
/* The two pickers in the playtest toolbar. Same shape as the deck page's
   bracket pick, so a dropdown reads as a dropdown on both. */
.pt-pick { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pt-pick select {
  padding: 6px 10px; font-size: 13px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); max-width: 200px;
}
.pt-pick select:hover { border-color: var(--accent); }
.pt-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: 10px 14px;
  background: var(--surface); border-bottom: 1px solid var(--line); position: sticky; top: 52px; z-index: 4; }
.pt-info { font-size: 12px; color: var(--muted); margin-left: auto; }
/* Kept together and kept small: these are two facts about the game rather than
   two things you do to it, so they read as a setting and not as an action. */
.pt-seat { display: inline-flex; gap: 4px; }
.pt-seat select { font: inherit; font-size: 11px; padding: 2px 4px; border-radius: 6px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line); }
.pt-main { padding: 10px 14px calc(env(safe-area-inset-bottom) + 20px); max-width: 1100px; margin: 0 auto; }
.pt-zone { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 8px 10px; margin-bottom: 10px; }
.pt-zone.battlefield { min-height: 180px; }
/* The three rows of the board. Separated by a hairline rather than by space:
   the point is that they are three passes over one battlefield, not three
   zones, and a gap wide enough to read as a divider says the wrong thing.
   Lands last, so the row you tap from all game is nearest the hand. */
.pt-row-creatures, .pt-row-other, .pt-row-lands { padding: 6px 0; }
.pt-row-other, .pt-row-lands { border-top: 1px solid var(--line); }
/* A flex row so a control can sit at the far end of it. Baseline-aligned:
   the label and the tip are text and should sit on the same line as each
   other, whatever height a button next to them happens to be. */
.pt-zone-label { display: flex; align-items: baseline; gap: 8px;
  font-size: 11px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .05em; margin-bottom: 6px; }
.pt-zone-tip { text-transform: none; letter-spacing: 0; opacity: .75; margin-left: 6px; }
.pt-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
/* A tile is a card shape, whether or not anybody has a picture of the card.
   Without this a name-plate is as tall as the rules text it holds, so a row
   of art-less cards is ragged, nothing lines up, and the caption along the
   bottom of a tall one floats level with the middle of its neighbours —
   which is what "messed up" looked like. */
.pt-card { position: relative; width: var(--pt-w, 84px); aspect-ratio: 488/680;
  /* A flex item's min-height is auto, which means min-content — so without
     this the plate's rules text wins over the ratio and the tile grows anyway.
     The plate clips its own overflow, so shrinking to the card shape is safe. */
  min-height: 0; align-self: flex-start;
  cursor: pointer; transition: transform .12s; }
/* Cropped to the card's shape rather than left at its own. A printed card face
   is already 488x680 so this is a no-op for one; the painted token art is 4:3
   and without this it sat short in a tile sized for a card, with the row's
   height set by whichever tile happened to hold a real card. */
.pt-card img { width: 100%; aspect-ratio: 488/680; object-fit: cover;
  border-radius: 5px; display: block; background: var(--surface-2); }
.pt-card.tapped { transform: rotate(90deg); margin: 20px 24px; }
/* A flip card has one printed face and both halves' boxes on it, so turning it
   over IS a rotation — that is what you do to the cardboard. The picture turns
   and nothing else does: the counters, the badges and the pick strips have to
   stay the right way up to be read, and a tapped flip card is then sideways and
   upside down, which is also what the cardboard does. */
.pt-card.upended img { transform: rotate(180deg); }
/* The P/T total moved to the left corner so a card can carry both: a Gideon is
   a planeswalker with a loyalty badge that is also a creature with counters on
   it, and two badges in one corner is one badge nobody can read. */
.pt-counter { position: absolute; bottom: 4px; left: 4px; background: var(--accent);
  color: var(--accent-ink); font-size: 11px; font-weight: 600; padding: 1px 5px; border-radius: 8px; }
/* Loyalty, in the corner it is printed in and at the weight it is printed at.
   Dark with a pale number, like the shield on the card — deliberately not the
   accent pill, so a glance tells loyalty from a pile of +1/+1 counters. */
.pt-loyalty { position: absolute; bottom: 3px; right: 3px; min-width: 21px;
  padding: 1px 4px; border-radius: 5px; text-align: center;
  background: #0d0c0a; color: #f1ead6; border: 1px solid rgba(255, 255, 255, .55);
  font-size: 13px; font-weight: 700; line-height: 1.25;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .6); }
/* Counters, drawn as the three different things they are. The P/T total keeps
   the badge that used to be the only one — it is what changes the creature —
   and the rest sit in a row along the bottom, where they cover the art rather
   than the name plate. */
.pt-ctr-row { position: absolute; left: 2px; right: 2px; bottom: 20px;
  display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; }
/* Clipped by the tile rather than by the string. A name cut mid-word with no
   ellipsis is a different word -- "1que" for a quest counter -- and the tooltip
   nobody hovers is where the truth was. max-width is per chip so two counters
   still fit side by side on an 84px tile. */
.pt-ctr-kw, .pt-ctr-n { font-size: 8.5px; line-height: 1.3; padding: 0 3px;
  border-radius: 4px; text-transform: lowercase; white-space: nowrap;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
/* A keyword counter is the ability it grants, so it is drawn as a word rather
   than as a tally. A named counter is a number and a name, because "3 charge"
   is the whole of what it is. */
.pt-ctr-kw { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.pt-ctr-n { background: rgba(0,0,0,.66); color: #e8e2d2; border: 1px solid rgba(255,255,255,.18); }
/* The chip row is a control, not a label: it is how you get at the numbers. */
.pt-ctr-row { border: 0; background: none; padding: 0; cursor: pointer; }
/* The strip that replaces the tile while a counter is being moved. Same shape
   and same reasoning as the loyalty one: the number changes every turn, and the
   card panel is a long way to go for it. */
.pt-ctr-pick { position: absolute; inset: 0; z-index: 4; display: flex;
  flex-direction: column; align-items: stretch; justify-content: center; gap: 3px;
  padding: 4px; background: rgba(0,0,0,.82); }
.pt-ctr-set { display: flex; align-items: center; justify-content: space-between; gap: 3px; }
.pt-ctr-set b { flex: 1; min-width: 0; text-align: center; font-size: 10px;
  color: #f2ecdc; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-ctr-set b i { font-style: normal; opacity: .72; margin-left: 3px; }
.pt-ctr-mini { width: 18px; height: 18px; flex: 0 0 auto; border-radius: 5px;
  border: 1px solid rgba(255,255,255,.28); background: rgba(255,255,255,.1);
  color: #f2ecdc; font: inherit; font-size: 12px; line-height: 1; cursor: pointer; }
.pt-ctr-mini:hover:not(:disabled) { background: var(--accent); color: var(--accent-ink); }
.pt-ctr-mini:disabled { opacity: .3; cursor: default; }
.pt-ctr-more { margin-top: 2px; padding: 2px 4px; border-radius: 5px; font: inherit;
  font-size: 9px; cursor: pointer; border: 1px solid rgba(255,255,255,.28);
  background: none; color: #cfc7b4; }
.pt-ctr-more:hover { color: var(--accent); border-color: var(--accent); }
.pt-card.counting .pt-ctr-row { display: none; }
.pt-ctr-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.pt-ctr-line b { min-width: 18px; text-align: center; font-variant-numeric: tabular-nums; }
.pt-ctr-add { display: flex; gap: 6px; margin: 10px 0; }
.pt-ctr-add input { flex: 1; min-width: 0; font: inherit; font-size: 13px; padding: 5px 8px;
  border-radius: 8px; background: var(--surface-2); border: 1px solid var(--line);
  color: var(--text); }

.pt-tok { position: absolute; top: 4px; left: 4px; background: var(--surface-0); color: var(--muted);
  font-size: 10px; padding: 0 4px; border-radius: 4px; border: 1px solid var(--line); }

/* --- battlefield: tap by clicking, everything else behind the ⋯ --- */
/* Faint until the card is under the pointer, so a board of forty permanents
   isn't forty buttons shouting. On touch there is no hover, so it stays legible
   there — hover is the only thing that dims it. */
/* --- the stack ------------------------------------------------------------
   Marked off from the battlefield rather than styled like it: what is here has
   not happened yet, and the two rows are next to each other. The left edge is
   the whole signal — a second border colour would make it a different kind of
   object rather than a different state. */
.pt-zone.stack { border-left: 3px solid var(--accent); }
.pt-zone.stack .pt-card { width: 96px; }
/* The bill, on the card. Sits over the art at the bottom because the top-right
   corner is the ⋯ everywhere else and muscle memory is worth more than the
   symmetry. */
.pt-stack-cost { position: absolute; left: 3px; bottom: 20px; display: flex; gap: 2px;
  padding: 2px 3px; border-radius: 4px; background: rgba(0,0,0,.62); }
/* What the board is taking off this spell. Beside the cost rather than instead
   of it: a number quietly different from the one printed in the corner is worse
   than no discount at all, and the tooltip names what is granting it. */
.pt-stack-off { position: absolute; top: 3px; left: 3px; z-index: 2;
  font-size: 10px; font-weight: 700; padding: 0 4px; border-radius: 7px;
  background: var(--accent); color: var(--accent-ink); }
/* A tax is not a discount, and reading as one at a glance is the whole failure
   this badge exists to prevent. */
.pt-stack-off.pt-stack-up { background: var(--bad, #d0503b); color: #fff; }
.pt-stack-alt { position: absolute; left: 3px; top: 3px; font-size: 9px; padding: 1px 4px;
  border-radius: 4px; background: rgba(0,0,0,.62); color: var(--accent);
  max-width: calc(100% - 8px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-resolve { position: absolute; left: 0; right: 0; bottom: 0; border: 0;
  padding: 3px 0; font: inherit; font-size: 10px; cursor: pointer;
  background: var(--accent); color: #17150f; border-radius: 0 0 5px 5px; }
.pt-resolve:hover { filter: brightness(1.08); }

/* The two explainers travel together: the row wraps around the pair rather than
   through it, so "Layers, next to the ?" survives a narrow window. */
.pt-explain { display: inline-flex; gap: 6px; align-items: center; }

/* --- a pause point, holding the turn --------------------------------------
   Not a toast. It stays until it is answered, and the turn does not move while
   it is up, so it is drawn as part of the page rather than over it. */
.pt-prompt { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 8px 12px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 16%, var(--surface));
  border: 1px solid var(--accent); }
.pt-prompt-step { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); }
.pt-prompt-text { font-size: 14px; }
.pt-prompt .pt-btn { margin-left: auto; }
/* A step with something pinned to it says so, so the bar is the place you look
   to see where the turn will stop. */
.step-pill.paused { border-color: var(--accent); }
.step-dot { color: var(--accent); font-size: 8px; vertical-align: 3px; margin-left: 3px; }

/* --- paying for a spell --------------------------------------------------- */
.pt-pip-sm { display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; font-size: 9px; font-style: normal;
  font-weight: 700; color: #17150f; }
.pt-cost-line { display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  font-size: 14px; margin: 0 0 8px; }
.pt-cost-note { font-size: 12px; color: var(--muted); margin: 0 0 10px; }
.pt-type { font-size: 12px; color: var(--muted); margin: 0 0 6px; }
.pt-oracle { font-size: 13px; line-height: 1.45; white-space: pre-wrap; margin: 0 0 10px; }
.pt-sec { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin: 14px 0 6px; }
.pt-alt-cost { display: inline-flex; gap: 2px; margin-left: 4px; }
.pt-gen-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.pt-gen-chip { display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  padding: 6px 10px; border-radius: 999px; font: inherit; font-size: 13px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--text); }
.pt-gen-chip:hover:not([disabled]) { border-color: var(--accent); }
.pt-gen-chip[disabled] { opacity: .4; cursor: default; }
.pt-ruling { font-size: 12.5px; line-height: 1.5; margin: 0 0 8px; }
.pt-ruling-date { color: var(--muted); margin-inline-end: 6px; font-variant-numeric: tabular-nums; }

/* --- the pause editor ----------------------------------------------------- */
.pt-pause-step { border-top: 1px solid var(--line); padding: 8px 0; }
.pt-pause-head { font-size: 13px; margin-bottom: 4px; }
.pt-pause-head small { color: var(--muted); margin-left: 6px; font-size: 11px; }
.pt-pause-list { list-style: none; margin: 0 0 6px; padding: 0; }
.pt-pause-line { display: flex; align-items: center; gap: 8px; font-size: 13px;
  padding: 3px 0; }
.pt-pause-line.off { opacity: .5; }
.pt-pause-line span { flex: 1; min-width: 0; }
.pt-pause-tog, .pt-pause-x { background: none; border: 0; cursor: pointer; padding: 2px 4px;
  font: inherit; color: var(--muted); }
.pt-pause-tog { color: var(--accent); }
.pt-pause-x:hover { color: #d98b6a; }
.pt-pause-add { display: flex; gap: 6px; }
.pt-pause-add input { flex: 1; min-width: 0; font: inherit; font-size: 13px;
  padding: 5px 8px; border-radius: 6px; background: var(--surface-2);
  border: 1px solid var(--line); color: var(--text); }

.pt-more { position: absolute; top: 3px; right: 3px; width: 20px; height: 20px; padding: 0;
  border: 0; border-radius: 50%; background: rgba(15,13,10,.72); color: #d8d2c6;
  font-size: 13px; line-height: 18px; cursor: pointer; opacity: .55; }
.pt-card:hover .pt-more, .pt-more:focus-visible { opacity: 1; }
/* The no-mana tap. Below the ⋯ rather than beside it: the top-right corner is
   where the menu has always been, and two controls sharing a corner is how you
   press the wrong one.
   Unlike the ⋯ it does not wait for a hover. A menu is discoverable by
   convention — everybody has pressed one — but nobody knows this button exists
   until they see it, and one that only appears once the pointer is already on
   the card is one nobody goes looking for. It sits at three-quarters strength
   and comes up full under the pointer. */
.pt-nomana { position: absolute; top: 27px; right: 2px; width: 22px; height: 22px;
  padding: 3px; cursor: pointer; border-radius: 50%; opacity: .78;
  transition: opacity .12s, background .12s, color .12s;
  background: rgba(12, 11, 9, .82); color: var(--accent);
  border: 1px solid var(--accent);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .55); }
.pt-nomana svg { display: block; width: 100%; height: 100%; }
.pt-card:hover .pt-nomana { opacity: 1; }
.pt-nomana:hover, .pt-nomana:focus-visible {
  opacity: 1; background: var(--accent); color: var(--accent-ink); outline: none; }
.pt-more:hover { background: var(--accent); color: var(--accent-ink); }

/* The mana choice sits on the card that offers it. Counter-rotated, because the
   card it belongs to is lying on its side once it's tapped — the two rotations
   cancel and the pips read straight however the card is sitting.
   width:max-content, because a five-colour land's pips do not fit inside 84px
   and wrapping them turned the row into a stack taller than the card. It
   overhangs its neighbours instead, which is why the card it belongs to is
   raised above them for as long as it is asking. */
/* Wraps rather than running off the card. Five pips fitted on one line and
   were the most a card could offer; Study Hall offers six, and five of those
   carry a price as well as a colour, which is twice the width. Two short rows
   sit over the card that owns them instead of over its neighbours. */
.pt-mana-pick { position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: flex; flex-wrap: wrap; justify-content: center;
  width: max-content; max-width: 168px; gap: 4px;
  padding: 4px; border-radius: 999px; background: rgba(15,13,10,.9);
  box-shadow: 0 2px 12px rgba(0,0,0,.55); }
.pt-card.picking { z-index: 3; }
.pt-card.tapped .pt-mana-pick { transform: translate(-50%, -50%) rotate(-90deg); }
.pt-mana-opt { display: flex; gap: 1px; padding: 2px; border: 1px solid transparent;
  border-radius: 999px; background: none; cursor: pointer; }
.pt-mana-opt:hover, .pt-mana-opt:focus-visible { border-color: var(--accent); }
.pt-mana-opt i { width: 18px; height: 18px; border-radius: 50%; font-style: normal;
  font-size: 11px; font-weight: 700; color: #17140f; display: flex;
  align-items: center; justify-content: center; }
/* An ability with a price on it. The cost sits in front of the pips it buys,
   in the order the card prints it: {1}, {T}: Add {U}{R}. Bordered rather than
   just labelled, because the free option next to it is one press and this one
   opens a bill. */
.pt-mana-opt.pt-mana-paid { border-color: var(--line); background: rgba(0,0,0,.35); }
.pt-mana-opt.pt-mana-paid u { font-size: 10px; font-weight: 700; text-decoration: none;
  color: var(--muted); align-self: center; padding: 0 3px 0 1px;
  font-variant-numeric: tabular-nums; }
.pt-mana-opt.pt-mana-paid:hover u, .pt-mana-opt.pt-mana-paid:focus-visible u { color: var(--accent); }
/* A priced option the pool cannot pay for. Dimmed rather than disabled: a
   disabled button swallows the click without firing one, and the click would
   then land on the card underneath and untap it — so it stays pressable, and
   pressing it says what is missing. */
.pt-mana-opt.pt-mana-short { opacity: .45; }
/* A planeswalker's abilities, on the card. The same overlay as the mana picker
   and deliberately so — it is the same gesture, and a board where one kind of
   permanent answers a click differently from another is a board you have to
   remember rather than read.
   Stacked rather than in a row: loyalty costs are read down the card, and three
   of them side by side stop looking like the card they came off. */
.pt-loyal-pick { position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: stretch;
  width: max-content; min-width: 52px; gap: 3px;
  padding: 5px; border-radius: 10px; background: rgba(15,13,10,.92);
  box-shadow: 0 2px 12px rgba(0,0,0,.55); z-index: 4; }
.pt-card.loyaling { z-index: 3; }
.pt-loyal-opt { border: 1px solid var(--line); border-radius: 6px;
  background: rgba(0,0,0,.35); color: var(--text); cursor: pointer;
  font-size: 13px; font-weight: 700; line-height: 1; padding: 5px 8px;
  font-variant-numeric: tabular-nums; }
.pt-loyal-opt:hover, .pt-loyal-opt:focus-visible { border-color: var(--accent); color: var(--accent); }
/* One the loyalty cannot pay for. Dimmed rather than disabled, for the reason
   above the mana version: a disabled button swallows its own click and the card
   underneath gets it instead. */
.pt-loyal-opt.pt-loyal-short { opacity: .45; }
/* The counter itself, movable by hand. An effect that moves loyalty is commoner
   than the abilities that do. */
.pt-loyal-set { display: flex; align-items: center; justify-content: space-between;
  gap: 2px; margin-top: 2px; padding-top: 4px; border-top: 1px solid var(--line); }
.pt-loyal-set b { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--accent); }
.pt-loyal-mini { border: none; background: none; color: var(--muted);
  cursor: pointer; font-size: 14px; line-height: 1; padding: 1px 5px; }
.pt-loyal-mini:hover, .pt-loyal-mini:focus-visible { color: var(--accent); }
.pt-mana-opt.pt-mana-short u { text-decoration: line-through; }

.pt-piles { display: flex; gap: 8px; margin-bottom: 10px; }
.pt-pile { flex: 1; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 6px; font-size: 12px; color: var(--muted); cursor: pointer; display: flex; flex-direction: column;
  align-items: center; gap: 2px; }
.pt-pile:hover { border-color: var(--accent); }
.pt-pile-n { font-size: 20px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.pt-pile small { font-size: 10px; }
.pt-preview { width: 180px; max-width: 60%; border-radius: 8px; display: block; margin: 0 auto 12px; }
.pt-act-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.pt-act { padding: 10px 14px; font-size: 14px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer; }
.pt-act:hover { border-color: var(--accent); }
.pt-zone-list { list-style: none; margin: 0; padding: 0; }
.pt-zone-list li { display: flex; align-items: center; gap: 10px; padding: 6px 0;
  border-bottom: 1px solid var(--line); cursor: pointer; }
.pt-zone-list img { width: 40px; border-radius: 4px; }
/* What casting it costs, pushed to the far end of the row. Only the command
   zone draws one, which is the only list where the next thing you do with a
   card is pay for it. */
.pt-zone-cost { margin-inline-start: auto; display: flex; gap: 2px; }

/* What an Aura is on, on the Aura's own tile. An Aura sitting on the
   battlefield next to the creature it is supposed to be enchanting looks
   exactly like one that is enchanting it, which is the confusion this caption
   exists to end. A loose one gets a question mark rather than nothing, because
   nothing is what it looked like before. */
/* What a card is on, and what is on it. Both along the bottom, stacked, in one
   strip that grows upward.

   The "what is on it" line used to sit along the top, to keep the two apart.
   The top of a card is its NAME — on the art and on the name-plate a card with
   no art gets — so the line saying an Aura was on a land covered what the land
   was called, which is how this was reported. */
.pt-caps { position: absolute; left: 2px; right: 2px; bottom: 2px; z-index: 2;
  display: flex; flex-direction: column; gap: 1px; align-items: stretch; }
.pt-cap { font-size: 9px; line-height: 1.2; padding: 1px 3px; border-radius: 4px;
  background: rgba(15,13,10,.86); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
button.pt-cap { border: 0; cursor: pointer; font-family: inherit; text-align: left; }
.pt-cap.pt-loose { color: var(--muted); }
.pt-cap.pt-loose:hover { color: var(--accent); }
/* And on the tile itself, because the caption is nine pixels tall and two
   copies of one Aura — one on a land, one on nothing — are otherwise the same
   picture with different small print. Sorting by name now guarantees the two
   sit side by side, which is what made the difference worth shouting. */
.pt-card.pt-unattached::after { content: ""; position: absolute; inset: 0;
  border: 1px dashed var(--muted); border-radius: 5px; pointer-events: none; }
/* How many cards a stacked tile stands for. Top-right, where the ⋯ lives on
   hover — the two never show at once, because a tile you are pointing at is a
   tile you are about to act on rather than count. */
.pt-stack-n { position: absolute; top: 3px; right: 3px; z-index: 2;
  min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 10px; font-weight: 700; line-height: 16px; text-align: center; }
.pt-card:hover .pt-stack-n { opacity: 0; }
/* The switch beside the zone label, which is where the thing it changes is. */
/* The opening hand, seven across rather than a list you scroll: the whole
   point of the question is seeing all of it at once. */
.pt-mull-hand { display: flex; flex-wrap: wrap; gap: 6px; }
.pt-mull-hand li { flex: 0 0 auto; width: 92px; display: block; text-align: center; }
.pt-mull-hand img { width: 92px; height: auto; border-radius: 5px; display: block; }
.pt-mull-hand span { display: block; font-size: 10px; line-height: 1.2; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-zone-switch { margin-left: auto; font-size: 11px; padding: 1px 8px;
  color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 999px; cursor: pointer; }
.pt-zone-switch:hover { color: var(--accent); border-color: var(--accent); }
.pt-zone-switch.on { color: var(--accent-ink); background: var(--accent);
  border-color: var(--accent); }

/* --- playtest: mana bar + next-level tools --- */
.pt-primary { border-color: var(--accent); color: var(--accent); }
.pt-mana { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 8px 14px;
  background: var(--surface); border-bottom: 1px solid var(--line); position: sticky; top: 104px; z-index: 3; }
.pt-turn, .pt-storm { font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pt-turn b, .pt-storm b { color: var(--accent); font-size: 16px; font-variant-numeric: tabular-nums; min-width: 18px; text-align: center; }
.pt-pool { display: flex; gap: 6px; }
.pt-pip { display: flex; align-items: center; gap: 3px; border: none; border-radius: 6px;
  padding: 4px 8px; font-size: 12px; font-weight: 600; color: #1b1305; cursor: pointer; }
.pt-pip b { font-variant-numeric: tabular-nums; }
/* How much of that colour came from a snow source. Drawn only where there is
   some, so a pool that has never seen a snow permanent looks exactly as it
   always did — which is every pool in most decks. */
.pt-snow-n { font-style: normal; font-size: 10px; font-weight: 700;
  opacity: .75; margin-inline-start: 1px; }
/* The switch that decides whether mana added by hand is snow. Off, it is a
   quiet outline; on, it is the ice colour {S} is drawn in everywhere else. */
.pt-snow-add { background: transparent; border: 1px solid var(--line);
  color: var(--muted); font-size: 13px; line-height: 1; padding: 4px 7px; }
/* Take one back. Drawn only for a colour that has any, so an empty pool is the
   bar it always was — and drawn at all because the only way to do this used to
   be a right-click nobody could see and a phone could not make. */
.pt-pip-less { border: 1px solid var(--line); border-radius: 6px; background: transparent;
  color: var(--muted); font-size: 12px; line-height: 1; padding: 4px 6px; cursor: pointer; }
.pt-pip-less:hover, .pt-pip-less:focus-visible { border-color: var(--accent); color: var(--accent); }
.pt-pipwrap { display: flex; gap: 2px; }
.pt-snow-add.on { background: #a9cbe0; border-color: #a9cbe0; color: #17150f; }
.pt-snow-add:hover { border-color: var(--accent); }
/* An activated ability, as the card writes it: the cost on one line and what
   it does under it. A full-width block rather than a chip in a row, because
   the effect is a sentence and a sentence in a chip wraps into a scribble. */
.pt-abil { display: block; width: 100%; text-align: start; margin: 6px 0;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: rgba(0,0,0,.25); color: var(--text); cursor: pointer; font: inherit; }
.pt-abil:hover:not(:disabled), .pt-abil:focus-visible { border-color: var(--accent); }
.pt-abil:disabled { opacity: .55; cursor: default; }
.pt-abil-cost { display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
  font-size: 12px; font-weight: 600; margin-bottom: 4px; }
.pt-abil-eff { display: block; font-size: 12px; line-height: 1.45; color: var(--muted); }
/* The part of the cost the sandbox will not charge. Called out rather than
   hidden: this is the difference between a button that finished and one that
   got as far as it honestly could. */
.pt-abil-owed { display: block; margin-top: 4px; font-size: 11px; color: var(--accent); }
/* A loyalty cost in the panel: a chip in a row rather than a block with a
   sentence under it, because the sentence is already on the card above. */
.pt-abil-loyal { font-variant-numeric: tabular-nums; font-weight: 700; min-width: 46px; }
.pt-abil-loyal.pt-loyal-short { opacity: .45; }
/* A card in hand the pod is being shown. Sits on the tile rather than only in
   the capture, because the capture is the one screen you are not looking at
   while you play. */
.pt-shown { position: absolute; left: 3px; bottom: 3px; z-index: 2;
  padding: 1px 5px; border-radius: 4px; font-size: 9px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  background: var(--accent); color: #17150f; }
/* A zone list you tick rather than click through. Same rows as the plain one,
   with the state on the row instead of in a checkbox nobody can hit on a
   phone. */
.pt-pick-list li { cursor: pointer; }
.pt-pick-list li.on { outline: 1px solid var(--accent); outline-offset: -1px;
  background: rgba(0,0,0,.3); }
.pt-pick-mark { margin-inline-start: auto; padding-inline: 8px;
  color: var(--accent); font-weight: 700; }
/* --- playtest: OBS capture session --- */
.pt-capture { display: flex; align-items: center; gap: 10px; padding: 8px 14px;
  background: var(--surface); border-bottom: 1px solid var(--line); }
.pt-capture .pt-info { margin-left: 0; }
.cap-live { color: var(--accent); font-weight: 600; }
.pt-cap-panel { padding: 10px 14px 14px; background: var(--surface);
  border-bottom: 1px solid var(--line); }
.pt-cap-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pt-cap-row label { font-size: 12px; color: var(--muted); }
.pt-cap-row input { flex: 1 1 320px; min-width: 220px; padding: 6px 10px; font-size: 13px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 8px; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; }
.pt-cap-row .pt-btn { text-decoration: none; }
.pt-cap-note { font-size: 12px; color: var(--muted); margin: 8px 0 0; max-width: 78ch; line-height: 1.5; }
.pt-cap-strong { color: var(--text); font-weight: 600; }
.pt-cap-seed { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); align-items: flex-start; }
.pt-cap-seed .pt-cap-note { margin: 0; flex: 1 1 320px; }
/* --- shuffle verification ------------------------------------------------- */
.v-order { margin: 0; padding-left: 30px; font-size: 13px; line-height: 1.7;
  max-height: 60vh; overflow-y: auto; columns: 2; column-gap: 28px; }
@media (max-width: 640px) { .v-order { columns: 1; } }
.v-order li { break-inside: avoid; }
/* A tap that costs life. The number sits on the button rather than in a note
   beside it, because the decision is which button to press. */
.pt-mana-hurts { border-color: #a3402f; }
.pt-mana-pain { color: #d0705b; font-size: 11px; font-weight: 700; margin-left: 2px; }
.pt-cap-stop { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
  align-items: flex-start; }
.pt-cap-stop .pt-cap-note { margin: 0; flex: 1 1 320px; }
.pt-cap-hand { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.pt-cap-hand > div:last-child { flex: 1 1 320px; }
/* white plate behind the code: a QR on a dark background reads as inverted and
   most phone cameras won't look twice */
.pt-qr { background: #fff; padding: 8px; border-radius: 8px; line-height: 0; }

/* --- keyword chips -------------------------------------------------------- */
/* On a card sheet and on the zoom overlay: the keywords a card has, each one a
   button that answers for itself out of the CR glossary. */
.kw-chips { margin: 10px 0 0; }
.kw-row { display: flex; flex-wrap: wrap; gap: 6px; }
.kw-chip { font-size: 12px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; cursor: pointer; }
.kw-chip:hover { border-color: var(--accent); color: var(--accent); }
.kw-chip[aria-expanded="true"] { background: var(--accent); color: var(--accent-ink);
  border-color: var(--accent); }
.kw-def { margin-top: 8px; padding: 9px 11px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--surface-0); }
.kw-def-body { margin: 0; font-size: 13px; line-height: 1.5; }
/* set like a card sets it: the keyword upright, the reminder in italics */
.kw-rem { color: var(--muted); }
.kw-cr { font-size: 11px; color: var(--muted); white-space: nowrap; }
.kw-def a { color: var(--accent); }
/* over the zoom overlay's dark backdrop, not a panel */
.pt-zoom .kw-chips { max-width: min(92vw, 560px); margin: 12px auto 0; }
.pt-zoom .kw-row { justify-content: center; }
.pt-zoom .kw-def { background: rgba(15,13,10,.94); }

/* --- rules explainers (layers, turn order) ------------------------------------------------- */
/* One overlay, shared by every explainer — see explain.js. */
.exp-wrap { position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; padding: 16px; }
.exp-scrim { position: absolute; inset: 0; background: rgba(0,0,0,.72); }
.exp-panel { position: relative; background: var(--surface); border: 1px solid var(--line);
  border-radius: 16px; width: min(760px, 100%); max-height: min(88vh, 900px);
  display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
.exp-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 16px 18px 10px; border-bottom: 1px solid var(--line); }
.exp-head h2 { margin: 0; font-size: 18px; }
/* The panel is tall enough to always scroll, so its scrollbar is on screen the
   whole time — left at the browser default it renders light grey down the side
   of a dark panel. */
.exp-body { overflow-y: auto; padding: 14px 18px calc(env(safe-area-inset-bottom) + 20px);
  scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.exp-body::-webkit-scrollbar { width: 10px; }
.exp-body::-webkit-scrollbar-thumb { background: var(--line); border-radius: 5px; }
.exp-body::-webkit-scrollbar-track { background: transparent; }
.exp-body p { font-size: 14px; line-height: 1.6; }
.exp-lead { margin-top: 0; font-size: 15px !important; }
.exp-note { color: var(--muted); font-size: 13px !important; }
.exp-h { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 22px 0 8px; }
.exp-list { list-style: none; margin: 0; padding: 0; }
.exp-list li { display: grid; grid-template-columns: 34px 1fr; gap: 2px 10px;
  padding: 8px 0; border-top: 1px solid var(--line); align-items: baseline; }
.exp-list li:first-child { border-top: 0; }
.exp-n { grid-row: span 2; font-size: 13px; font-weight: 700; color: var(--accent);
  font-variant-numeric: tabular-nums; }
.exp-t { font-size: 14px; font-weight: 600; }
.exp-d { font-size: 13px; color: var(--muted); line-height: 1.5; }
.exp-eg { color: var(--accent); opacity: .85; }
.exp-hot .exp-t { color: var(--accent); }
.exp-eg-box { border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  margin-bottom: 12px; background: var(--surface-0); }
.exp-q { margin: 0 0 10px; font-weight: 600; }
.exp-steps { width: 100%; border-collapse: collapse; margin-bottom: 10px; }
.exp-steps td { font-size: 13px; padding: 4px 0; border-bottom: 1px solid var(--line);
  color: var(--muted); }
.exp-steps td:last-child { text-align: right; color: var(--text); font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap; padding-left: 12px; }
.exp-steps tr:last-child td { border-bottom: 0; }
.exp-a { margin: 0 0 6px; font-size: 15px !important; font-weight: 700; color: var(--accent); }
.exp-why { margin: 0; font-size: 13px !important; color: var(--muted); }
.exp-cr { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--line);
  color: var(--muted); font-size: 13px !important; }
.exp-cr a, .exp-body a { color: var(--accent); }

/* --- hand surface (phone) ------------------------------------------------- */
.hand-body { padding-bottom: 78px; }              /* room for the fixed bar */
.hand-main { padding: 10px 12px; }
.hand-board { margin-bottom: 14px; }
.hand-counts { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.hd-chip { font-size: 12px; color: var(--muted); background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; }
.hd-chip b { color: var(--text); font-variant-numeric: tabular-nums; }
.hd-n { font-size: 12px; color: var(--muted); font-weight: 400; }
.hand-h { font-size: 13px; color: var(--muted); font-weight: 500; margin: 0 0 6px; }
/* the board is where you tap from, so its thumbnails carry a tap target, a ⋯,
   and the mana question — everything the desktop board has, at 58px */
.hand-mini { list-style: none; margin: 0; padding: 0; display: flex; gap: 6px;
  flex-wrap: wrap; align-items: flex-start; }
.hand-mini-li { position: relative; line-height: 0; }
.hand-mini-li.picking { z-index: 3; }
.hand-mini-card { width: 58px; padding: 0; background: none; border: 0; cursor: pointer;
  display: block; transition: transform .12s; }
.hand-mini-card img { width: 58px; aspect-ratio: 488/680; object-fit: cover;
  border-radius: 5px; display: block; }
/* The same idiom as the table and the desktop: a tapped permanent lies down.
   Scaled to fit the slot it already occupies rather than given margins to
   sprawl into — at 58px a rotated card that resizes its own row drags the whole
   board about, and takes the ⋯ anchored to the slot away from the card. */
.hand-mini-card.tapped { transform: rotate(90deg) scale(.716); }
/* One card is asking; the rest of the board steps back so it is obvious which
   one the pips belong to. They overhang their neighbours by necessity — five
   colours do not fit inside 58px. */
.hand-mini.asking .hand-mini-li:not(.picking) { opacity: .3; }
.hand-mini-li.picking .hand-mini-card { outline: 2px solid var(--accent);
  outline-offset: 2px; border-radius: 6px; }
.hand-more { position: absolute; top: 1px; right: 1px; width: 22px; height: 22px; padding: 0;
  border: 0; border-radius: 50%; background: rgba(15,13,10,.75); color: #d8d2c6;
  font-size: 13px; line-height: 20px; cursor: pointer; z-index: 2; }
.hand-mana-pick { position: absolute; left: 50%; top: 50%; z-index: 3;
  transform: translate(-50%, -50%);
  display: flex; flex-wrap: nowrap; width: max-content; gap: 5px;
  padding: 5px; border-radius: 999px; background: rgba(15,13,10,.92);
  box-shadow: 0 2px 14px rgba(0,0,0,.6); }
.hand-mana-opt { display: flex; gap: 1px; padding: 3px; border: 1px solid transparent;
  border-radius: 999px; background: none; cursor: pointer; }
.hand-mana-opt:active { border-color: var(--accent); }
.hand-mana-opt.hurts { border-color: #a3402f; }
.hand-mana-opt b { color: #d0705b; font-size: 11px; font-weight: 700; align-self: center; }
/* 22px, not the desktop's 18: this one is hit with a thumb */
.hand-mana-opt i { width: 22px; height: 22px; border-radius: 50%; font-style: normal;
  font-size: 12px; font-weight: 700; color: #17140f; display: flex;
  align-items: center; justify-content: center; }

.hand-pool { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.hd-pip { display: inline-flex; align-items: center; gap: 4px; font-size: 11px;
  font-weight: 700; color: #17140f; background: var(--pip); border-radius: 999px;
  padding: 2px 8px 2px 6px; }
.hd-pip b { font-variant-numeric: tabular-nums; font-size: 12px; }
.hd-pip.zero { opacity: .35; }
.hand-tip { font-size: 11px; color: var(--muted); margin: 0 0 8px; }
/* the hand is the workspace: bigger, and scrolled sideways rather than wrapped,
   so the cards stay in the order you're used to seeing them */
.hand-strip { list-style: none; margin: 0; padding: 0 0 6px; display: flex; gap: 8px;
  overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; }
.hand-strip > li { scroll-snap-align: center; flex: 0 0 auto; }
.hand-card { width: 120px; padding: 0; background: none; border: 0; cursor: pointer; }
.hand-card img { width: 120px; aspect-ratio: 488/680; object-fit: cover;
  border-radius: 8px; display: block; }
.hand-back { display: flex; align-items: center; justify-content: center;
  width: 100%; aspect-ratio: 488/680; border-radius: 8px; font-size: 12px;
  color: var(--muted); background: var(--surface-2); border: 1px solid var(--line); }
.hand-preview { width: 100%; max-width: 260px; border-radius: 10px; display: block; margin: 0 auto 12px; }
.hand-log { font-size: 12px; color: var(--muted); margin: 14px 0 0; min-height: 1.4em; }
#hQuery { width: 100%; padding: 10px 12px; font-size: 16px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 10px; }
/* fixed, and above the home indicator on a phone */
.hand-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  display: flex; gap: 6px; justify-content: space-between;
  padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  background: var(--surface); border-top: 1px solid var(--line); }
.hand-bar .pt-btn { flex: 1; text-align: center; padding: 10px 4px; font-size: 13px; }

.pt-hint { font-size: 12px; color: var(--muted); margin: 0 0 10px; }
.pt-zone-list.look li { justify-content: space-between; }
.pt-look-acts { display: flex; gap: 6px; margin-left: auto; }
.pt-mini { font-size: 12px; padding: 4px 8px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 6px; cursor: pointer; }
.pt-mini:hover { border-color: var(--accent); }

/* --- playtest Tier 1: face-down, zoom, reveal --- */
.pt-card.facedown .pt-back { width: 100%; aspect-ratio: 488/680; border-radius: 5px;
  background: repeating-linear-gradient(45deg, #2b2620, #2b2620 6px, #332e26 6px, #332e26 12px);
  border: 1px solid var(--line); display: flex; align-items: center; justify-content: center;
  color: var(--muted); font-size: 11px; letter-spacing: .1em; }
.pt-zoom { position: fixed; inset: 0; z-index: 40; background: rgba(0,0,0,.85);
  display: flex; align-items: center; justify-content: center; padding: 20px; }
.pt-zoom img { max-height: 92vh; max-width: 92vw; border-radius: 12px; }
/* One card or several — "reveal the top three" is what cards actually say, so
   the slot wraps rather than assuming a single picture. The label takes the
   full width so the row below it reads as one group. */
.pt-reveal { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 4px; padding: 6px; background: var(--surface); border: 1px solid var(--accent);
  border-radius: var(--radius); max-width: 320px; }
.pt-reveal small { flex: 0 0 100%; text-align: center; font-size: 10px;
  color: var(--muted); text-transform: uppercase; }
.pt-reveal img { width: 64px; border-radius: 5px; cursor: pointer; }

/* The picker's free entry, under the common counts. "The top n" is the shape
   every card that looks at a library is written in, and n is not always one of
   six numbers. */
.pt-pick-any { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.pt-pick-any label { font-size: 13px; color: var(--muted); display: flex;
  align-items: center; gap: 6px; }
.pt-pick-any input { width: 92px; font: inherit; font-size: 14px; padding: 5px 8px;
  border-radius: 8px; background: var(--surface-2); border: 1px solid var(--line);
  color: var(--text); }

/* --- Tier 2 stats panel --- */
.odds-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin: 4px 0 8px; }
.odds-row select, .odds-row input[type="number"] { font-size: 14px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; }
.odds-row select { max-width: 60%; }
.odds-row input[type="number"] { width: 56px; }
.odds-row label { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.odds-out { font-size: 14px; color: var(--text); margin: 4px 0 12px; }
.odds-out b { color: var(--accent); }

/* --- basics tool --- */
.basics-tool { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 0 0 14px; }
.basics-tool label { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.basics-tool input { width: 60px; padding: 6px 8px; font-size: 15px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; }
.basics-msg { font-size: 12px; color: var(--muted); }

/* --- landing page --------------------------------------------------------- */
.home-top { text-align: center; }
.home-top h1 { justify-content: center; font-size: 22px; margin-bottom: 4px; }
.home-logo { width: 40px; height: 40px; margin-inline-end: 10px; }
.home-top .hint { margin: 0; }

/* min(…,100%) keeps the track from forcing the page wider than the viewport */
.home-nav { display: grid; gap: 12px; margin: 4px 0 22px;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.home-btn { display: grid; grid-template-columns: 34px 1fr; align-items: center;
  column-gap: 12px; row-gap: 2px; padding: 16px 18px; text-decoration: none;
  color: var(--text); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); transition: border-color .15s ease, transform .15s ease; }
.home-btn:hover { border-color: var(--accent); transform: translateY(-2px); }
.home-ic { grid-row: 1 / 3; font-size: 24px; text-align: center; }
img.home-ic { width: 34px; height: 34px; border-radius: 8px; object-fit: cover; }
.home-t { font-size: 17px; font-weight: 600; }
.home-s { font-size: 12px; color: var(--muted); }

.home-hd { display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; font-size: 15px; font-weight: 600; margin: 0 0 12px;
  padding-bottom: 8px; border-bottom: 1px solid var(--line); }

/* --- format filter -------------------------------------------------------- */
.fmt-head { display: flex; justify-content: flex-end; margin-bottom: 6px; }
/* Arrows ride over the ends of the strip and disappear at each end, so they
   never point somewhere there's nothing to go. */
.fmt-scroll { position: relative; }
.fmt-nav { position: absolute; top: 50%; left: -8px; transform: translateY(-50%);
  z-index: 3; width: 46px; height: 46px; padding: 0; overflow: hidden;
  border-radius: 50%; border: 1px solid var(--line); background: var(--surface);
  cursor: pointer; box-shadow: 0 2px 12px rgba(0, 0, 0, .6); }
.fmt-nav-r { left: auto; right: -8px; }
.fmt-nav img { display: block; width: 100%; height: 100%; object-fit: cover; }
.fmt-nav:hover { border-color: var(--accent); }
.fmt-nav[hidden] { display: none; }
@media (max-width: 560px) { .fmt-nav { width: 38px; height: 38px; } }
.fmt-acts { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.fmt-toggles { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px;
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr)); }
.fmt-toggles label { display: flex; align-items: center; gap: 8px; padding: 6px 4px;
  font-size: 14px; cursor: pointer; border-radius: 6px; }
.fmt-toggles label:hover { background: var(--surface-2); }
/* One emblem per format. There are 25, so this scrolls sideways rather than
   wrapping into a wall that buries the decks underneath it.

   Called .fmt-rail rather than .fmt-bar because the search page has a
   .fmt-bar too — a row of "Legal in / Sort by" controls — and this rule sits
   later in the file, so it was silently winning on both pages. The search
   page lost its top margin (no gap under the search box), its
   align-items:center, and its flex-wrap, picking up a sideways scroll it has
   no use for. Two components, one name, and the file order decided which one
   was right. */
.fmt-rail { display: flex; gap: 10px; margin: 0 0 12px; padding: 0 0 8px;
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch; }
.fmt-cell { position: relative; display: flex; flex: 0 0 auto; scroll-snap-align: start; }
.fmt { display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: 132px; padding: 10px 6px 8px; cursor: pointer; color: var(--muted);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.fmt img { width: 108px; height: 108px; border-radius: 10px; object-fit: contain; }
.fmt-t { font-size: 12px; line-height: 1.25; text-align: center; }
.fmt-n { font-size: 11px; opacity: .55; font-variant-numeric: tabular-nums; }
.fmt:hover { border-color: var(--accent); color: var(--text); }
.fmt.on { border-color: var(--accent); color: var(--text); background: var(--surface-2); }
.fmt-empty { opacity: .45; }
.fmt-new { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  opacity: 0; pointer-events: none; transition: opacity .12s;
  white-space: nowrap; font-size: 12px; font-weight: 500; padding: 5px 12px;
  color: var(--accent-ink); background: var(--accent); border-radius: 999px;
  cursor: pointer; box-shadow: 0 2px 10px rgba(0, 0, 0, .55); }
.fmt-cell:hover .fmt-new, .fmt-cell:focus-within .fmt-new { opacity: 1; pointer-events: auto; }
.fmt-cell:hover .fmt img, .fmt-cell:focus-within .fmt img { opacity: .45; }
/* keep the scrollbar from stealing the emblems' height */
.fmt-rail::-webkit-scrollbar { height: 8px; }
.fmt-rail::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
@media (hover: none) {
  .fmt-cell { flex-direction: column; }
  .fmt-new { position: static; transform: none; opacity: 1; pointer-events: auto;
    margin-top: 4px; box-shadow: none; }
  .fmt-cell:hover .fmt img { opacity: 1; }
}
@media (max-width: 560px) {
  .fmt { width: 104px; }
  .fmt img { width: 84px; height: 84px; }
}

/* --- bracket filter ------------------------------------------------------- */
/* The same logos the deckboxes wear as a 24px badge, here at a size where they
   can actually be read. Picking one filters the wall below; the plain Deck
   Builder logo is the "everything" option. */
.brk-bar { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 16px; padding: 0; }
.brk-cell { position: relative; display: flex; }
/* Hovering a bracket offers to start a deck in it. Sits over the logo, which
   dims so the pill stays legible against the art. */
.brk-new { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  opacity: 0; pointer-events: none; transition: opacity .12s;
  white-space: nowrap; font-size: 12px; font-weight: 500; padding: 5px 12px;
  color: var(--accent-ink); background: var(--accent); border-radius: 999px;
  cursor: pointer; box-shadow: 0 2px 10px rgba(0, 0, 0, .55); }
.brk-cell:hover .brk-new, .brk-cell:focus-within .brk-new { opacity: 1; pointer-events: auto; }
.brk-cell:hover .brk img, .brk-cell:focus-within .brk img { opacity: .45; }
.brk { display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: 156px; padding: 10px 6px 8px; cursor: pointer; color: var(--muted);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.brk img { width: 128px; height: 128px; border-radius: 10px; object-fit: contain; }
.brk-t { font-size: 12px; line-height: 1.25; text-align: center; }
.brk-n { font-size: 11px; opacity: .55; font-variant-numeric: tabular-nums; }
.brk:hover { border-color: var(--accent); color: var(--text); }
.brk.on { border-color: var(--accent); color: var(--text); background: var(--surface-2); }
.brk-empty { opacity: .45; }        /* no decks in it — still selectable */
/* Six of these at full size wrap to three rows on a phone and push the decks
   off screen, so they stay nearer the original size there. */
@media (max-width: 560px) {
  .brk { width: 104px; padding: 8px 4px 6px; }
  .brk img { width: 84px; height: 84px; }
}
/* A touch screen has no hover, so an overlay would be unreachable — the build
   button sits under the chip there instead of over the logo. */
@media (hover: none) {
  .brk-cell { flex-direction: column; }
  .brk-new { position: static; transform: none; opacity: 1; pointer-events: auto;
    margin-top: 4px; box-shadow: none; }
  .brk-cell:hover .brk img { opacity: 1; }
}

/* --- deckbox tiles -------------------------------------------------------- */
.dbox-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); }
.dbox-tile { position: relative; display: flex; flex-direction: column; gap: 8px; }
/* Delete, revealed on hover so it can't be hit by accident while browsing.
   Confirms before it fires. */
.dbox-del { position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 26px; height: 26px; border-radius: 50%; padding: 0;
  opacity: 0; pointer-events: none; transition: opacity .12s;
  font-size: 12px; line-height: 1; cursor: pointer;
  color: var(--text); background: rgba(0, 0, 0, .62); border: 1px solid var(--line); }
.dbox-tile:hover .dbox-del, .dbox-tile:focus-within .dbox-del { opacity: 1; pointer-events: auto; }
.dbox-del:hover { background: #7a2b22; border-color: #c0503b; color: #fff; }
/* no hover on touch — otherwise it could never be reached */
@media (hover: none) { .dbox-del { opacity: 1; pointer-events: auto; } }

/* the box itself: art on the face, lid seam up top, depth down the left edge */
.dbox { position: relative; display: block; aspect-ratio: 5 / 7; overflow: hidden;
  border-radius: 12px; border: 1px solid var(--line); background: var(--surface-2);
  color: var(--text); text-decoration: none;
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
  transform: perspective(800px) rotateY(-5deg);
  transition: transform .18s ease, box-shadow .18s ease; }
.dbox:hover, .dbox:focus-visible { transform: perspective(800px) rotateY(0deg) translateY(-3px);
  box-shadow: 0 14px 28px rgba(0,0,0,.6); }
.dbox::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 10px; z-index: 2;
  background: linear-gradient(90deg, rgba(0,0,0,.6), rgba(0,0,0,0)); pointer-events: none; }
.dbox-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the logo fallback is a wordmark — letterbox it instead of cropping the type off */
.dbox-art.is-logo { object-fit: contain; padding: 12% 10% 22%;
  background: radial-gradient(circle at 50% 38%, #2f2c22, #14130e); }
.dbox-lid { position: absolute; left: 0; right: 0; top: 0; height: 26%; z-index: 2;
  border-bottom: 1px solid rgba(0,0,0,.6);
  box-shadow: 0 1px 0 rgba(255,255,255,.12);
  background: linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,0)); }
.dbox-glare { position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(115deg, rgba(255,255,255,.14) 0%, rgba(255,255,255,0) 42%); }
/* bracket medallion, centred on the lid */
.dbox-badge { position: absolute; top: 4.5%; left: 50%; transform: translateX(-50%);
  z-index: 3; width: 34%; aspect-ratio: 1; border-radius: 50%; overflow: hidden;
  border: 1px solid rgba(255,255,255,.45); box-shadow: 0 3px 10px rgba(0,0,0,.6); }
.dbox-badge img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* the face is already the bracket logo — no need to stamp it twice */
.dbox.hide-badge .dbox-badge { display: none; }
.dbox-face { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 2px; padding: 16px 10px 10px;
  background: linear-gradient(0deg, rgba(0,0,0,.9) 40%, rgba(0,0,0,0)); }
.dbox-name { font-size: 14px; font-weight: 600; line-height: 1.25; }
.dbox-sub { font-size: 11px; color: #cbc5b4; }
.dbox-art-btn { align-self: stretch; padding: 6px 8px; font-size: 12px; cursor: pointer;
  color: var(--muted); background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; }
.dbox-art-btn:hover { color: var(--accent); border-color: var(--accent); }

/* --- deckbox art picker --------------------------------------------------- */
.art-opt { display: block; width: 100%; }
.art-opt-img { display: block; width: 100%; aspect-ratio: 626 / 457; object-fit: cover;
  background: var(--surface-2); }
.art-opt-nm { display: block; padding: 6px 8px; font-size: 12px; line-height: 1.3; }
.art-opt-cmd { font-size: 9px; font-weight: 700; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 4px; padding: 0 3px; vertical-align: 1px; }

/* session expiry — a failed write must never look like a successful one */
.auth-lost { position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  padding: 12px var(--pad) calc(env(safe-area-inset-bottom) + 12px);
  font-size: 14px; text-align: center; color: #fff2dd;
  background: #7a2d16; border-top: 1px solid #a8542f;
  box-shadow: 0 -4px 18px rgba(0,0,0,.5); }
.auth-lost a { color: #ffd9a8; font-weight: 600; }

/* --- grid view: qty controls without opening the card sheet --------------- */
.card-face { display: block; width: 100%; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; text-align: left; cursor: pointer; }
.card-steps { display: flex; align-items: center; gap: 4px; cursor: default;
  padding: 6px 8px; border-top: 1px solid var(--line); }
.card-steps .q { min-width: 22px; text-align: center; font-size: 13px;
  font-variant-numeric: tabular-nums; }
.card-steps .row-del { margin-left: auto; }

/* ---------------------------------------------------------------- AI panel */
/* Sits between the page chrome and its content on home, decks and each deck.
   Hidden entirely when the assistant is off, so it costs nothing visually. */
.ai-panel { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px; margin: 0 0 18px; }
.ai-panel .cat-head { margin-top: 0; display: flex; align-items: center; gap: 8px; }
.ai-panel .cat-head .cb-cards { margin-left: auto; font-weight: 400; }
.ai-form { display: flex; gap: 8px; align-items: flex-end; }
.ai-form textarea { flex: 1; resize: vertical; min-height: 44px;
  padding: 10px 12px; font: inherit; font-size: 14px; color: var(--text);
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px; }
.ai-form textarea:focus { outline: none; border-color: var(--accent); }
.ai-reply { margin-top: 12px; font-size: 14px; line-height: 1.6; }
.ai-reply p { margin: 0 0 10px; }
.ai-reply ul { margin: 0 0 10px; padding-left: 20px; }
.ai-reply code { background: var(--surface-2); border-radius: 4px; padding: 1px 5px;
  font-size: 12px; }
.ai-h { font-weight: 600; color: var(--accent); margin: 12px 0 4px; }
.ai-diff { margin-top: 6px; max-height: 340px; overflow-y: auto;
  border-top: 1px solid var(--line); padding-top: 8px; }
.ai-cards { list-style: none; margin: 0 0 8px; padding: 0;
  columns: 2; column-gap: 18px; font-size: 13px; }
.ai-cards li { break-inside: avoid; padding: 1px 0; }
@media (max-width: 560px) { .ai-cards { columns: 1; } .ai-form { flex-direction: column;
  align-items: stretch; } }

/* ----------------------------------------------------------- deck gallery */
.gal-grid { display: grid; gap: 12px; margin-bottom: 18px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.gal-card { display: flex; flex-direction: column; gap: 2px; padding: 0 0 10px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; text-decoration: none;
  color: var(--text); transition: border-color .15s, transform .15s; }
.gal-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.gal-art { width: 100%; aspect-ratio: 626 / 240; object-fit: cover;
  background: var(--surface-2); margin-bottom: 6px; }
.gal-art-none { background: linear-gradient(160deg, var(--surface-2), var(--surface)); }
.gal-card > span { padding: 0 10px; }
.gal-name { font-weight: 600; font-size: 15px; line-height: 1.25; }
.gal-by { color: var(--muted); }
.gal-lock { margin-top: 4px; font-size: 12px; color: var(--accent); }

/* ------------------------------------------------------------ deck sharing */
.share-box .pick-label { margin-top: 16px; }
.share-toggles { display: grid; gap: 8px; margin-bottom: 10px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.share-opt { display: flex; gap: 8px; align-items: flex-start; padding: 10px;
  font-size: 14px; background: var(--bg); border: 1px solid var(--line);
  border-radius: 10px; cursor: pointer; }
.share-opt:hover { border-color: var(--accent); }
.share-opt input { margin-top: 3px; }
.share-link { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.share-link input { flex: 1; min-width: 220px; padding: 8px 10px; font: inherit;
  font-size: 13px; color: var(--muted); background: var(--bg);
  border: 1px solid var(--line); border-radius: 8px; }
.set-row { display: flex; gap: 8px; align-items: center; font-size: 14px; }

/* --------------------------------------------------------- settings: keys */
.prov-card { background: var(--bg); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px; margin-bottom: 10px; }
.prov-card .pick-label { margin: 0 0 2px; display: flex; gap: 8px;
  align-items: baseline; flex-wrap: wrap; }
.prov-card input { width: 100%; padding: 7px 10px; font: inherit; font-size: 13px;
  color: var(--text); background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; }

/* ------------------------------------------------------------ suggestions */
.sug-group { margin-bottom: 14px; }
.sug-body, .sug-note { display: block; margin-top: 2px; }
.sug-note { color: var(--accent); }
.primer-view { font-size: 14px; }

/* ------------------------------------------------------------- busy paw */
/* A minute of silence reads as "it's stuck". The paw turns while the
   assistant is working, purely so there's something alive on screen. */
.paw-spin { width: 22px; height: 22px; flex: 0 0 auto; vertical-align: -5px;
  animation: paw-turn 1.6s linear infinite; }
@keyframes paw-turn { to { transform: rotate(360deg); } }
/* Reduced motion still needs a sign of life, just not a spinning one. */
@media (prefers-reduced-motion: reduce) {
  .paw-spin { animation: paw-pulse 1.4s ease-in-out infinite; }
  @keyframes paw-pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
}
.ai-busy { display: flex; align-items: center; gap: 8px; }

/* ------------------------------------------------------------- tab shell */
/* app.html hosts the ordinary pages in iframes so a background tab keeps
   running - an AI deck build survives you going to look at something else. */
.shell-body { height: 100vh; height: 100dvh; margin: 0; display: flex;
  flex-direction: column; overflow: hidden; }
.frames { flex: 1; min-height: 0; position: relative; }
.tabframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  background: var(--bg); }

.tabbar { display: flex; align-items: stretch; gap: 2px; padding: 4px 6px 0;
  background: var(--surface); border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: thin; flex: 0 0 auto; }
.tab { display: inline-flex; align-items: center; gap: 6px; max-width: 220px;
  padding: 7px 6px 7px 12px; font-size: 13px; color: var(--muted);
  background: var(--bg); border: 1px solid var(--line); border-bottom: none;
  border-radius: 9px 9px 0 0; cursor: pointer; white-space: nowrap;
  transition: color .12s, background .12s; }
.tab:hover { color: var(--text); }
.tab-on { color: var(--text); background: var(--surface-2);
  border-color: var(--accent); }
.tab-t { overflow: hidden; text-overflow: ellipsis; }
.tab-x { padding: 0 4px; font-size: 12px; line-height: 1; color: inherit;
  background: none; border: 0; border-radius: 4px; cursor: pointer; opacity: .5; }
.tab-x:hover { opacity: 1; background: var(--line); }
.tab-add { margin-left: 4px; padding: 0 10px; font-size: 15px; color: var(--muted);
  background: none; border: 0; cursor: pointer; }
.tab-add:hover { color: var(--accent); }

/* Walking paws: the SVG animates itself (SMIL), so no CSS animation here -
   adding one would spin the whole thing while the paws are trying to walk. */
.paw-walk { width: 28px; height: 28px; flex: 0 0 auto; vertical-align: -7px; }

/* The foil price is its own choice, not a label. Clicking the tile buys the
   normal printing; clicking this buys the foil, and ticks the Foil box. */
.print-foil { display: block; width: 100%; margin-top: 2px; padding: 3px 6px;
  font: inherit; font-size: 11px; color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 0 0 8px 8px; cursor: pointer; }
.print-foil:hover { color: var(--text); border-color: var(--accent); }
.print-foil[aria-pressed="true"] { color: var(--accent-ink); background: var(--accent);
  border-color: var(--accent); font-weight: 600; }

/* ------------------------------------------------------------------- help */
.help-list { margin: 6px 0 0; padding-left: 20px; font-size: 14px; line-height: 1.6; }
.help-list li { margin-bottom: 6px; }
.ruling-box p { font-size: 14px; line-height: 1.6; margin: 0 0 8px; }
.help-keys { width: 100%; border-collapse: collapse; font-size: 14px; }
.help-keys td { padding: 6px 8px; border-bottom: 1px solid var(--line);
  vertical-align: top; }
.help-keys td:first-child { width: 42%; white-space: nowrap; }
kbd { display: inline-block; padding: 2px 6px; font-family: inherit; font-size: 12px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-bottom-width: 2px; border-radius: 5px; }
.site-foot { margin: 26px 0 40px; padding-top: 14px; border-top: 1px solid var(--line);
  text-align: center; }
.site-foot p { margin: 0 0 6px; }

/* ------------------------------------------------------------ credit meter */
.meter-bar { height: 8px; margin: 8px 0; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 5px; overflow: hidden; }
.meter-fill { height: 100%; width: 0; background: var(--accent);
  transition: width .3s ease; }
.meter-full { background: var(--bad); }

/* The studio lockup in the footer. Dimmed until hovered so it signs the page
   without competing with it. */
.foot-mark { display: inline-block; margin-bottom: 10px; opacity: .75;
  transition: opacity .15s; }
.foot-mark:hover { opacity: 1; }
.foot-mark img { display: block; width: 200px; max-width: 60vw; height: auto; }

/* The active filter can outlive its chip once its format is hidden, so the
   heading carries the way out. */
#clearFilter { margin-left: 10px; vertical-align: middle; }

/* ---------------------------------------------------------- deck catalog */
/* A card-index cabinet: wooden drawers with brass plates, holding paper index
   cards. Kept from the prototype, minus its webfonts - a CDN on the critical
   path of a page that otherwise loads entirely from this server. */
.cat-rail { display: flex; gap: 18px; overflow-x: auto; padding: 4px 2px 20px;
  scroll-snap-type: x proximity; }
.cat-drawer { flex: 0 0 280px; scroll-snap-align: start; display: flex;
  flex-direction: column; padding: 12px 12px 14px; border-radius: 10px;
  border: 1px solid #0c0805;
  background: linear-gradient(180deg, #54391f, #3b2917 14%, #2a1c10 100%);
  box-shadow: 0 1px 0 #6c4a28 inset, 0 14px 26px -12px #000a; }
.cat-drawer-open { background: linear-gradient(180deg, #3a3527, #2b2820 14%, #201d16 100%); }
.cat-drop { outline: 2px dashed var(--accent); outline-offset: -6px; }

.cat-plate { position: relative; margin-bottom: 12px; padding: 8px 42px 8px 12px;
  border: 1px solid #5b3f16; border-radius: 6px;
  background: linear-gradient(180deg, #f0d081, #c8974a 45%, #7c561f);
  box-shadow: 0 1px 0 #fbeec2 inset, 0 3px 7px -2px #000a; }
.cat-label { width: 100%; font: inherit; font-size: 15px; font-weight: 600;
  color: #241503; background: transparent; border: 0; outline: none;
  text-shadow: 0 1px 0 #f4dfa4; }
.cat-label:read-only { cursor: default; }
.cat-n { position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  padding: 1px 7px; font-size: 11px; font-weight: 600; color: #3a250a;
  background: #f3dca0; border: 1px solid #7c561f; border-radius: 20px;
  font-variant-numeric: tabular-nums; }

.cat-cards { flex: 1; display: flex; flex-direction: column; gap: 8px;
  min-height: 96px; padding: 6px 5px; border-radius: 6px; background: #0f140d;
  box-shadow: 0 2px 8px #0006 inset; }
.cat-card { position: relative; padding: 8px 26px 8px 12px; cursor: grab;
  border-radius: 3px 3px 4px 4px; border: 1px solid #cdbf9c;
  border-top: 3px solid #9e3b2f; color: #2b2318; font-size: 13px; line-height: 1.3;
  background: linear-gradient(180deg, #ece2ca, #e2d6b8);
  box-shadow: 0 2px 5px -1px #0008; }
.cat-card:active { cursor: grabbing; }
.cat-dragging { opacity: .4; }
.cat-name { display: block; color: #2b2318; text-decoration: none; font-weight: 600; }
.cat-name:hover { color: #7c2318; text-decoration: underline; }
.cat-meta { display: block; margin-top: 2px; font-size: 10px; color: #6a5c44; }
.cat-rm { position: absolute; top: 4px; right: 5px; padding: 2px; opacity: 0;
  color: #b0452f; font-size: 13px; line-height: 1; background: none; border: 0;
  cursor: pointer; }
.cat-card:hover .cat-rm, .cat-card:focus-within .cat-rm { opacity: .85; }
.cat-rm:hover { color: #7c2318; }

/* Drag-and-drop is unusable on a phone, so every card also carries this. */
.cat-move { display: flex; align-items: center; gap: 5px; margin-top: 5px; }
.cat-move-t { font-size: 10px; color: #6a5c44; }
.cat-move select { flex: 1; min-width: 0; padding: 1px 4px; font: inherit;
  font-size: 11px; color: #2b2318; background: #f6efdc; border: 1px solid #cdbf9c;
  border-radius: 4px; }

.cat-empty { margin: 0; padding: 22px 8px; text-align: center; font-size: 12px;
  font-style: italic; color: #5f6b56; }
.cat-foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 8px; }
/* A drawer with a link out of it, and the decks that link reaches. The mark is
   on every card rather than only on the drawer because the grant is live: what
   is shared is whatever is in here, so the card is where somebody finds out
   what dragging a deck in just did. */
.cat-card-shared { border-left: 3px solid var(--accent); padding-left: 9px; }
.cat-shared { color: var(--accent); font-size: 11px; text-transform: uppercase;
  letter-spacing: .04em; }
.cat-del { padding: 0; font: inherit; font-size: 11px; color: #8a7a5c;
  background: none; border: 0; cursor: pointer; }
.cat-del:hover { color: #d0705b; }

@media (max-width: 560px) { .cat-drawer { flex-basis: 84vw; } }
@media (prefers-reduced-motion: no-preference) {
  .cat-card { transition: transform .12s ease, box-shadow .12s ease; }
  .cat-card:hover { transform: translateY(-1px) rotate(-.35deg);
    box-shadow: 0 5px 10px -2px #0009; }
}

/* --- the play order ------------------------------------------------------- */
.pt-steps { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 var(--pad) 8px; }
.step-bar { display: flex; flex-wrap: wrap; gap: 3px; flex: 1 1 auto; min-width: 0; }
/* Every step is here, including the ones a table never says out loud, because
   being able to see them is the point. */
.step-pill { font-size: 11px; padding: 3px 8px; border-radius: 999px; cursor: pointer;
  background: var(--surface-2); color: var(--muted); border: 1px solid transparent;
  white-space: nowrap; }
.step-pill:hover { border-color: var(--accent); color: var(--accent); }
/* the two steps where no player receives priority — nothing can happen in them,
   and they should not look like a window you could act in */
.step-pill.nopri { opacity: .55; font-style: italic; }
.step-pill.now { background: var(--accent); color: var(--accent-ink); font-weight: 700;
  opacity: 1; font-style: normal; }
.pt-fmt { font-size: 12px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .05em; }
/* arrived this turn, no haste */
.pt-sick { position: absolute; bottom: 4px; left: 4px; width: 16px; height: 16px;
  border-radius: 50%; background: rgba(15,13,10,.8); color: #d8d2c6; font-size: 10px;
  font-weight: 700; display: flex; align-items: center; justify-content: center; }

/* --- sideboarding between games ------------------------------------------- */
.sb-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.sb-h { font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin: 0 0 6px; }
.sb-h span { color: var(--accent); font-variant-numeric: tabular-nums; }
.sb-list { max-height: 46vh; overflow-y: auto; scrollbar-width: thin; }
@media (max-width: 560px) { .sb-cols { grid-template-columns: 1fr; } }

/* --- limited: draft, sealed, block, chaos ----------------------------------------------------------- */
.lt-controls { flex-wrap: wrap; row-gap: 10px; }
.lt-controls label { display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--muted); }
.lt-eras { display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.status-bad { color: #d98b6a; }

.lt-seat { margin-bottom: 26px; }
.lt-seat-h { font-size: 15px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--accent); margin: 0 0 10px; padding-bottom: 6px;
  border-bottom: 1px solid var(--line); }

.lt-pack { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px; }
.lt-pack-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px; font-size: 14px; }
.lt-round { font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); }
/* set code and year read as metadata, so they sit back from the set's name */
.lt-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; color: var(--accent); }
.lt-year, .lt-era-tag { font-size: 12px; color: var(--muted); }
.lt-era-tag { padding: 1px 7px; border: 1px solid var(--line); border-radius: 999px; }
.lt-short { font-size: 12px; color: #d98b6a; }

.lt-grid { display: grid; gap: 8px; list-style: none; padding: 0; margin: 0;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.lt-card { position: relative; }
.lt-card img { width: 100%; display: block; border-radius: 6px;
  border: 1px solid var(--line); background: var(--surface-2); }
.lt-card img:hover { border-color: var(--accent); }
/* The rarity stripe is the only cue that survives shrinking a card to a
   thumbnail — at 96px the set symbol's colour is a few pixels. */
.lt-card::before { content: ""; position: absolute; left: 0; right: 0; top: -3px;
  height: 3px; border-radius: 3px; background: var(--line); }
.lt-card.r-uncommon::before { background: #9fb3c8; }
.lt-card.r-rare::before     { background: #d4b45a; }
.lt-card.r-mythic::before   { background: #d1682a; }
/* the name is for the no-art case and for anyone reading rather than looking */
.lt-name { display: block; font-size: 11px; color: var(--muted); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lt-noart { display: flex; align-items: center; justify-content: center;
  aspect-ratio: 5 / 7; padding: 6px; font-size: 11px; text-align: center;
  color: var(--muted); background: var(--surface-2); border: 1px dashed var(--line);
  border-radius: 6px; }

.lt-list { margin: 0; padding-left: 26px; column-width: 220px; column-gap: 24px; }
.lt-list li { font-size: 13px; margin-bottom: 2px; break-inside: avoid; }
.lt-r { display: inline-block; width: 14px; font-weight: 700; color: var(--accent); }
.lt-cn { color: var(--muted); font-size: 11px; }

.lt-seed { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin: 20px 0 40px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lt-seed label { display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--muted); flex: 1 1 260px; }
.lt-seed input { flex: 1; min-width: 180px; font-family: ui-monospace, monospace;
  font-size: 13px; padding: 6px 8px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); }
.lt-seed .hint { flex-basis: 100%; margin: 0; }

/* Printing a draft is a real use — someone reads the packs off paper while the
   pod opens them. Drop the app furniture and let the packs break across pages. */
@media print {
  .topbar, .lt-controls, .lt-seed, #ltStatus, footer { display: none !important; }
  .lt-pack { break-inside: avoid; border-color: #999; }
  .lt-seat-h { color: #000; }
}

/* --- limited: the section's own furniture ---------------------------------- */
/* Mode tiles. Same 34px medallion the home page uses, on purpose: a
   destination should look the same wherever it's offered. */
.lt-modes { display: grid; gap: 12px; margin-bottom: 20px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.lt-mode { display: grid; grid-template-columns: 34px 1fr; align-items: center;
  column-gap: 12px; row-gap: 2px; padding: 16px 18px; text-align: left;
  color: var(--text); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
  transition: border-color .15s ease, transform .15s ease; }
.lt-mode:hover { border-color: var(--accent); transform: translateY(-2px); }
.lt-mode.on { border-color: var(--accent); background: var(--surface-2); }
.lt-mode-ic { grid-row: 1 / 3; width: 34px; height: 34px; border-radius: 8px;
  object-fit: cover; }
.lt-mode-t { font-size: 17px; font-weight: 600; }
.lt-mode-s { font-size: 12px; color: var(--muted); }

.lt-panel { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 18px; }
.lt-panel-h { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.lt-panel-h h2 { margin: 0; font-size: 18px; }
.lt-panel-h .hint { margin: 2px 0 0; }
.lt-panel-h > button { margin-left: auto; flex: none; }
.lt-panel-ic { width: 42px; height: 42px; border-radius: 9px; object-fit: cover;
  flex: none; }

.lt-rules { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 12px 0; margin-bottom: 12px; }
.lt-rules-grid { display: grid; gap: 8px 18px; margin: 0;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.lt-rule dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); }
.lt-rule dd { margin: 1px 0 0; font-size: 13px; }
.lt-rule-notes { font-size: 13px; color: var(--text); margin: 12px 0 6px; }

.lt-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  row-gap: 10px; }
.lt-controls label { display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--muted); }
.lt-controls select { max-width: 320px; }
/* A locked option is still shown, so it reads as a property of the format
   rather than as a control that went missing. */
.lt-locked-opt { opacity: .75; }
/* An option the chosen pool can't offer — collector boosters on a 1997 set.
   Fainter than locked, and struck through, so the two greys don't read as the
   same state: one is on and can't be turned off, the other isn't there at all.
   The title says which set is the reason. */
.lt-opt-off { opacity: .45; text-decoration: line-through;
  text-decoration-thickness: 1px; cursor: not-allowed; }

/* Cards open in a panel rather than a new tab: a pod is all looking at this
   page together, and navigating away costs everyone their place. */
.lt-zoom { position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; padding: 24px; }
.lt-zoom-scrim { position: absolute; inset: 0; background: rgba(8,7,5,.82); }
.lt-zoom-panel { position: relative; margin: 0; display: flex; flex-direction: column;
  align-items: center; gap: 10px; max-height: 100%; }
.lt-zoom-panel img { max-width: min(88vw, 480px); max-height: 78vh; width: auto;
  border-radius: 14px; box-shadow: 0 18px 50px rgba(0,0,0,.6); }
.lt-zoom-panel figcaption { font-size: 13px; color: var(--text); text-align: center; }
.lt-zoom-x { position: absolute; top: -14px; right: -14px; width: 34px; height: 34px;
  border-radius: 50%; font-size: 15px; line-height: 1; cursor: pointer;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line); }
.lt-zoom-x:hover { border-color: var(--accent); color: var(--accent); }
body.lt-locked { overflow: hidden; }

/* the card itself is a button now, so it needs the button reset */
.lt-card-btn { display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: zoom-in; }

/* the chaos pack filter — which sets are in the hat */
.lt-packs { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 8px 12px; margin-bottom: 12px; background: var(--surface-2); }
.lt-packs summary { cursor: pointer; font-size: 13px; color: var(--muted); }
.lt-packs-n { color: var(--accent); font-variant-numeric: tabular-nums; }
.lt-packs-n.lt-packs-short { color: #d98b6a; }
.lt-packs-acts { display: flex; gap: 8px; align-items: center; margin: 10px 0 8px;
  flex-wrap: wrap; }
.lt-packs-acts input { flex: 1; min-width: 160px; font-size: 13px; padding: 6px 8px;
  color: var(--text); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); }
.lt-packs-list { max-height: 320px; overflow-y: auto; scrollbar-width: thin;
  display: grid; gap: 2px 16px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.lt-pack-opt { display: flex; align-items: baseline; gap: 6px; font-size: 13px;
  padding: 2px 0; }
.lt-pack-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lt-pack-opt .lt-year { margin-left: auto; }
.import-btn:disabled { opacity: .5; cursor: not-allowed; }

/* --- building a deck out of a pool ----------------------------------------- */
.bd-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; row-gap: 10px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 12px; }
.bd-toolbar label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px;
  color: var(--muted); }
.bd-toolbar input[type="number"] { width: 68px; }
.bd-toolbar input, .bd-toolbar select { font-size: 13px; padding: 6px 8px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); }
.bd-toolbar input[type="search"] { flex: 1; min-width: 150px; }
.bd-tally { font-size: 15px; color: var(--muted); }
.bd-tally b { font-size: 22px; color: var(--text); font-variant-numeric: tabular-nums; }
.bd-short { margin-left: 8px; font-size: 12px; }
.bd-short.bd-bad { color: #d98b6a; }
.bd-short.bd-ok { color: var(--accent); }

/* The curve is the one thing a limited deck lives or dies by, so it gets to be
   a picture rather than a table. Three fixed rows per column — count, track,
   label — so the bars grow from a baseline that stays put. */
.bd-curve { display: grid; grid-template-columns: repeat(8, 1fr); gap: 6px;
  height: 104px; margin-bottom: 16px; }
.bd-cbar { display: grid; grid-template-rows: 15px 1fr 15px; min-width: 0; }
.bd-cbar-n, .bd-cbar-l { font-size: 11px; line-height: 15px; color: var(--muted);
  text-align: center; }
.bd-cbar-w { display: flex; align-items: flex-end; }
.bd-cbar-f { width: 100%; background: var(--accent); border-radius: 3px 3px 0 0;
  min-height: 2px; }
.bd-cbar-l { border-top: 1px solid var(--line); }

.bd-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 40px; }
.bd-col { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; min-width: 0; }
.bd-h { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 0 0 8px; }
.bd-h span { color: var(--accent); font-variant-numeric: tabular-nums; }
.bd-cmd { border-bottom: 1px solid var(--line); padding-bottom: 10px; margin-bottom: 10px; }
.bd-list { max-height: 62vh; overflow-y: auto; scrollbar-width: thin; }

/* A row, not a tile: a 90-card pool read as pictures is a scroll marathon, and
   the thing you are actually doing is comparing costs and colours. Hover and
   click still give you the card. */
.bd-row { display: flex; align-items: center; gap: 6px; padding: 1px 0;
  border-left: 3px solid var(--line); padding-left: 6px; margin-bottom: 2px; }
.bd-row.r-uncommon { border-left-color: #9fb3c8; }
.bd-row.r-rare     { border-left-color: #d4b45a; }
.bd-row.r-mythic   { border-left-color: #d1682a; }
.bd-move { flex: none; width: 22px; height: 22px; border-radius: 6px; font-size: 14px;
  line-height: 1; cursor: pointer; color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--line); }
.bd-move:hover { border-color: var(--accent); color: var(--accent); }
.bd-name { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px;
  padding: 2px 0; text-align: left; background: none; border: 0; cursor: zoom-in;
  color: var(--text); font-size: 13px; }
.bd-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-name:hover .bd-nm { color: var(--accent); }
.bd-cost { flex: none; font-size: 11px; color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.bd-r { flex: none; font-size: 11px; color: var(--muted); width: 12px; text-align: center; }
.bd-cmd-btn { flex: none; width: 20px; height: 20px; border-radius: 5px; font-size: 11px;
  line-height: 1; cursor: pointer; color: var(--accent); background: var(--surface-2);
  border: 1px solid var(--line); }
.bd-cmd-btn:hover { border-color: var(--accent); }

@media (max-width: 720px) { .bd-cols { grid-template-columns: 1fr; } }

/* --- a card face drawn from fields ----------------------------------------- */
/* Deliberately not a replica: no Wizards frame art, no set symbol, no mana
   symbol artwork, and a mark in the footer saying what it is. Those assets
   aren't ours to ship, and a proxy that can be mistaken for a real card is a
   worse object than one that can't be.

   None of that is a reason for it to look like a wireframe, which is what the
   first pass was: three identical flat panels on a flat field, with the colours
   desaturated so far towards grey that every card looked like the same card.
   What makes a printed card look printed isn't the frame art — it's depth,
   hierarchy and paper. All three are free.

   Every colour here is a gradient with a light source at the top, every plate
   is bevelled against the frame it sits on, and the whole thing carries a faint
   grain so it reads as stock rather than as a div. */

.cf {
  position: relative;
  width: 100%; max-width: 300px; aspect-ratio: 5 / 7;
  display: flex; flex-direction: column; gap: 5px;
  padding: 11px 10px 10px;
  /* A real card's corner is about 1/16" on a 2.5" card. At 300px that is 12px,
     and matching it is what stops the shape reading as "rounded box". */
  border-radius: 13px;
  /* The black border is the border, not a hairline: it is most of what says
     "card" before any of the contents are read. */
  border: 5px solid #0d0c0a;
  background:
    /* grain, twice, at angles that don't moiré against each other */
    repeating-linear-gradient(52deg, rgba(255,255,255,.035) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-38deg, rgba(0,0,0,.03) 0 1px, transparent 1px 4px),
    /* the frame itself, lit from the top */
    linear-gradient(168deg, var(--cf-bg2, #4a4a42) 0%, var(--cf-bg, #3a3a34) 46%,
                    var(--cf-bg-d, #2c2c26) 100%);
  box-shadow:
    0 10px 26px rgba(0,0,0,.45),
    0 2px 6px rgba(0,0,0,.35),
    /* the bevel that lifts the frame off its own border */
    inset 0 1px 0 rgba(255,255,255,.28),
    inset 0 -1px 0 rgba(0,0,0,.28);
  font-size: 12px;
  color: var(--cf-ink, #17150f);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Frame colours. Saturated now, and each is three stops so the frame has a
   direction. --cf-box is the text plate, kept close to paper so rules text
   stays black-on-cream rather than black-on-colour. */
.cf-w { --cf-bg: #e8d9ae; --cf-bg2: #f6ecd2; --cf-bg-d: #c9b483; --cf-box: #fbf6e6; }
.cf-u { --cf-bg: #6ea3c9; --cf-bg2: #9cc6e4; --cf-bg-d: #40739b; --cf-box: #e6f0f8; }
.cf-b { --cf-bg: #5e5852; --cf-bg2: #8a827a; --cf-bg-d: #35312d;
        --cf-box: #ddd7d0; --cf-ink: #14120f; }
.cf-r { --cf-bg: #d4714b; --cf-bg2: #ec9a72; --cf-bg-d: #a04c2c; --cf-box: #fae2d5; }
.cf-g { --cf-bg: #6d9c69; --cf-bg2: #9bc294; --cf-bg-d: #456a42; --cf-box: #e2eede; }
/* gold: two or more colours */
.cf-m { --cf-bg: #cfae5c; --cf-bg2: #ecd692; --cf-bg-d: #9b7f34; --cf-box: #f7eecd; }
/* Artifact, and colourless-but-not-an-artifact, which used to be one frame.
   They cannot be: black is a warm mid grey and the old colourless frame was the
   same warm grey a shade lighter, so at tile size an artifact and a black card
   were telling apart by brightness alone — which survives neither a dim room
   nor a battlefield where every card is 84px wide.

   Artifact gets a cool gunmetal instead. It is the one hue nothing else here
   claims: black and land are warm, blue is saturated and cyan, and a
   desaturated steel reads as metal rather than as a colour, which is what an
   artifact is. 2,909 colourless cards in this corpus are artifacts, so this is
   the frame that had to move.

   What is left in .cf-c is Eldrazi and devoid — colourless and not made of
   metal. Paler and flatter than it was, because its job now is only to not be
   black, and because a bone-grey is the right feel for a card with no colour
   at all rather than one with a colour it is hiding. */
.cf-a { --cf-bg: #7d8790; --cf-bg2: #a9b1b8; --cf-bg-d: #565f67; --cf-box: #e8ebee; }
.cf-c { --cf-bg: #bdb8b0; --cf-bg2: #dad6cf; --cf-bg-d: #918c84; --cf-box: #f1efeb; }
/* land */
.cf-l { --cf-bg: #9a8161; --cf-bg2: #bfa683; --cf-bg-d: #6d5940; --cf-box: #ece0cd; }

/* Snow is a supertype, not a colour, so it is a treatment laid over whatever
   frame the card already has rather than a frame of its own. A Snow Creature
   can be blue, colourless or five-coloured, and all three have to still read as
   their colour underneath.

   Frost from the corners and a cold cast over the whole face — enough to be
   unmistakable next to the same card without it, not enough to argue with the
   colour it is sitting on. `screen` keeps the pale tint from muddying a dark
   frame the way an opaque overlay would. */
.cf-is-snow::before {
  content: ""; position: absolute; inset: 0;
  border-radius: 8px; pointer-events: none; z-index: 0;
  mix-blend-mode: screen;
  background:
    radial-gradient(120% 80% at 0% 0%, rgba(214,238,250,.52) 0%, transparent 56%),
    radial-gradient(120% 80% at 100% 100%, rgba(214,238,250,.40) 0%, transparent 56%),
    /* the crystal grain: three angles, none of them regular enough to read as
       stripes at the size a card is actually looked at */
    repeating-linear-gradient(24deg, rgba(232,246,255,.20) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(-51deg, rgba(232,246,255,.16) 0 1px, transparent 1px 11px),
    repeating-linear-gradient(97deg, rgba(232,246,255,.11) 0 1px, transparent 1px 5px);
}
/* Everything the card draws sits above the frost, or the frost would wash out
   the rules text it is meant to be behind. */
.cf-is-snow > * { position: relative; z-index: 1; }
/* The text plate cools with it, so the card doesn't read as a warm card with a
   blue sheet over it. As an extra layer keyed off a variable rather than a
   redefinition of --cf-box: a custom property cannot be defined in terms of
   itself, and restating the plate's own gradient here would leave two copies to
   keep in step. */
.cf-is-snow { --cf-frost: rgba(186,218,238,.32); }

/* The plates. Title and type line are the same object at two weights, pressed
   into the frame rather than laid on top of it — the inset highlight above and
   shadow below is the whole trick. */
.cf-title, .cf-type {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 8px;
  border-radius: 7px;
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--cf-box) 96%, #fff) 0%,
              color-mix(in srgb, var(--cf-box) 88%, #000) 100%);
  border: 1px solid rgba(0,0,0,.38);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7),
              0 1px 0 rgba(255,255,255,.16);
}
.cf-name {
  flex: 1; min-width: 0;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
               Georgia, serif;
  font-weight: 600; font-size: 13px; letter-spacing: .005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cf-cost { flex: none; display: flex; gap: 2px; }
.cf-type span:first-child {
  flex: 1; min-width: 0; font-size: 10.5px; font-weight: 500;
  letter-spacing: .01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Mana, as a mark in a coloured disc. Not WotC's symbol artwork — the idea,
   not their drawing of it — so it gets a set of our own.

   The disc, its edge, the highlight and the mark are all drawn inside the SVG
   (cardface.js, from the files in /mana_symbols), which is why there is so
   little here: a pip is a 15px box, and everything visible is its contents.
   The one thing CSS still owns is the lift off the card, because a drop shadow
   has to follow the drawn shape rather than the box around it. */
.cf-pip { display: inline-block; width: 15px; height: 15px; line-height: 0; }
.cf-sym {
  display: block; width: 100%; height: 100%;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,.4));
}
.cf-box .cf-pip { width: 12px; height: 12px; vertical-align: -2px; }

/* Art is recessed into the frame, which is the other half of the depth. */
.cf-art {
  /* `fill`: the picture is stretched to the window. Not `cover`, which blows it
     up until it fills and cuts the edges off; not `contain`, which fits all of
     it and leaves bars. All of the art, none of the bars, and the price is that
     a picture generated at the wrong ratio comes out distorted rather than
     cropped — which is at least visible, and fixable by regenerating at the
     window's own 5:3. */
  width: 100%; flex: 0 0 42%; object-fit: fill;
  /* An image is a replaced element, so its automatic minimum size in a column
     flex container is its own scaled height — which overrides the 42% basis and
     lets a square or portrait upload take the card over. A tall one stretched
     the card past its own aspect-ratio and squeezed the rules box to nothing.
     The placeholder never showed it because a <div>'s min-content height is 0.
     Same fix as `.cf-half .cf-art` below, which hit this first. */
  min-height: 0;
  border-radius: 5px;
  border: 1px solid rgba(0,0,0,.5);
  /* Dark enough to read as a matte the art is mounted on. Since `contain`, this
     is what shows beside a picture that isn't the window's shape, and a pale
     one left the art looking like it was floating in a gap. */
  background: rgba(0,0,0,.38);
  box-shadow: inset 0 2px 6px rgba(0,0,0,.5), 0 1px 0 rgba(255,255,255,.18);
}
.cf-art-none {
  display: flex; align-items: center; justify-content: center;
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.34);
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.045) 0 6px, transparent 6px 12px),
    rgba(0,0,0,.24);
}

.cf-box {
  flex: 1; min-height: 0; overflow: hidden;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid rgba(0,0,0,.38);
  /* --cf-frost is transparent unless a treatment sets it (Snow does), so the
     layer costs nothing on an ordinary card and the plate's own gradient is
     only written once. */
  background:
    linear-gradient(var(--cf-frost, transparent), var(--cf-frost, transparent)),
    linear-gradient(180deg,
              color-mix(in srgb, var(--cf-box) 97%, #fff) 0%,
              color-mix(in srgb, var(--cf-box) 90%, #000) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7);
  display: flex; flex-direction: column; gap: 3px;
}
.cf-rules p { margin: 0 0 4px; font-size: 10.5px; line-height: 1.36; }
.cf-rules p:last-child { margin-bottom: 0; }
.cf-rem { opacity: .72; font-style: italic; }
/* The hairline before flavour is how a card separates what it does from what
   it says. */
.cf-flavour {
  margin: auto 0 0; padding-top: 5px;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 9.8px; font-style: italic; line-height: 1.35; opacity: .8;
  border-top: 1px solid rgba(0,0,0,.18);
  box-shadow: 0 -1px 0 rgba(255,255,255,.5);
}

.cf-foot {
  display: flex; align-items: center; gap: 6px;
  font-size: 9px; letter-spacing: .02em;
  color: rgba(255,255,255,.88);
  text-shadow: 0 1px 1px rgba(0,0,0,.55);
  min-height: 15px;
}
.cf-set { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- a token, laid out the way a printed one is ---------------------------
   Nothing under the text box, and the stat in the corner plate rather than in
   a row. A printed card hangs that plate off the bottom-right edge, half on the
   frame and half off it, and getting that one detail right is most of what
   makes the shape read as a card before a word of it has been looked at.

   Drawn here, not borrowed: none of this is Wizards' frame art. */
.cf-token { padding-bottom: 12px; }
.cf-token .cf-box { flex: 1 1 auto; }
.cf-token .cf-corner {
  position: absolute; right: 6px; bottom: 4px; margin: 0;
  padding: 2px 10px; border-radius: 7px;
  /* Reads as a plate sitting ON the frame: a hard edge, a lift, and a shadow
     under it. Without the shadow it looks printed onto the card rather than
     laid over it, which is the difference a real one has. */
  border: 1px solid rgba(0,0,0,.5);
  box-shadow: 0 1px 0 rgba(255,255,255,.35) inset, 0 2px 5px rgba(0,0,0,.5);
  z-index: 2;
}
/* At tile size the corner plate would cover the last line of the text box, so
   the box gets out of its way rather than the plate shrinking into a smudge. */
.cf-token .cf-rules { padding-right: 34px; }

/* The hovered face. Same size and the same place as the hovered image, because
   they are two ways of showing one thing and a preview that moved depending on
   which kind of card it was would read as two features. */
#hoverFace { position: fixed; z-index: 60; width: 260px; pointer-events: none;
  filter: drop-shadow(0 12px 28px rgba(0,0,0,.55)); }
#hoverFace .cf { max-width: none; }
.cf-mark { opacity: .72; flex: none; }

/* Power/toughness, defense and loyalty all land here, in the corner plate a
   card puts them in. */
.cf-stat {
  margin-left: auto; flex: none;
  padding: 2px 9px; border-radius: 6px;
  font-family: "Iowan Old Style", Palatino, Georgia, serif;
  font-size: 12.5px; font-weight: 700; line-height: 1.1;
  color: var(--cf-ink, #17150f);
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--cf-box) 98%, #fff) 0%,
              color-mix(in srgb, var(--cf-box) 86%, #000) 100%);
  border: 1px solid rgba(0,0,0,.5);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.75), 0 1px 3px rgba(0,0,0,.4);
}

/* A letter, not a set symbol — but a letter can still be a nicely cut gem. */
.cf-rarity {
  flex: none; width: 15px; height: 15px; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; font-weight: 700; color: #fff;
  background: linear-gradient(160deg, #55524a, #2e2c27);
  border: 1px solid rgba(0,0,0,.45);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.3);
  text-shadow: 0 1px 1px rgba(0,0,0,.6);
}
.cf-r-uncommon { background: linear-gradient(160deg, #93a9bd, #4e647a); }
.cf-r-rare     { background: linear-gradient(160deg, #d8bb62, #8a6f24); }
.cf-r-mythic   { background: linear-gradient(160deg, #e08040, #9c3a12); }

/* --- the custom card workshop ---------------------------------------------- */
.cc-wrap { display: grid; grid-template-columns: 280px 1fr; gap: 16px;
  margin-bottom: 20px; align-items: start; }
.cc-shelf { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px; }
.cc-shelf-acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 8px; }
.cc-shelf input[type="search"] { width: 100%; font-size: 13px; padding: 6px 8px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 8px; }
.cc-list { list-style: none; margin: 0; padding: 0; max-height: 64vh;
  overflow-y: auto; scrollbar-width: thin; }
.cc-list .hint { padding: 8px 2px; }
.cc-item { display: grid; grid-template-columns: 1fr auto auto; gap: 2px 6px;
  width: 100%; text-align: left; padding: 6px 8px; margin-bottom: 3px;
  color: var(--text); background: none; border: 1px solid transparent;
  border-radius: var(--radius); cursor: pointer; }
.cc-item:hover { border-color: var(--line); }
.cc-item.on { background: var(--surface-2); border-color: var(--accent); }
.cc-item-n { font-size: 13px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.cc-item-cost { display: flex; gap: 2px; }
.cc-item-t { grid-column: 1 / -1; font-size: 11px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-item-base { color: var(--accent); font-size: 11px; }

.cc-editor { display: grid; grid-template-columns: 1fr 320px; gap: 18px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; align-items: start; }
.cc-fields { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.cc-fields label { display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--muted); }
.cc-fields label.import-mode { flex-direction: row; align-items: center; gap: 7px; }
.cc-fields input[type="text"], .cc-fields textarea, .cc-fields select {
  font-size: 13px; padding: 6px 8px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); font-family: inherit; }
.cc-fields textarea { resize: vertical; }
.cc-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.cc-row > label { flex: 0 1 auto; }
.cc-row > label.cc-grow { flex: 1 1 180px; }
.cc-acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding-top: 4px; }
.cc-preview { display: flex; flex-direction: column; align-items: center; gap: 10px; }
/* A fixed box, because a preview that resizes itself to its contents is not a
   preview. #ccFace was a bare div in a centred flex column, so it took its
   width from the card inside it, and the card took its width from `100%` of
   that — circular, resolved by shrinking to the text. A plain creature came out
   171px wide and a Room 310px, and nothing about the card was to blame.
   420 = 300 × 1.4, so a landscape card gets the same area as a portrait one
   rather than half of it: it is the same card turned, not a smaller card. */
#ccFace { width: 420px; max-width: 100%; }
#ccFace .cf { margin-inline: auto; }
.cc-preview .hint { text-align: center; margin: 0; }

.cc-ai { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 40px; }
.cc-ai .cc-row { align-items: flex-end; margin-top: 8px; }
.cc-ai label { display: flex; flex-direction: column; gap: 4px; font-size: 12px;
  color: var(--muted); }
.cc-ai label.import-mode { flex-direction: row; align-items: center; gap: 7px; }
.cc-ai input[type="text"] { font-size: 13px; padding: 6px 8px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); }
.cc-ai-notes { font-size: 12px; color: var(--muted); font-style: italic;
  margin: 10px 0 0; }

@media (max-width: 900px) {
  .cc-wrap { grid-template-columns: 1fr; }
  .cc-editor { grid-template-columns: 1fr; }
  .cc-list { max-height: 34vh; }
}
/* Printing a custom card is the point of having one — drop everything else. */
@media print {
  .topbar, .cc-shelf, .cc-fields, .cc-ai, #ccStatus, footer { display: none !important; }
  .cc-wrap, .cc-editor { display: block; border: 0; padding: 0; background: none; }
  .cf { max-width: 63mm; box-shadow: none; }
}

/* --- long-form format rules ------------------------------------------------ */
/* Only the formats nobody else has written rules for carry one of these; the
   rest link out to an official document instead. Folded shut by default so a
   page of twenty-eight formats doesn't become a book. */
.rule-full { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
.rule-full summary { cursor: pointer; font-size: 12px; color: var(--accent);
  text-transform: uppercase; letter-spacing: .06em; }
.rule-md { margin-top: 10px; font-size: 13px; line-height: 1.5; }
.rule-md h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin: 14px 0 6px; }
.rule-md h3:first-child { margin-top: 0; }
.rule-md ul { margin: 0 0 8px; padding-left: 20px; }
.rule-md li { margin-bottom: 3px; }
.rule-md p { margin: 0 0 8px; }
.rule-md strong { color: var(--text); }
.rule-md em { color: var(--muted); }

/* the same plate on the desktop board */
.pt-plate { display: flex; flex-direction: column; gap: 2px;
  /* Fills the tile, which is the thing that carries the card shape. */
  width: 100%; height: 100%;
  padding: 5px; border-radius: 6px; background: var(--surface-2);
  border: 1px solid var(--line); overflow: hidden; }
.pt-plate-n { font-size: 10px; font-weight: 700; line-height: 1.15; color: var(--text); }
.pt-plate-c { font-size: 8px; color: var(--accent); font-family: ui-monospace, monospace; }
.pt-plate-t { font-size: 8px; color: var(--muted); }
/* The one part that may shrink. aspect-ratio gives the plate a card's
   height, but content taller than that still pushes the box out unless
   something is allowed to give — and the rules text is the part a tile has
   least room for. flex-basis 0 with min-height 0 lets it clip instead. */
.pt-plate-r { flex: 1 1 0; min-height: 0; font-size: 8px; line-height: 1.25;
  color: var(--text); overflow: hidden; }
.pt-plate-pt { margin-top: auto; align-self: flex-end; font-size: 11px; font-weight: 700;
  color: var(--text); }

/* --- base commanders in the pool builder ----------------------------------- */
.bd-cmd-row { border-left-color: var(--accent); }
.bd-base-tag { flex: none; font-size: 11px; color: var(--accent); }
.bd-partner { flex: none; font-size: 9px; color: var(--muted); letter-spacing: -1px; }
#bdBasePick { margin-top: 8px; }

.bd-bases-panel { position: relative; width: min(1100px, 94vw); max-height: 88vh;
  overflow-y: auto; scrollbar-width: thin; padding: 16px 18px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 18px 50px rgba(0,0,0,.6); }
.bd-bases-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bd-bases-head h2 { margin: 0; font-size: 18px; }
.bd-base-n { font-size: 12px; color: var(--accent); font-variant-numeric: tabular-nums; }
.bd-bases-head input { width: 70px; font-size: 13px; padding: 5px 7px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius);
  text-transform: uppercase; }
.bd-bases-x { position: static; margin-left: auto; }

.bd-base-grid { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.bd-base button { width: 100%; padding: 0; background: none; border: 0; cursor: pointer;
  border-radius: 14px; transition: transform .12s ease; }
.bd-base button:hover { transform: translateY(-3px); }
/* A chosen one stays in the list, ringed — clicking it again is how you undo. */
.bd-base.on button { outline: 2px solid var(--accent); outline-offset: 3px; }
.bd-base .cf { max-width: none; }

.bd-zoom-face { width: min(88vw, 320px); }

/* --- drafting against bots -------------------------------------------------- */
.dr-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; row-gap: 10px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px; }
.dr-tally { font-size: 15px; color: var(--muted); }
.dr-tally b { font-size: 18px; color: var(--text); }
.dr-dir { font-size: 12px; color: var(--accent); text-transform: uppercase;
  letter-spacing: .06em; }
.dr-pooln { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }

.dr-table { display: grid; grid-template-columns: 1fr 300px; gap: 16px;
  align-items: start; margin-bottom: 40px; }
.dr-h { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 0 0 8px; }
.dr-h span { color: var(--accent); font-variant-numeric: tabular-nums; }
.dr-pack-col, .dr-pool-col { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; min-width: 0; }
/* The pack is the thing you're looking at, so it gets bigger cards than the
   pack view does — you're reading them to choose, not counting them. */
.dr-pack { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
.dr-take { display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: pointer; border-radius: 8px; transition: transform .12s ease; }
.dr-take:hover { transform: translateY(-4px); }
.dr-take img { width: 100%; display: block; border-radius: 6px;
  border: 1px solid var(--line); }
.dr-take:hover img { border-color: var(--accent); }

.dr-pool { max-height: 70vh; overflow-y: auto; scrollbar-width: thin; }
.dr-pool-g { margin-bottom: 10px; }
.dr-pool-g h3 { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin: 0 0 3px; }
.dr-pool-g h3 span { color: var(--accent); }
.dr-pool-row { display: flex; border-left: 3px solid var(--line); padding-left: 6px;
  margin-bottom: 1px; }
.dr-pool-row.r-uncommon { border-left-color: #9fb3c8; }
.dr-pool-row.r-rare     { border-left-color: #d4b45a; }
.dr-pool-row.r-mythic   { border-left-color: #d1682a; }

.dr-done { background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px; text-align: center;
  margin-bottom: 40px; }
.dr-done h2 { margin: 0 0 6px; }
.dr-done .hint { margin: 0 0 14px; }

@media (max-width: 820px) { .dr-table { grid-template-columns: 1fr; } }

/* --- packs you haven't opened yet ------------------------------------------ */
/* The wrapper still names the set — you can read that off a real one too. What
   it doesn't say is what's inside. */
.lt-pack-shut { border-style: dashed; }
.lt-wrapped { display: flex; align-items: center; gap: 12px; padding: 18px 6px; }
.lt-open { padding: 8px 16px; font-size: 14px; cursor: pointer; color: var(--accent-ink);
  background: var(--accent); border: 1px solid var(--accent);
  border-radius: var(--radius); font-weight: 500; }
.lt-open:hover { filter: brightness(1.08); }
.lt-wrapped-n { font-size: 12px; color: var(--muted); }
.lt-locked-opt { opacity: .75; }

/* --- announcements, and the revision list they double as -------------------- */
/* A corner panel rather than a modal over the page. What it has to say is worth
   an interruption once; it is not worth taking the page away from somebody who
   came here to build a deck. */
.bm-ann { position: fixed; right: 16px; bottom: 16px; z-index: 90;
  width: min(360px, calc(100vw - 32px)); background: var(--surface);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: 12px 14px 14px;
  box-shadow: 0 10px 30px rgba(0,0,0,.45); }
/* Downtime is the one kind that is about to cost somebody something, so it is
   the one kind that doesn't look like the others. */
.bm-ann[data-kind="downtime"] { border-left-color: #d08a3a; }
.bm-ann-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.bm-ann-ic { font-size: 15px; }
.bm-ann-kind { font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); }
.bm-ann-n { font-size: 11px; color: var(--muted); margin-left: auto; }
.bm-ann-x { margin-left: auto; background: none; border: 0; color: var(--muted);
  font-size: 20px; line-height: 1; cursor: pointer; padding: 0 2px; }
.bm-ann-n + .bm-ann-x { margin-left: 6px; }
.bm-ann-x:hover { color: var(--ink); }
.bm-ann-t { margin: 0 0 4px; font-size: 15px; }
.bm-ann-v { font-size: 11px; color: var(--muted); font-weight: 400; }
.bm-ann-when { margin: 0 0 6px; font-size: 12px; color: #d9a25f; }
.bm-ann-body { font-size: 13px; color: var(--muted); }
.bm-ann-body p { margin: 0 0 6px; }
.bm-ann-more { margin: 8px 0 0; font-size: 12px; }

@media (max-width: 560px) {
  /* Full width at the bottom on a phone: a 360px card floating in a corner is
     a card floating over the thumb. */
  .bm-ann { right: 8px; left: 8px; bottom: 8px; width: auto; }
}

.rev-list { list-style: none; margin: 0; padding: 0; }
.rev { border-top: 1px solid var(--line); padding: 12px 0; }
.rev:first-child { border-top: 0; }
.rev-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.rev-v { font-size: 11px; color: var(--accent-ink); background: var(--accent);
  border-radius: 999px; padding: 2px 8px; font-weight: 600; }
.rev-t { font-size: 15px; }
.rev-d { font-size: 12px; color: var(--muted); margin-left: auto; }
.rev-b { font-size: 13px; color: var(--muted); margin-top: 4px; }
.rev-b p { margin: 0 0 6px; }

/* --- the admin screen ------------------------------------------------------- */
.ad-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 16px; margin-bottom: 10px; }
.ad-grid > label { display: flex; flex-direction: column; gap: 4px;
  font-size: 13px; color: var(--muted); }
.ad-grid .ad-wide { grid-column: 1 / -1; }
.ad-grid .ad-check { flex-direction: row; align-items: center; gap: 8px;
  grid-column: 1 / -1; }
/* Form controls are styled per section in this stylesheet rather than globally,
   so a new page that doesn't say this gets the browser's white boxes on a dark
   background. Every assertion passed and the screenshot showed it immediately. */
.ad-grid input[type="text"], .ad-grid input[type="datetime-local"],
.ad-grid textarea, .ad-grid select {
  font-size: 13px; padding: 6px 8px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); font-family: inherit; }
/* The date picker and its spinners are drawn by the browser, and this is the
   only thing that tells it which way round the page is. */
.ad-grid input[type="datetime-local"] { color-scheme: dark; }
.ad-grid textarea { resize: vertical; }
.ad-sub { margin: 18px 0 4px; font-size: 14px; color: var(--muted); }

/* The preview uses the real panel's own classes and its own renderer, so it
   sits in the flow instead of hanging in the corner of the window. */
.bm-ann-static { position: static; width: auto; max-width: 380px;
  box-shadow: none; margin-top: 8px; }
/* The dismiss button is part of the panel's markup and shouldn't look like it
   does anything here. */
.bm-ann-static .bm-ann-x { opacity: .35; pointer-events: none; }

.ad-row { border-top: 1px solid var(--line); padding: 12px 0; }
.ad-row:first-child { border-top: 0; }
.ad-row-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.ad-title { font-size: 14px; }
.ad-kind { font-size: 11px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .06em; }
.ad-when { font-size: 12px; color: var(--muted); margin-left: auto; }
.ad-sub-line { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
.ad-win { color: #d9a25f; }
.ad-acts { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.ad-del:hover { border-color: #a4503f; color: #e08e7c; }

/* Four states, drawn apart on purpose: "not shown" is a decision somebody made,
   the other two are just the clock. */
.ad-badge { font-size: 11px; border-radius: 999px; padding: 2px 8px;
  border: 1px solid var(--line); color: var(--muted); }
.ad-live { border-color: #4f7a4a; color: #8fc487; }
.ad-soon { border-color: #6a6a8a; color: #a3a3c8; }
.ad-past { border-color: var(--line); color: var(--muted); }
.ad-off  { border-color: var(--line); color: var(--muted); opacity: .8; }

@media (max-width: 700px) { .ad-grid { grid-template-columns: 1fr; } }

/* --- trading with somebody -------------------------------------------------- */
.sw-code-in { text-transform: uppercase; letter-spacing: .12em; width: 8em;
  font-size: 14px; padding: 6px 8px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); }
.sw-search { width: 100%; margin-bottom: 10px; font-size: 13px; padding: 6px 8px;
  color: var(--text); background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); }
.sw-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.sw-head-l { display: flex; align-items: center; gap: 10px; }
.sw-head .hint { margin: 0; flex: 1 1 200px; }
.sw-code { font-size: 22px; letter-spacing: .16em; font-weight: 600;
  color: var(--accent); }
.sw-mine { margin: 4px 0; font-size: 13px; }

/* Two piles side by side, because that is the shape of the thing on the table.
   They stack on a phone rather than shrinking to two unreadable columns. */
.sw-table { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.sw-pile-h { margin: 0 0 6px; font-size: 14px; display: flex; gap: 8px;
  align-items: baseline; }
.sw-lines { list-style: none; margin: 0; padding: 0; }
.sw-line { display: flex; align-items: center; gap: 8px; padding: 5px 0;
  border-top: 1px solid var(--line); font-size: 13px; }
.sw-line:first-child { border-top: 0; }
.sw-line .nm { flex: 1 1 auto; }
.sw-line .pr { color: var(--muted); }
/* A card promised in a quantity its owner no longer has. Marked here as well as
   in the sentence below, so it's findable rather than merely announced. */
.sw-line-short { color: #e08e7c; }
.sw-line-short .cb-cards { color: #e08e7c; }

.sw-diff { margin: 12px 0 4px; font-size: 14px; }
.sw-short { margin: 0 0 8px; font-size: 13px; color: #e08e7c; }

.sw-binders { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }

@media (max-width: 900px) {
  .sw-table, .sw-binders { grid-template-columns: 1fr; }
}
.sw-promo { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.sw-promo > div { flex: 1 1 320px; }
.sw-promo .cat-head { margin-top: 0; }
.sw-promo .hint { margin-bottom: 0; }
/* Two binders share the width, so their tiles are narrower than a full-page
   grid's. Without this they inherit the 150px minimum and a half-width column
   fits exactly one, which is a list pretending to be a grid. */
.sw-grid { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px; }
.sw-grid .meta { padding: 5px 7px; font-size: 11px; }

/* --- card kinds whose text has structure ------------------------------------ */
/* A Saga's chapters are a track down the left, not paragraphs with numerals in
   them. Drawn as paragraphs is what made an invented Saga read as a plain
   enchantment. */
/* A Saga's chapters run down a rule, the way the card prints them, rather than
   sitting in a stack of bordered rows. The rule is the track; the numerals are
   stops on it. */
.cf-saga { display: flex; flex-direction: column; gap: 4px;
  padding-left: 3px; border-left: 2px solid rgba(0,0,0,.22); }
.cf-ch { display: grid; grid-template-columns: auto 1fr; gap: 7px;
  align-items: start; padding: 2px 0; }
.cf-ch + .cf-ch { border-top: 1px solid rgba(0,0,0,.12);
  box-shadow: 0 -1px 0 rgba(255,255,255,.45); }
/* Side by side, not stacked. 'I, II —' is one ability with two stops on
   the track; stacked, the second numeral fell below the text it belonged
   to and read as a chapter with nothing in it. */
.cf-ch-marks { display: flex; flex-direction: row; gap: 2px; margin-left: -11px;
  flex: none; }
.cf-ch-n { display: inline-flex; align-items: center; justify-content: center;
  min-width: 19px; height: 17px; padding: 0 4px;
  font-family: "Iowan Old Style", Palatino, Georgia, serif;
  font-size: 10px; font-weight: 700; color: #f2ece0;
  border-radius: 3px;
  background: linear-gradient(160deg, #55524a, #2b2924);
  border: 1px solid rgba(0,0,0,.45);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.3); }
.cf-ch-intro { margin: 0 0 4px; }

/* A Class's levels are bars across, with the cost on the right as printed. */
/* A Class's levels are bars across the box, with the cost on the right. */
.cf-lvl { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin: 6px 0 3px; padding: 3px 7px; border-radius: 4px;
  background: linear-gradient(180deg, rgba(0,0,0,.42), rgba(0,0,0,.28));
  border: 1px solid rgba(0,0,0,.4);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 1px 0 rgba(255,255,255,.4);
  color: #f2ece0; font-size: 9.5px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; }
.cf-lvl-t { margin: 0 0 4px; }

/* --- two faces -------------------------------------------------------------- */
/* Both sides are rendered and one is hidden, rather than swapped on flip: the
   art of the side you can't see should already be loaded when you turn it over,
   and a printed card genuinely has both. */
/* stretch, not center: the face is width:100%, and centring made a
   two-faced card render narrower than a one-faced one. */
.cf-dfc { display: flex; flex-direction: column; align-items: stretch; gap: 8px; }
.cf-dfc .cf-flip { align-self: center; }
.cf-flip { font-size: 12px; padding: 5px 12px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer; }
.cf-flip:hover { border-color: var(--accent); }
.cf-flip[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
/* A corner mark, so a face on its own still says which side it is. */
/* Which side you are looking at. It shares the custom mark's corner because
   they answer neighbouring questions — what this is, and which half of it you
   have in front of you. Given its own weight on the back: at .72 opacity in
   8px type it was present and unreadable, which is the same as absent.
   Raised on the mark itself rather than the ::after, because opacity on the
   parent makes a group its children can't climb back out of. */
.cf[data-face="back"] .cf-mark::after { content: " · back"; }
.cf[data-face="back"] .cf-mark { opacity: 1; font-weight: 700; }

/* The mana key in the cheat sheet. */
.pip-key { list-style: none; margin: 6px 0 8px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 5px 16px; }
.pip-key li { display: flex; align-items: center; gap: 5px; font-size: 12.5px; }
.pip-key code { font-size: 11px; color: var(--muted); }

/* --- halves: split, room, aftermath, flip ----------------------------------
   Drawn upright and side by side. A printed split card is read by turning it,
   and reproducing that here would mean asking someone to tilt their head at a
   thing that could simply be the right way up. The rotation is dress; the two
   halves are the card. */
.cf-beside {
  aspect-ratio: 7 / 5; max-width: 420px;
  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr auto;
  gap: 6px;
}
.cf-flipcard { display: grid; grid-template-rows: 1fr auto 1fr auto; gap: 5px; }
.cf-beside > .cf-foot, .cf-flipcard > .cf-foot { grid-column: 1 / -1; }

/* A half carries the same colour custom properties a whole face does, so one
   set of frame colours covers both and a half can't drift from a card. */
.cf-half {
  display: flex; flex-direction: column; gap: 3px;
  /* Both axes. A grid item's automatic minimum is its *content's* minimum, so
     a long word in a type line silently widens one column past its 1fr and
     pushes the other out of the card — which is what "Enchantment — Room" did. */
  min-width: 0; min-height: 0; overflow: hidden;
  padding: 5px; border-radius: 7px;
  background: linear-gradient(168deg, var(--cf-bg2, #4a4a42) 0%,
                              var(--cf-bg, #3a3a34) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25),
              inset 0 -1px 0 rgba(0,0,0,.25);
}
/* A half is short, so everything that isn't the rules text is told not to grow
   and the rules text gets whatever is left. */
.cf-half .cf-title, .cf-half .cf-type { flex: none; min-width: 0; }
.cf-half .cf-art { flex: 0 0 26%; min-height: 0; }
.cf-half .cf-box { flex: 1 1 auto; min-height: 0; overflow: hidden; padding: 4px 5px; }
.cf-half .cf-name { font-size: 10.5px; min-width: 0; }
.cf-half .cf-type, .cf-half .cf-rules { font-size: 9px; }
.cf-half .cf-rules p { margin: 0 0 3px; }
/* The lower half of a flip card is the card upside down, which is the card.
   Matched on the face rather than on position: the art sits between them and
   would otherwise be counted. */
.cf-flipcard > .cf-half[data-face="back"] { transform: rotate(180deg); }
.cf-flipcard > .cf-art { flex: none; height: 21%; }
.cf-half-note { font-size: 8.5px; font-style: italic; opacity: .7; }
/* Said on the half it is true of, rather than in the footer about "the second
   half" — which half is second is exactly what a reader can't tell. */
.cf-half-tag { font-size: 7.5px; font-style: italic; opacity: .75;
  margin-left: auto; white-space: nowrap; }

/* --- an Adventure, inset in the creature's text box ------------------------- */
.cf-adv {
  border: 1px solid rgba(0,0,0,.28); border-radius: 5px;
  padding: 4px 6px; margin-bottom: 5px; background: rgba(0,0,0,.055);
}
.cf-adv-head { display: flex; justify-content: space-between;
  align-items: baseline; gap: 6px; }
.cf-adv-name { font-weight: 700; font-size: 11px; font-family: Georgia, serif; }
.cf-adv-type { font-size: 9px; opacity: .75; margin-bottom: 2px; }
.cf-adv .cf-rules { font-size: 10px; }

/* --- a Battle is landscape --------------------------------------------------
   Read off the type line, like Saga and Class. Only the front: the back of a
   Siege is an ordinary permanent and stands up. */
.cf-is-battle[data-face="front"] {
  aspect-ratio: 7 / 5; max-width: 420px;
  display: grid; column-gap: 8px;
  grid-template-columns: 44% 1fr;
  grid-template-rows: auto auto 1fr auto;
  grid-template-areas: "title title" "art type" "art box" "foot foot";
}
.cf-is-battle[data-face="front"] > .cf-title { grid-area: title; }
.cf-is-battle[data-face="front"] > .cf-art {
  grid-area: art; height: 100%; min-height: 0; aspect-ratio: auto; }
.cf-is-battle[data-face="front"] > .cf-type { grid-area: type; }
.cf-is-battle[data-face="front"] > .cf-box { grid-area: box; min-height: 0; }
.cf-is-battle[data-face="front"] > .cf-foot { grid-area: foot; }

/* --- the keyword picker -----------------------------------------------------
   Closed by default: it is a shortcut, and a shortcut that occupies a third of
   the form is a form with a shortcut in the way. */
.cc-kw { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 6px 10px; background: var(--surface-2); }
.cc-kw > summary { font-size: 12.5px; color: var(--muted); cursor: pointer;
  list-style: none; }
.cc-kw > summary::-webkit-details-marker { display: none; }
.cc-kw > summary::before { content: "+ "; opacity: .7; }
.cc-kw[open] > summary::before { content: "− "; }
.cc-kw-bar { display: flex; gap: 10px; align-items: center; margin: 8px 0 6px; }
.cc-kw-bar input[type="search"] { flex: 1 1 auto; min-width: 0; }
.cc-kw-rem { flex: 0 0 auto; display: flex !important; flex-direction: row !important;
  align-items: center; gap: 5px; font-size: 12px; white-space: nowrap;
  margin-bottom: 0 !important; }
/* Capped and scrolled: three hundred keywords is a page of its own otherwise,
   and the filter is right there. */
.cc-kw-list { display: flex; flex-wrap: wrap; gap: 5px;
  max-height: 148px; overflow-y: auto; padding: 2px 0 4px; }
.cc-kw-chip { padding: 3px 9px; font: inherit; font-size: 12px;
  color: var(--text); background: var(--surface); cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; }
.cc-kw-chip:hover { border-color: var(--accent, #b98b3a); }
.cc-kw .hint { margin: 2px 0 0; }

/* A card that is already in a deck says so before you type, not after you save.
   Coloured as information rather than alarm: a deck holding the id instead of a
   copy is the design working, and the note only exists so it isn't a surprise. */
.cc-in-decks { margin: 0 0 10px; padding: 7px 10px; font-size: 12.5px;
  color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--line); border-left: 3px solid var(--accent, #b98b3a);
  border-radius: var(--radius); }
.cc-in-decks a { color: var(--text); }

/* A custom card in the add box, and on a deck tile with no art yet. */
.ac-mine { margin-left: 6px; font-size: 10px; opacity: .7; white-space: nowrap; }
.art-none { display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; aspect-ratio: 626 / 457;
  font-size: 11px; color: var(--muted); background: var(--surface-2);
  border-bottom: 1px solid var(--line); }
.art-none span { font-size: 9.5px; opacity: .7; }
/* A whole-card image standing in for an art crop is portrait in a landscape
   slot, so it is framed to the same shape rather than stretched to it. */
.art-custom { object-fit: cover; object-position: center 22%; }

/* --- which face you are editing ---------------------------------------------
   A segmented pair rather than a dropdown: there are two of them and both fit
   on screen, so making you open a menu to see the choice would be charging for
   nothing. */
/* The front panel is a div now rather than a run of direct children, so it has
   to carry the column layout its contents used to get from .cc-fields. */
#ccFront { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.cc-faces { display: flex; gap: 0; margin: 0 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.cc-face-btn { flex: 1 1 0; padding: 7px 10px; font: inherit; font-size: 13px;
  color: var(--muted); background: var(--surface-2); border: 0; cursor: pointer; }
.cc-face-btn + .cc-face-btn { border-left: 1px solid var(--line); }
.cc-face-btn:hover { color: var(--text); }
.cc-face-btn.on { color: var(--text); background: var(--surface);
  box-shadow: inset 0 -2px 0 var(--accent, #b98b3a); font-weight: 600; }

/* The card, rather than either face — set apart because it does not change
   when you switch sides. */
.cc-card-level { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 12px 12px; margin: 12px 0 2px; }
.cc-card-level legend { font-size: 12px; color: var(--muted); padding: 0 6px; }

/* --- the back-face panel in the editor -------------------------------------- */
.cc-back { border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 12px 12px; margin: 4px 0 2px; }
.cc-back legend { font-size: 12px; color: var(--muted); padding: 0 6px; }
.cc-back .hint { margin-top: 0; }
.cc-back input[type="text"], .cc-back textarea {
  font-size: 13px; padding: 6px 8px; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius); font-family: inherit; }
.cc-back textarea { resize: vertical; }
.cc-back > label { display: flex; flex-direction: column; gap: 4px;
  font-size: 13px; color: var(--muted); margin-bottom: 8px; }
/* Starring a printing is a fact about you, not about this deck — so it sits
   apart from the tile that picks one, and only one can be lit. */
.print-fav { width: 100%; margin-top: 3px; padding: 2px 0; font-size: 13px;
  line-height: 1.2; color: var(--muted); background: transparent;
  border: 1px solid transparent; border-radius: 6px; cursor: pointer; }
.print-fav:hover { border-color: var(--line); color: var(--text); }
.print-fav[aria-pressed="true"] { color: var(--accent); }

/* --- the custom card cheat sheet -------------------------------------------- */
/* Closed by default: it answers a question you have once, and after that it is
   a wall between you and the editor. Remembered open for as long as you want it. */
.cc-cheat { margin-bottom: 18px; }
.cc-cheat > summary { cursor: pointer; font-size: 14px; color: var(--text);
  list-style: none; }
.cc-cheat > summary::-webkit-details-marker { display: none; }
.cc-cheat > summary::before { content: "▸ "; color: var(--accent); }
.cc-cheat[open] > summary::before { content: "▾ "; }
.cheat-lead { margin: 10px 0 14px; font-size: 13px; }
.cheat-grid { display: grid; gap: 18px 24px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.cheat-grid h3 { margin: 0 0 4px; font-size: 13px; color: var(--accent); }
.cheat-grid p { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.cheat-grid ul { margin: 0 0 8px; padding-left: 18px; font-size: 13px;
  color: var(--muted); }
.cheat-grid li { margin-bottom: 4px; }
/* The examples are the point, so they read as something you'd type. */
.cheat-grid pre { margin: 0 0 8px; padding: 8px 10px; font-size: 12px;
  line-height: 1.45; color: var(--text); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius);
  white-space: pre-wrap; overflow-x: auto; }
.cc-cheat code { font-size: 12px; padding: 1px 4px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--line); }
.cheat-foot { margin: 16px 0 0; padding-top: 12px;
  border-top: 1px solid var(--line); }

/* --- a card whose picture is the whole card --------------------------------- */
/* Made in Card Conjurer or Magic Set Editor, uploaded here. This app draws no
   frame in that case, because one already exists — it keeps the data, which is
   the half a deck needs, and the mark, because a finished render looks exactly
   like a real card and should still say what it is in a deck list. */
.cf-full { padding: 0; border: 0; background: none; box-shadow: none;
  overflow: visible; }
.cf-full-img { width: 100%; aspect-ratio: 5 / 7; object-fit: cover;
  display: block; border-radius: 13px;
  box-shadow: 0 10px 26px rgba(0,0,0,.45), 0 2px 6px rgba(0,0,0,.35); }
/* Bottom-left, over the card's own border where every frame has margin. Small
   and unobtrusive, but never absent. */
.cf-full .cf-mark { position: absolute; left: 8px; bottom: 8px;
  padding: 1px 6px; border-radius: 999px; font-size: 8.5px; letter-spacing: .04em;
  color: rgba(255,255,255,.92); background: rgba(0,0,0,.62);
  backdrop-filter: blur(2px); opacity: 1; }
.cf-full-empty { display: flex; align-items: center; justify-content: center;
  aspect-ratio: 5 / 7; border-radius: 13px; border: 1px dashed var(--line);
  background: repeating-linear-gradient(45deg, rgba(255,255,255,.03) 0 6px,
              transparent 6px 12px), var(--surface-2);
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); }

/* --- life counter (/life.html) ------------------------------------------
   A device lying flat in the middle of a table, read from all four sides.
   Two rules drive most of what follows.

   Rotation goes on an inner wrapper, never the grid cell: rotating the cell
   rotates its own layout box, so the far row stops lining up with the grid it
   is supposed to be part of.

   The life digits size from cqh/cqw against the life row itself, not the
   viewport. The counter row underneath wraps as commander-damage chips are
   added, and a viewport-sized numeral kept its height while its row shrank
   under it — clipping the one number the whole screen exists to show. */
/* The seven-segment face the life numerals are drawn in. Vendored, not fetched
   from a CDN: this is the one page that has to work on a table with no wifi,
   and a webfont that only arrives online would fall back to monospace exactly
   when it matters. 5 KB, SIL Open Font License — the licence travels with it
   in dseg7-classic.LICENSE.txt, which the OFL requires. */
@font-face {
  font-family: "DSEG7 Classic";
  src: url("/dseg7-classic.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
/* Two stencils beside it, vendored on the same terms and for the same reason:
   a table with no wifi still gets the face it was set to. Both SIL OFL, both
   with their licence alongside. Saira is the wide geometric one that carries
   furthest across a table; Stardos is the slab, closer to a stamped crate and
   to the serif the card names already use. */
@font-face {
  font-family: "Saira Stencil One";
  src: url("/saira-stencil.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Stardos Stencil";
  src: url("/stardos-stencil.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
.lc-body { margin: 0; overflow: hidden; overscroll-behavior: none; }
.lc-root {
  position: relative; width: 100%; height: 100vh; height: 100dvh;
  background: var(--bg); padding: 8px; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 8px; overflow: hidden;
}
.lc-grid { flex: 1 1 0%; min-height: 0; display: grid; gap: 8px; }

.lc-panel {
  position: relative; overflow: hidden;
  border-radius: var(--radius); background: var(--surface);
  border: 1px solid var(--line); border-top: 3px solid var(--seat, var(--accent));
}
.lc-panel.lc-out { opacity: .45; }
.lc-inner { position: absolute; inset: 0; display: flex; flex-direction: column; }

.lc-head { flex: none; display: flex; align-items: center; gap: 6px;
  flex-wrap: wrap; padding: 8px 12px 0; }
.lc-name { background: none; border: 0; padding: 6px; min-height: 44px;
  font: 600 15px/1.2 inherit; color: var(--text); text-align: left;
  display: flex; align-items: center; gap: 7px; cursor: pointer; }
.lc-dot { width: 12px; height: 12px; border-radius: 50%; flex: none;
  background: var(--seat, var(--accent)); }
.lc-spacer { flex: 1; }
.lc-tags { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.lc-pill { font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  border-radius: 999px; padding: 4px 9px; border: 1px solid var(--line);
  color: var(--muted); background: none; }
.lc-pill-out { background: var(--surface-2); }
/* The turn seat gets the phase control. Gold on a gold tint so it reads as
   "the game is here" from the far side of the table. */
.lc-phase { padding: 6px 12px; min-height: 34px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 22%, var(--surface-2));
  border: 1px solid var(--accent); color: var(--text);
  font: 600 11px/1 inherit; letter-spacing: .1em; text-transform: uppercase;
  cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
.lc-phase .lc-chev { color: var(--accent); }
.lc-monarch { background: var(--accent); color: var(--accent-ink);
  border: 1px solid var(--accent); font-weight: 600; min-height: 32px; cursor: pointer; }
.lc-init { background: none; border: 1px solid var(--accent);
  color: var(--accent); min-height: 32px; cursor: pointer; }
.lc-team { flex: none; padding: 0 14px; font-size: 12px; color: var(--muted);
  font-family: "Iowan Old Style", Palatino, Georgia, serif;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.lc-life { flex: 1 1 0%; display: grid; grid-template-columns: 1fr auto 1fr;
  grid-template-rows: 100%; align-items: stretch; min-height: 0;
  overflow: hidden; container-type: size; }
/* align-self, not height:100% — a percentage height resolves against the grid
   area and lets the button overflow the row it sits in. */
.lc-step { align-self: stretch; min-height: 0; border: 0; background: none;
  display: flex; align-items: center; justify-content: center;
  font-size: min(40px, 34cqh); color: var(--muted); cursor: pointer;
  -webkit-user-select: none; user-select: none; touch-action: manipulation; }
.lc-step:hover { color: var(--accent); background: var(--surface-2); }
.lc-mid { display: flex; flex-direction: column; align-items: center;
  justify-content: center; padding: 0 4px; min-height: 0; overflow: hidden; }
/* Sunken well: dark gradient plus an inset shadow, so the numerals read as
   stamped into the panel rather than floating on it. */
.lc-well { position: relative; padding: 4cqh 3cqw; border-radius: 10px; min-height: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bg) 88%, black) 0%,
    color-mix(in srgb, var(--surface-2) 70%, black) 100%);
  box-shadow: inset 0 3px 6px rgba(0,0,0,.72),
              inset 0 -1px 0 color-mix(in srgb, var(--line) 70%, transparent),
              0 1px 0 color-mix(in srgb, var(--line) 55%, transparent); }
.lc-digits { font-size: min(62cqh, 30cqw); line-height: 1;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--text) 86%, var(--bg));
  text-shadow: 0 -1px 1px rgba(0,0,0,.85),
               0 1px 0 color-mix(in srgb, var(--muted) 45%, transparent); }
/* The handoff specifies 24cqw here. That was tuned in a host page where the
   panel was not full height; at a real 100dvh one panel is most of a phone
   screen and the width cap left the numerals adrift in dead space. Height
   leads, width still catches the very narrow case. */
.lc-solo .lc-digits { font-size: min(52cqh, 42cqw); }
.lc-num-lcd { font-family: "DSEG7 Classic", ui-monospace, monospace; }
.lc-num-serif { font-family: "Iowan Old Style", Palatino, Georgia, serif; }
.lc-num-stencil { font-family: "Saira Stencil One", Impact, sans-serif; }
/* 700 is the weight that ships; without it the browser synthesises a bold from
   the regular it does not have and the stencil bridges close up. */
.lc-num-stamp { font-family: "Stardos Stencil", Impact, serif; font-weight: 700; }
.lc-delta { flex: none; min-height: 13px; margin-top: 2px; font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }

.lc-counters { flex: none; display: flex; flex-wrap: wrap; gap: 6px;
  padding: 0 10px 10px; align-items: center; }
.lc-chip { display: inline-flex; align-items: center; gap: 2px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 4px; }
.lc-chip button { background: none; border: 0; color: inherit;
  font-size: 15px; padding: 6px 8px; cursor: pointer; touch-action: manipulation; }
.lc-chip-lbl { font-size: 12px; min-width: 64px; text-align: center; color: var(--text); }
.lc-cmd .lc-chip-lbl { min-width: 0; display: inline-flex; align-items: center; gap: 5px; }
.lc-cmd-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.lc-cmd-val { font: 600 13px/1 inherit; font-variant-numeric: tabular-nums;
  min-width: 16px; text-align: right; }
.lc-cmd-0 .lc-chip-lbl, .lc-cmd-0 .lc-cmd-val { color: var(--muted); }
/* 21 is lethal, so it stops being a number you read and becomes a state you
   notice: the whole chip flips to accent. */
.lc-cmd-lethal { background: var(--accent); border-color: var(--accent); }
.lc-cmd-lethal .lc-chip-lbl, .lc-cmd-lethal .lc-cmd-val,
.lc-cmd-lethal button { color: var(--accent-ink); }

.lc-center { position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%); z-index: 6;
  display: flex; gap: 6px; align-items: center; }
.lc-round-btn { min-height: 44px; padding: 8px 14px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--text);
  font: 600 11px/1 inherit; letter-spacing: .06em; text-transform: uppercase;
  box-shadow: 0 4px 18px rgba(0,0,0,.45); cursor: pointer; }
.lc-round-btn:hover { border-color: var(--accent); color: var(--accent); }
.lc-tools-btn { width: 56px; height: 56px; padding: 0; border-radius: 50%;
  font-size: 10px; color: var(--accent); }

.lc-phone-bars { flex: none; display: flex; flex-direction: column; gap: 6px; }
.lc-turnrow { display: flex; gap: 6px; }
.lc-turnbar { flex: 1; min-height: 52px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 22%, var(--surface-2));
  border: 1px solid var(--accent); color: var(--text);
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font: 600 14px/1.2 inherit; padding: 0 12px; cursor: pointer;
  overflow: hidden; white-space: nowrap; }
.lc-turnbar .lc-tb-txt { overflow: hidden; text-overflow: ellipsis; }
.lc-goto { min-width: 66px; min-height: 52px; }
.lc-rail { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; }
.lc-rail::-webkit-scrollbar { display: none; }
.lc-seat { min-width: 78px; min-height: 58px; border-radius: var(--radius);
  background: var(--surface-2); border: 1px solid var(--line); color: var(--muted);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; padding: 4px 8px; flex: none; cursor: pointer; }
/* Viewed and turn are different facts and must not share a treatment — one
   shared highlight made "whose seat am I looking at" and "whose turn is it"
   indistinguishable. */
.lc-seat.lc-viewed { background: var(--surface); border-color: var(--text); color: var(--text); }
.lc-seat-nm { font-size: 11px; max-width: 110px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 5px; }
.lc-seat-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.lc-turn-dot { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 70%, transparent); }
.lc-seat-life { font: 600 18px/1 inherit; font-variant-numeric: tabular-nums; }
.lc-seat-turn { font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); min-height: 11px; }
.lc-rail .lc-round-btn { min-width: 62px; min-height: 58px; border-radius: var(--radius); }

/* Both bands cross the middle of the table, full bleed, so a message is
   equally reachable from every seat. */
.lc-band { position: absolute; left: 0; right: 0; top: 50%;
  transform: translateY(-50%); z-index: 8; background: var(--surface-2);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 14px 20px; display: flex; flex-direction: column; align-items: center;
  gap: 2px; cursor: pointer; }
.lc-band-msg { font: 600 22px/1.25 inherit; color: var(--accent); text-align: center; }
.lc-band-sub { font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); }
.lc-prompt { z-index: 9; background: var(--accent); color: var(--accent-ink);
  border-color: var(--accent); padding: 12px 16px; gap: 6px; cursor: default; }
.lc-prompt .lc-band-msg { color: var(--accent-ink); font-size: 19px; }
.lc-prompt-who { font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  opacity: .75; }
.lc-prompt-btn { min-height: 40px; padding: 8px 22px; border-radius: 999px;
  background: var(--accent-ink); color: var(--accent); border: 0;
  font: 600 13px/1 inherit; cursor: pointer; }
/* Printed twice in table view, one copy upside down, so nobody turns the
   tablet round to read a reminder that is about them. */
.lc-flip { transform: rotate(180deg); }

.lc-sheet .cat-head { color: var(--text);
  font-family: "Iowan Old Style", Palatino, Georgia, serif;
  font-size: 16px; font-weight: 400; letter-spacing: .01em; text-transform: none; }
.lc-sheet input[type="text"], .lc-sheet input[type="number"] {
  background: var(--surface-2); color: var(--text); border: 1px solid var(--line);
  border-radius: 8px; padding: 11px 12px; font-size: 15px; width: 100%;
  box-sizing: border-box; }
.lc-sheet .lc-serif { font-family: "Iowan Old Style", Palatino, Georgia, serif; }
.lc-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0; }
.lc-choice { min-height: 44px; padding: 10px 16px; border-radius: 999px; }
.lc-pips { display: flex; gap: 8px; }
.lc-pip { width: 48px; height: 48px; border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface-2); color: var(--muted); font: 600 16px/1 inherit; cursor: pointer; }
.lc-rem { display: flex; align-items: center; gap: 8px; padding: 8px 0;
  border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.lc-rem-off { color: var(--muted); }
.lc-rem-txt { flex: 1; min-width: 140px; }
.lc-rem-meta { font-size: 11px; color: var(--muted); }

/* --- life counter: chosen colours, art, typed totals, icons --------------- */

/* The total is a button (tap to type) or an input (typing). Neither may look
   like a control — it is still the number the whole table reads — so both
   inherit the well's treatment and only the input shows a frame. */
.lc-digits { background: none; border: 0; padding: 0; cursor: pointer; display: block; }
/* A <button> does not inherit font-family, so the "System" numeral option needs
   this — but scoped, because a blanket `font-family: inherit` here sits later in
   the file than .lc-num-lcd and silently beat it, dropping the seven-segment
   face back to the UI font while everything still looked plausible. */
.lc-digits:not(.lc-num-lcd):not(.lc-num-serif):not(.lc-num-stencil):not(.lc-num-stamp)
  { font-family: inherit; }
.lc-edit { width: 100%; text-align: center; cursor: text;
  background: rgba(0,0,0,.4); border-radius: 8px;
  outline: 2px solid var(--accent); outline-offset: 2px; }

/* The painted medallions, clipped to their circle so the square corners of a
   jpeg never show against the panel. */
.lc-step img { width: min(64px, 44cqh); height: auto; aspect-ratio: 1;
  border-radius: 50%; display: block; opacity: .92; }
.lc-step:hover img { opacity: 1; }
.lc-step:hover { background: none; }
.lc-ic-btn { width: 56px; height: 56px; padding: 0; border-radius: 50%;
  overflow: hidden; display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--accent); }
.lc-ic-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lc-big { width: 66px; height: 66px; }
.lc-rail .lc-ic-btn { min-width: 58px; width: 58px; height: 58px; border-radius: 50%; }

/* Where the first-player spinner is lit. Deliberately loud: it is being
   watched from four seats at once, across a table, in whatever light the
   kitchen has. */
.lc-spin { outline: 3px solid var(--accent); outline-offset: -3px;
  box-shadow: 0 0 28px color-mix(in srgb, var(--accent) 60%, transparent); }
@media (prefers-reduced-motion: reduce) { .lc-spin { box-shadow: none; } }

.lc-swatches { gap: 6px; }
.lc-swatch { width: 34px; height: 34px; border-radius: 50%; padding: 0;
  border: 2px solid transparent; cursor: pointer; }
.lc-swatch.lc-chosen { border-color: var(--text); }

.lc-arthits { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.lc-arthit { width: 96px; height: 68px; border-radius: 8px; padding: 0;
  border: 1px solid var(--line); background-size: cover; background-position: center;
  cursor: pointer; }
.lc-arthit:hover { border-color: var(--accent); }

.lc-rules-hits { margin-top: 6px; }
.lc-rule { padding: 10px 0; border-bottom: 1px solid var(--line); }
.lc-rule-no { font-size: 12px; letter-spacing: .06em; color: var(--accent); }
.lc-rule-body { font-size: 14px; color: var(--text); margin-top: 3px;
  white-space: pre-wrap; }

/* Commander typeahead. Sits in the flow under its field rather than floating:
   the sheet already scrolls, and an absolutely-positioned dropdown inside a
   scrolling panel detaches from its input the moment anyone scrolls. */
.lc-cmdr-row { flex-direction: column; align-items: stretch; gap: 4px; }
.lc-ac:empty { display: none; }
.lc-ac { display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--line); border-radius: 8px; padding: 4px;
  background: var(--surface-2); max-height: 240px; overflow-y: auto; }
.lc-achit { display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  background: none; border: 0; color: var(--text); text-align: left;
  font-family: "Iowan Old Style", Palatino, Georgia, serif; font-size: 15px;
  padding: 9px 10px; border-radius: 6px; cursor: pointer; min-height: 44px; }
.lc-achit:hover, .lc-achit:focus-visible { background: var(--surface); outline: none; }
.lc-achit-t { font-family: inherit; font-size: 11px; color: var(--muted); }

/* The dice tray. Sits just above the centre cluster, upright: it is a menu you
   reach for, not a result — results print twice in the band below so both
   sides of the table can read them without turning the tablet round. */
.lc-tray { position: absolute; left: 50%; top: 50%; z-index: 7;
  transform: translate(-50%, calc(-50% - 62px));
  display: flex; gap: 6px; flex-wrap: wrap; justify-content: center;
  max-width: min(92vw, 620px); padding: 8px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 10px 30px rgba(0,0,0,.55); }
.lc-tray .lc-choice { min-height: 44px; padding: 8px 14px; }


/* The count sits on its own line above the dice, full width, so it reads as
   "how many of the thing below" rather than as another thing to roll. */
.lc-tray-count { flex-basis: 100%; display: flex; align-items: center;
  justify-content: center; gap: 8px; padding-bottom: 2px; }
.lc-tray-n { font-size: 18px; font-variant-numeric: tabular-nums;
  min-width: 26px; text-align: center; color: var(--text); }

.lc-sheet select { background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px; padding: 11px 12px;
  font-size: 15px; width: 100%; min-height: 44px; }

.lc-name-txt { display: inline-flex; align-items: center; gap: 7px; }
/* The emblem rides with the name rather than on its own line: a seat's header
   already carries a dot, pips, and up to four tags, and another row would push
   the life row down on a four-panel tablet. */
/* Set symbols ship from Scryfall as black-on-transparent SVGs, invisible on a
   dark panel. Masked rather than drawn as an <img>: a mask takes its colour
   from background-color, so the symbol comes out in the accent gold exactly
   like every other control on this page, where an <img> can only be filtered
   to white by a chain of brightness/invert/hue-rotate that nobody can read and
   that breaks the moment a symbol is not pure black.

   The gold ring and dark well are the same medallion language as the plus,
   minus, table and rules buttons, so a seat's set reads as part of the set of
   controls rather than as a smudge next to the name. */
.lc-emblem { width: 30px; height: 30px; flex: none; border-radius: 50%;
  display: inline-block; position: relative;
  background: var(--bg); box-shadow: 0 0 0 1.5px var(--accent), 0 1px 4px rgba(0,0,0,.5); }
.lc-emblem::after {
  content: ""; position: absolute; inset: 5px; background: var(--accent);
  -webkit-mask: var(--sym) center / contain no-repeat;
  mask: var(--sym) center / contain no-repeat;
}

/* Anchors styled as buttons in the life sheets. .off-btn assumes a <button>,
   which is centred and has no underline by default; an <a> is neither. */
.lc-sheet a.off-btn, .lc-sheet a.import-btn {
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none;
}

/* Offline is a state of the whole page, not a notice on one corner of it: the
   controls that need a connection are still there and still look pressable. */
body.is-offline [data-offline-status] { color: var(--accent); }

/* --- the usage guide ------------------------------------------------------
   A button beside each page's heading, and the overlay it opens. The overlay
   rather than an unfolding section because the guide describes what is behind
   it: pushing the page down moves the thing being explained off the screen at
   the moment somebody is looking for it. */
.usage-btn {
  margin-left: 10px; padding: 0; border: 0; background: none; cursor: pointer;
  line-height: 0; vertical-align: middle; border-radius: 50%;
  /* inline-flex so the label sits beside the picture rather than under it —
     the button lands next to an <h1>, whose own display would otherwise stack
     them. */
  display: inline-flex; align-items: center; gap: 7px;
}
/* The label reads as a caption, not as part of the heading it stands beside:
   the heading is 18px and 600, so this is deliberately smaller and lighter. */
.usage-lbl { font-size: 13px; font-weight: 500; line-height: 1;
  color: var(--muted); font-family: inherit; }
.usage-btn:hover .usage-lbl { color: var(--accent); }
/* !important because this button lands in three different headers, and the
   playtest bar styles its own images at a size that wins on specificity. The
   button is 30px wherever it is, or it is a 140px medallion in a 40px bar. */
.usage-btn img { width: 30px !important; height: 30px !important;
                 border-radius: 50%; display: block; }
.usage-btn:hover img { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The AI notice sits beside Page Help and carries no icon. Every painted circle
   in this app stands for a destination; this one stands for a sentence, and a
   made-up glyph for it would be one more thing to learn. The rule keeps it from
   reading as a second half of the button before it. */
/* The buy-cheapest split: one basket per shop, each with the text a bulk box
   takes. A textarea and not a <pre>, because the point is that it can be
   selected and copied — including by somebody whose browser refuses the
   clipboard API, which is every browser without a secure context. */
.cheap-vendor { margin: 14px 0 0; }
.cheap-vendor .pick-label { display: flex; align-items: baseline; gap: 8px; }
.cheap-list {
  width: 100%; margin-top: 6px; resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; line-height: 1.5;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px;
}

/* The kinds-of-printing checkboxes. A list rather than a stack of .lc-row,
   because it is a set of choices about one thing and reads as one block. */
/* The "some versions are hidden" line sits in the picker grid, which is a
   `repeat(auto-fill, minmax(130px, 1fr))` — so it has to be told to take the
   whole row or it becomes a 130px column of wrapped words beside the tiles. */
.print-hidden { grid-column: 1 / -1; }
.print-hidden a { color: var(--accent); }

.hide-opts { list-style: none; margin: 8px 0 10px; padding: 0; }
.hide-opts li { margin: 0; }
.hide-opts .lc-row { margin: 0 0 4px; }
.hide-opts .hint { display: inline; }
#hideSets { flex: 1; min-width: 200px; }

/* A bug in the triage list, marked before the title rather than after it. The
   maintainer is scanning a column of first words for the ones that mean
   somebody is stuck. */
.sug-bug { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  padding: 1px 6px; border-radius: 4px; vertical-align: 1px;
  color: var(--accent-ink); background: var(--accent); }

.ai-notice-btn { padding-inline-start: 12px; }
.ai-notice-btn::before {
  content: ""; width: 1px; height: 14px; margin-inline-end: 12px;
  background: var(--line);
}
/* Full-screen surfaces — the life counter, the shared table — have no header
   to sit in, so the mark goes in the corner. Below the sheet's z-index so an
   open guide covers it rather than the button floating over its own overlay. */
.usage-float { position: fixed; top: 10px; right: 12px; z-index: 40; }
.usage-float img { width: 26px; height: 26px; opacity: 0.72; }
.usage-float:hover img { opacity: 1; }
.usage-scrim {
  position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; padding: 24px;
  background: rgba(0, 0, 0, 0.66);
}
.usage-sheet {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); max-width: 720px; width: 100%;
  max-height: 82vh; display: flex; flex-direction: column; outline: none;
}
.usage-head {
  display: flex; align-items: center; gap: 12px; padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.usage-head h2 { margin: 0; font-size: 19px; color: var(--accent); flex: 1; }
.usage-x {
  background: none; border: 0; color: var(--muted); font-size: 18px;
  cursor: pointer; padding: 4px 8px; border-radius: var(--radius);
}
.usage-x:hover { color: var(--text); }
/* The reading column. Slightly looser than the app's default line height —
   this is prose to be read, not a table to be scanned. */
.usage-body { padding: 4px 20px 20px; overflow-y: auto; line-height: 1.62; }
.usage-body h3 { margin: 20px 0 6px; font-size: 15px; color: var(--accent); }
.usage-body h3:first-child { margin-top: 14px; }
.usage-body p { margin: 0 0 10px; color: var(--text); }
.usage-body ul { margin: 0 0 12px; padding-left: 20px; color: var(--text); }
.usage-body li { margin: 0 0 5px; }
/* This app has no global <a> colour — every link in it is styled by the thing
   it sits in, which is fine until something puts prose on the page. The AI
   notice did, and its email address and Ko-fi link came out as the browser
   default: #0000EE on a near-black panel, which is close to unreadable and
   looks like a page that lost its stylesheet. */
.usage-body a { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }
.usage-body a:hover { color: var(--text); }
@media (max-width: 600px) {
  .usage-scrim { padding: 0; }
  .usage-sheet { max-height: 100vh; border-radius: 0; border: 0; }
}

/* ---- the sponsor board (sponsor.html) --------------------------------
   A funding page read by people who have never seen the app, so it is the
   one page here that is mostly prose. The board underneath it is 150 tiles
   and has to stay legible on a phone, which is why the grid is auto-fill on
   a fixed minimum rather than a column count. */
.sp-pitch, .sp-how { max-width: 62ch; }
.sp-pitch p, .sp-how p { line-height: 1.62; margin: 0 0 10px; }
.sp-steps { line-height: 1.62; padding-left: 20px; margin: 0 0 12px; }
.sp-steps li { margin: 0 0 6px; }

/* The tally. Two stacked spans rather than a bar per status: the eye reads
   "how much of this is done" off one continuous line, and four segments in
   four colours is a chart nobody asked for. */
.sp-tally { margin: 18px 0 22px; max-width: 62ch; }
.sp-bar { display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--line); }
.sp-bar span { display: block; transition: width .3s ease; }
#spBarPainted { background: var(--accent); }
#spBarClaimed { background: #6b6446; }
.sp-nums { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 18px;
  margin: 10px 0 6px; padding: 0; }
.sp-nums li { display: flex; align-items: baseline; gap: 5px; font-size: 13px;
  color: var(--muted); }
.sp-nums b { font-size: 17px; color: var(--text); }

.sp-cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  margin: 14px 0 0; }
.sp-cta { text-decoration: none; display: inline-block; }

.sp-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin: 22px 0 10px; }
.sp-fil { padding: 4px 12px; font-size: 13px; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; cursor: pointer; }
.sp-fil:hover { border-color: var(--accent); }
.sp-fil.on { border-color: var(--accent); color: var(--accent); }
.sp-filters input { margin-left: auto; }

.sp-block-n { float: right; font-weight: 400; color: var(--muted);
  font-size: 13px; }
.sp-grid { list-style: none; margin: 0 0 22px; padding: 0; display: grid;
  gap: 12px; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.sp-tile { display: flex; flex-direction: column; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; cursor: pointer; transition: border-color .15s, transform .15s; }
.sp-tile:hover { border-color: var(--accent); transform: translateY(-2px); }

.sp-art-wrap { position: relative; }
/* 5:3, the same window cardface.js stretches the square source into — so a
   tile and the card it becomes crop the picture identically. */
.sp-art { display: block; width: 100%; aspect-ratio: 5 / 3; object-fit: cover; }
.sp-art-none { background: linear-gradient(160deg, var(--surface-2), var(--surface)); }
/* On the picture, not under it. A disclaimer that is not touching the thing
   it disclaims is one people read past. */
.sp-mark { position: absolute; left: 6px; bottom: 6px; padding: 1px 7px;
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  color: #e8e2d2; background: rgba(12,11,8,.78);
  border: 1px solid rgba(232,226,210,.28); border-radius: 999px; }

.sp-meta { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px 10px; }
/* Not a flex row. It was, with space-between, and on the two-thirds of these
   names that wrap to a second line the identity pips flew off to the top right
   and read as a stray dot beside the title. They belong after the last word,
   which is what ordinary inline flow already does. */
.sp-name { font-weight: 600; font-size: 14.5px; line-height: 1.25; }
.sp-type { font-size: 11.5px; color: var(--muted); }
.sp-status { font-size: 11.5px; margin-top: 3px; }
.sp-status-open { color: var(--accent); }
.sp-status-claimed, .sp-status-painting { color: #b9ab7d; }
.sp-status-painted { color: #8fbf7a; }
.sp-artist { font-size: 12px; color: var(--text); }
.sp-by { font-size: 11.5px; color: var(--muted); }
.sp-note { margin: 4px 0 0; font-size: 11.5px; font-style: italic;
  color: var(--muted); }
/* A finished painting is the point of the page, so it is the one state that
   changes the frame rather than only a line of text. */
.sp-is-painted { border-color: #4e6444; }

.sp-ci { display: inline-flex; gap: 2px; margin-left: 5px;
  vertical-align: middle; }
.sp-pip { width: 9px; height: 9px; border-radius: 999px; display: inline-block;
  border: 1px solid rgba(0,0,0,.45); }
.sp-pip-w { background: #f4efd6; } .sp-pip-u { background: #7fb4d8; }
.sp-pip-b { background: #4a4348; } .sp-pip-r { background: #d1755c; }
.sp-pip-g { background: #78a06a; } .sp-pip-c { background: #b3ada0; }

.sp-admin { margin-top: 28px; padding-top: 14px; border-top: 1px solid var(--line); }

/* The four chips under the theme picker: the ground, a panel on it, the text
   and the accent. A swatch is how somebody recognises a palette they have seen;
   the figure beside it is how they decide whether they can read it. */
.theme-swatch { display: flex; gap: 0; margin: 8px 0 4px; }
.theme-chip { width: 34px; height: 22px; display: block;
  border: 1px solid var(--line); border-right-width: 0; }
.theme-chip:first-child { border-radius: 5px 0 0 5px; }
.theme-chip:last-child { border-radius: 0 5px 5px 0; border-right-width: 1px; }

/* =================================================================== paper ==
   `html.paper` is on whenever the chosen theme is a light one, put there by
   themes.js. It shares the handful of rules below that are about a pale ground
   rather than about electronic paper - a scrim that has to be the page's own
   white rather than a wash over it, and the studio mark, which is a cream
   wordmark drawn for a dark page and is very nearly not there on a pale one.

   Everything else in this section stays e-ink's alone. Flattening the shadows,
   stopping the animation, unsticking the header and lettering the mana pips are
   answers to a *panel* - sixteen greys, a refresh that costs something, no
   pointer - and doing them to somebody who picked Foolscap because they like
   paper would be restyling an app they can see perfectly well.

   ============================================================== e-ink tablet ==
   One class on <html>, put there by eink.js before the first paint.

   This is not "the light theme" under another name, and building it as one
   would get the important half backwards. A phone's dark theme is a kindness
   because the screen emits: less white is less glare in a dark room. E-ink
   emits nothing. It is paper, lit by whatever light is already in the room, and
   its black is a grey somewhere around 15% reflective. Painting the page dark
   therefore spends the panel's entire contrast budget on the background and
   leaves the words sitting in the narrow part of what is left - and then
   repaints that whole dark field every time the page scrolls, which is what a
   full-screen flash is and where ghosting comes from.

   So this runs the dark theme backwards: paper white, ink black, hairlines
   heavy enough to survive sixteen greys, and nothing that moves.

   Three families are deliberately left alone, because they are pictures rather
   than furniture: card images, the drawn card faces (.cf-), and the deck boxes,
   catalogue drawers and card backs (.dbox-, .cat-, .pt-back). A card is the
   card wherever it is shown. Recolouring one is not a theme, it is a negative.

   What this cannot fix is listed on the settings page under the switch, and it
   is listed there rather than here because the person it costs is the reader,
   not whoever next edits this file. */

html.eink {
  /* Surfaces are the same white as the page on purpose. On sixteen greys a
     panel one step off the background is not a panel, it is a dithering
     artefact - so the panels are told apart by their borders instead, and
     --line is heavy enough to be one. */
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #e4e4e4;
  --line: #55524a;
  --text: #000000;
  /* Not a light grey. Hierarchy on paper is size and weight; contrast is the
     budget, and spending it to make secondary text *harder* to read is the one
     thing a reflective panel cannot afford. This is still 9:1 on white. */
  --muted: #45423a;
  --accent: #1a1a1a;
  --accent-ink: #ffffff;
  color-scheme: light;
  /* The checkboxes on this very page came out in the browser's default blue,
     which is the one colour in the app nobody chose. */
  accent-color: #000000;
}
/* The one rule in this file that pinned a widget to the dark scheme. */
html.eink .ad-grid input[type="datetime-local"] { color-scheme: light; }

/* An accent that is a shade of black is not an accent, so what --accent was
   carrying for links has to be carried by something a monochrome panel still
   has.

   Confined to `main`, which is not fussiness. The first draft was
   `a:not([class])` and it underlined the whole crumb nav - fifteen links in a
   row, each with a picture beside it, every one of them ruled. `.crumbs a` sets
   text-decoration: none and loses the specificity argument to `html.eink a`,
   which is the kind of thing you find in a screenshot and never in the CSS.
   Prose links are the ones that needed the underline anyway; a crumb with an
   icon in front of it was never in danger of reading as body text. */
html.eink main a:not([class]) { text-decoration: underline; }

/* --- stillness ------------------------------------------------------------ */
/* Every transition and every animation, including the ones written for
   prefers-reduced-motion, which this is not. A reader who has never asked for
   reduced motion on their phone still gets a smear for every frame here. */
html.eink *, html.eink *::before, html.eink *::after {
  transition: none !important;
  animation: none !important;
}
html.eink { scroll-behavior: auto; }
/* The busy paw. ai.js swaps the walking SVG for the still one (SMIL cannot be
   stopped from a stylesheet), and the still one was given an opacity pulse so
   it would still read as alive - which is a repaint a second on a panel that
   charges for repaints. The words beside it are the sign of life here. */
html.eink .paw-spin { opacity: 1; }

/* --- flatness ------------------------------------------------------------- */
/* Shadows carry no information in this app - every one of them is elevation,
   and elevation is a lighting metaphor on a surface with no light. What they do
   carry on e-ink is speckle, because a soft gradient in the last two greys gets
   dithered. The card faces and deck boxes keep theirs: there it is the edge of
   a drawn object, and without it the object has no boundary. */
html.eink *:not(.cf):not(.dbox):not(.cat-card):not(.cat-drawer):not(.cat-plate) {
  box-shadow: none !important;
  text-shadow: none !important;
}

/* --- the sticky bar ------------------------------------------------------- */
/* The single most expensive thing on the page for a panel like this. A sticky
   header is redrawn against new pixels for every line the page scrolls, and a
   partial refresh repeatedly asked to redraw the same rectangle is precisely
   how ghosting accumulates - the bar is the part of the screen that ends up
   grey and streaked while the rest of it is clean. It scrolls away instead.
   The playtest board stacks three of these, which is the same cost thrice. */
html.eink .topbar,
html.eink .pt-bar,
html.eink .pt-row-other,
html.eink .pt-row-lands,
html.eink .pt-mana { position: static; }
/* Which is exactly why the back-to-top button stays: with no bar riding along,
   it is the way back to the nav, and it does not repaint while it sits still. */

/* --- dialogs -------------------------------------------------------------- */
/* A translucent scrim is a grey wash here. The page behind it does not recede,
   it dithers, and the dialog on top then competes with the noise. Going opaque
   also means one rectangle to refresh rather than a whole page rendered twice -
   the sheet simply takes the screen, which is what it was trying to say in the
   first place. The playtest zoom keeps its dark backdrop: what sits on top of
   that one is a card image, and a card wants a dark mount. */
html.eink .sheet-scrim, html.paper .sheet-scrim,
html.eink .exp-scrim, html.paper .exp-scrim,
html.eink .usage-scrim, html.paper .usage-scrim,
html.eink .lt-zoom-scrim, html.paper .lt-zoom-scrim { background: var(--bg); }
html.eink .sheet-panel,
html.eink .exp-panel,
html.eink .bd-bases-panel { border: 2px solid var(--line); }

/* --- affordances that were behind :hover ---------------------------------- */
/* A control revealed on hover is a control that does not exist on a slate. Each
   of these already un-hides on :focus-within for keyboard users; e-ink just
   stops hiding them in the first place. */
html.eink .sec-act,
html.eink .fmt-new,
html.eink .brk-new,
html.eink .dbox-del,
html.eink .cat-rm { opacity: 1; pointer-events: auto; }

/* --- the mana pips -------------------------------------------------------- */
/* This is the one place the app leaned on colour, and it is worth being exact
   about how badly. The five pip colours land at 13%, 20%, 21%, 26% and 76%
   grey: white is white, and blue, black, red and green are one grey. On top of
   that they carry a near-black letter, so blue-on-its-letter is about 4.5:1 and
   black-on-its-letter about 3.2:1 - a bold nine-pixel glyph at the bottom of a
   reflective panel's range.
   The letter was always the part carrying the meaning and the colour was the
   decoration, so on paper the circle goes white and the letter goes black. The
   inline `background` these are drawn with is why this needs !important. */
html.eink .pt-pip,
html.eink .pt-pip-sm,
html.eink .pt-mana-opt i,
html.eink .pt-loyal-opt i,
html.eink .tk-pip,
html.eink .sp-pip {
  background: #ffffff !important;
  color: #000000 !important;
  border: 1px solid #000000;
}
/* Except the sponsor pips, which are the only ones in the app with no letter in
   them at all - five empty circles saying everything by hue. On e-ink they said
   nothing, so they are given the letter the others already had. */
html.eink .sp-pip { width: 13px; height: 13px; font-size: 9px; font-weight: 700;
  font-style: normal; line-height: 11px; text-align: center; }
html.eink .sp-pip-w::after { content: "W"; }
html.eink .sp-pip-u::after { content: "U"; }
html.eink .sp-pip-b::after { content: "B"; }
html.eink .sp-pip-r::after { content: "R"; }
html.eink .sp-pip-g::after { content: "G"; }
html.eink .sp-pip-c::after { content: "C"; }

/* --- the words that were red ---------------------------------------------- */
/* Every one of these becomes some dark grey, so none of them is still saying
   "bad" by being the colour it is. That is fine, and is why they are darkened
   rather than replaced with a mark: each already sits next to the words that
   mean it - "Not legal in", "Banned", "3 short". The colour was agreeing with a
   sentence, not standing in for one. */
html.eink .leg-bad,
html.eink .status-bad,
html.eink .bd-short.bd-bad,
html.eink .cat-del:hover,
html.eink .pt-mana-pain { color: #7a2a13; }
html.eink .leg-warn { color: #5f4300; }
html.eink .legality-panel { border-color: #7a2a13; }
html.eink .chip-bad { background: #f2ded8; color: #6b2410; border-color: #7a2a13; }
html.eink .chip-gc { background: #efe6c6; color: #4e3d00; border-color: #6b5400; }
/* The credit meter's two states were two hues on one bar. On paper the full one
   is the darker of two greys, which is a difference a reader can see without
   being told which colour means what. */
html.eink .meter-fill { background: #8a8a8a; }
html.eink .meter-full { background: #1a1a1a; }

/* --- the pictures --------------------------------------------------------- */
/* Grayscale is not for looks - it stops the panel picking its own dithering per
   hue, which is where the speckle in a card's sky comes from. The contrast nudge
   pulls the type box and the border away from the art; a Magic card is mostly
   mid-tones, and mid-tones are the range sixteen greys have least of.
   The painted icons are left alone. They are dark art on a dark ground, and on
   white they read as inked stamps - which is what they look like on paper
   anyway. */
/* The life counter's well is a recess: a top-to-bottom gradient with an inset
   shadow inside it. The shadow is already gone with every other one, and what
   the gradient leaves behind is eight greys' worth of ramp behind a number
   somebody is reading across a table. Flat, with an edge, says "panel" just as
   well and dithers into nothing. */
html.eink .lc-well { background: var(--surface-2); border: 1px solid var(--line); }

/* The studio mark in the footer is a cream wordmark on transparency, drawn for
   a dark page, and on white it is very nearly not there. It is the one image in
   the app that is a *mark* rather than a picture, so unlike a card it can be
   turned over: grayscale first, then inverted, which puts dark letters on the
   paper instead of pale ones. Full opacity because .75 of a low-contrast mark
   on a low-contrast panel is a smudge. */
html.eink .foot-mark, html.paper .foot-mark { opacity: 1; }
html.eink .foot-mark img,
html.paper .foot-mark img { filter: grayscale(1) invert(1); }

html.eink .card .art,
html.eink .cd-img,
html.eink .cd-figure img,
html.eink #hoverCard,
html.eink .pt-card img,
html.eink .lt-zoom-panel img,
html.eink .cf-full-img { filter: grayscale(1) contrast(1.12); }
