/* TM26 — faithful translation of the old Dash design language.
   Source of truth: app/shared/config.py + app/assets/custom.css + app/main.py.
   See web/docs/design_language.md. Server-rendered surfaces; charts/grids are
   the only client JS. */

@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=DM+Mono:wght@300;400;500&family=Outfit:wght@300;400;500;600&display=swap');

:root{
  --bg:#0a0c12; --paper:#13161f; --surface:#1c202e; --input:#252836;
  --border:#2a2d3e;
  --text:#e8eaf0; --subtext:#9aa0b3;            /* SUBTEXT is WCAG-AA — do not darken */
  --accent:#e8722a; --accent-dim:rgba(232,114,42,.15);
  --blue:#4ea8de; --up:#3ddc84; --down:#ff6b6b;
  --font-brand:'Bebas Neue',sans-serif;
  --font-mono:'DM Mono',ui-monospace,monospace;
  --font-ui:'Outfit',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--text);
  font-family:var(--font-ui);font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased}
a{color:inherit}

/* ── Header (brand block + controls) ─────────────────────────────────────────
   main.py ~511: flex row, padding-bottom 24, bottom border, margin-bottom 32. */
.tm26-header{display:flex;align-items:center;justify-content:space-between;
  padding:20px 24px 24px;max-width:1180px;margin:0 auto;
  border-bottom:1px solid var(--border)}
.brand{display:flex;align-items:center;gap:16px;text-decoration:none}
.brand-box{display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;line-height:.85;border:2px solid var(--accent);border-radius:4px;padding:6px 10px}
.brand-box .tm{font-family:var(--font-brand);font-size:46px;line-height:.85;letter-spacing:2px;color:var(--accent)}
.brand-box .yr{font-family:var(--font-brand);font-size:46px;line-height:.85;letter-spacing:2px;color:#fff}
.brand-text{display:flex;flex-direction:column;justify-content:center;gap:0}
.brand-text span{font-family:var(--font-ui);font-size:19px;font-weight:500;color:var(--text);
  letter-spacing:1.5px;text-transform:uppercase;line-height:1.1}
.brand-text .est{font-size:7px;color:var(--subtext);letter-spacing:1.5px;margin-top:3px}
.user{display:flex;align-items:center;gap:14px}
.email{color:var(--accent);font-size:11px;font-family:var(--font-mono);letter-spacing:.3px}
.btn-logout{background:transparent;color:var(--subtext);border:1px solid var(--border);
  border-radius:6px;padding:6px 14px;cursor:pointer;font-size:12px;font-weight:600;font-family:inherit}
.btn-logout:hover{color:#fff;border-color:var(--down);background:rgba(255,107,107,.08)}

/* ── Section-pill nav (main.py 732) ──────────────────────────────────────────── */
.tm26-nav{max-width:1180px;margin:0 auto;border-bottom:1px solid var(--border)}
.tabs{display:flex;gap:26px;padding:6px 24px 0}
.tab{background:transparent;color:var(--subtext);border:none;border-bottom:2px solid transparent;
  border-radius:0;padding:9px 2px 11px;cursor:pointer;font-size:12px;font-family:var(--font-ui);
  font-weight:600;letter-spacing:1.4px;text-transform:uppercase;text-decoration:none;
  transition:color .12s ease,border-color .12s ease;margin-bottom:-1px}
.tab:hover{color:var(--text)}
.tab.active{color:var(--text);border-bottom-color:var(--accent);font-weight:700}
/* In-menu copy of the section nav — shown only inside the mobile hamburger menu. */
.nav-mobile{display:none}

/* ── page scaffold ─────────────────────────────────────────────────────────── */
/* Content panel — old tab-content wrapper (main.py:764): card_style with rounded
   BOTTOM corners + no top border, so it reads as one panel attached to the nav
   above it (whose bottom border forms this panel's top edge). */
.content{background:var(--paper);border:1px solid var(--border);border-top:none;
  border-radius:0 0 8px 8px;padding:20px 24px 28px;max-width:1180px;margin:0 auto 40px}
h1{font-size:20px;font-weight:600;letter-spacing:.01em;margin:0 0 14px;font-family:var(--font-ui)}
h3{font-size:15px;font-weight:600;margin:18px 0 8px}
.muted{color:var(--subtext)}
.accent{color:var(--accent)}
.up{color:var(--up)} .down{color:var(--down)}
.big{font-size:22px;font-weight:700}
.section-label{display:block;color:var(--subtext);font-family:var(--font-mono);font-size:11px;
  font-weight:500;letter-spacing:1px;text-transform:uppercase;margin:24px 0 10px}

/* ── sub-tabs (underline — main.py _subtab_btn_style) ──────────────────────── */
.subtabs{display:flex;gap:0;margin:0 0 22px;border-bottom:1px solid var(--border);flex-wrap:wrap}
.subtab{padding:10px 16px;color:var(--subtext);text-decoration:none;font-size:12px;font-weight:400;
  font-family:var(--font-ui);border-bottom:2px solid transparent;margin-bottom:-1px;white-space:nowrap;
  transition:color .15s,border-color .15s}
.subtab:hover{color:var(--text)}
.subtab.active{color:var(--accent);border-bottom-color:var(--accent);font-weight:600}

/* ── league-detail — ESPN-style tabs + team header ─────────────────────────── */
.ld-topbar{display:flex;align-items:center;gap:11px;margin:0 0 12px}
.ld-title{font-family:var(--font-ui);font-size:21px;font-weight:700;margin:0;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ld-back{display:flex;align-items:center;justify-content:center;width:34px;height:34px;flex-shrink:0;
  background:var(--surface);color:var(--subtext);border:1px solid var(--border);border-radius:8px;
  font-size:16px;text-decoration:none}
.ld-back:hover{color:var(--text);border-color:var(--accent)}
/* draft bar — only while a draft is live */
.ld-draftbar{display:flex;align-items:center;justify-content:space-between;gap:10px;text-decoration:none;
  background:var(--accent-dim);border:1px solid var(--accent);border-radius:9px;padding:9px 13px;
  margin-bottom:12px;color:var(--text);font-size:13px;font-weight:600}
.ld-draftbar .ld-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#4ade80;
  margin-right:7px;box-shadow:0 0 0 3px rgba(74,222,128,.18)}
/* underline tab bar */
.ld-tabs{display:flex;gap:22px;margin-bottom:18px;overflow-x:auto;
  border-bottom:1px solid var(--border)}
.ld-tab{background:transparent;color:var(--subtext);border:none;border-bottom:2px solid transparent;
  border-radius:0;padding:8px 2px 10px;cursor:pointer;font-size:12px;font-weight:600;
  letter-spacing:1.2px;text-transform:uppercase;font-family:var(--font-ui);white-space:nowrap;
  margin-bottom:-1px;transition:color .12s ease,border-color .12s ease}
.ld-tab:hover{color:var(--text)}
.ld-tab.active{color:var(--accent);border-bottom-color:var(--accent);font-weight:700}
.ld-tab.active:hover{color:var(--accent);border-bottom-color:var(--accent)}
.ld-panel{display:none}
.ld-panel.active{display:block}
/* team header banner — compact */
.ld-teamhead{display:flex;align-items:center;gap:11px;background:var(--paper);border:1px solid var(--border);
  border-left:3px solid var(--accent);border-radius:10px;padding:10px 13px;margin-bottom:14px}
.ld-teamemoji{width:38px;height:38px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:19px;background:var(--surface);border:1px solid var(--border);flex-shrink:0}
.ld-teamname{font-size:16px;font-weight:700;margin:0;line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ld-teammeta{color:var(--subtext);font-size:11.5px;font-family:var(--font-mono);margin-top:1px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ld-teamhead>div:nth-child(2){min-width:0;flex:1}
.ld-teamstats{margin-left:auto;display:flex;gap:16px;flex-shrink:0}
.ld-teamstat{text-align:right}
.ld-teamstat .v{display:block;font-size:15px;font-weight:700;font-family:var(--font-mono);line-height:1.1}
.ld-teamstat .k{font-size:8px;text-transform:uppercase;letter-spacing:.5px;color:var(--subtext)}
/* league hub section list */
.ld-section{margin-bottom:22px}
.tscroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.tscroll>table{min-width:max-content}
/* roster binder view (cosmetic 3x3 pages) */
.roster-view{display:inline-flex;align-items:center;gap:6px}
.roster-view .rv-label{font-size:9px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
  color:var(--subtext);font-family:var(--font-mono)}
.roster-toggle{display:inline-flex;border:1px solid var(--border);border-radius:6px;overflow:hidden;
  background:var(--input)}
.rt-btn{cursor:pointer;border:0;background:transparent;color:var(--subtext);padding:5px 12px;
  font-size:10.5px;font-weight:600;letter-spacing:.8px;text-transform:uppercase;
  font-family:var(--font-mono);text-decoration:none;display:inline-block;
  transition:color .12s ease,background .12s ease}
.rt-btn + .rt-btn{border-left:1px solid var(--border)}
.rt-btn:hover{color:var(--text)}
.rt-btn.on{background:var(--surface);color:var(--accent);font-weight:700;
  box-shadow:inset 0 -2px 0 var(--accent)}
/* binder pages stay physical-binder sized: full width on phones, capped on
   desktop (a 3x3 page across 1100px reads as comically zoomed card art) */
.rb-page{background:var(--paper);border:1px solid var(--border);border-radius:12px;padding:12px;margin-bottom:14px;max-width:540px}
.rb-pageno{font-family:var(--font-mono);font-size:10px;color:var(--subtext);letter-spacing:.5px;margin:0 2px 9px}
.rb-pockets{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.rb-pocket{min-width:0;background:var(--surface);border:1px solid var(--border);border-radius:10px;
  padding:7px 5px;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:4px;
  text-align:center;font-family:inherit;color:var(--text);transition:transform .12s,border-color .12s}
.rb-pocket:hover{border-color:var(--accent);transform:translateY(-2px)}
.rb-empty{background:rgba(127,131,150,.045);border-style:dashed;border-color:#3a3f55;cursor:default;min-height:150px}
.rb-slot{font-size:8.5px;text-transform:uppercase;letter-spacing:.3px;color:var(--subtext);
  font-family:var(--font-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.rb-img{width:100%;border-radius:5px;aspect-ratio:.72;object-fit:cover;background:var(--bg)}
.rb-price{font-family:var(--font-mono);font-weight:700;font-size:13px}
.rb-pnl{font-family:var(--font-mono);font-size:9.5px;line-height:1.2;word-break:break-word;max-width:100%}
.rb-modal{position:fixed;inset:0;background:rgba(0,0,0,.78);display:none;align-items:center;
  overscroll-behavior:contain;
  justify-content:center;z-index:100;padding:20px}
.rb-modal.open{display:flex}
/* Confirm dialogs must layer ABOVE the card lightbox (z 3000): buying from
   the enlarged view opened the confirm underneath it (owner 2026-08-25). */
#dex-confirm, #swap-modal{z-index:3100}
.rb-mcard{background:var(--paper);border:1px solid var(--border);border-radius:8px;padding:18px;
  max-width:330px;width:100%;text-align:center;box-shadow:0 20px 50px rgba(0,0,0,.6)}
.rb-mcard img{width:100%;max-width:270px;border-radius:10px}
.rb-mname{font-weight:700;font-size:16px;margin-top:12px}
.rb-mprice{font-family:var(--font-mono);color:var(--accent);font-size:19px;font-weight:700;margin:3px 0 14px}
.rb-sell{background:rgba(239,68,68,.08);color:#f87171;border:1px solid rgba(248,113,113,.35);
  border-radius:4px;padding:10px 20px;font-size:13px;font-weight:600;cursor:pointer;width:100%;
  transition:background .12s ease,border-color .12s ease}
.rb-sell:hover{background:rgba(239,68,68,.18);border-color:#f87171}
.rb-close{background:none;border:0;color:var(--subtext);margin-top:12px;cursor:pointer;font-size:12px}
/* ── Pokédex Binder (Paper Trading) — empty slot placeholders + buy modal ─────── */
.bx-empty{background:rgba(127,131,150,.05);border-style:dashed;border-color:#3a3f55;
  min-height:150px;justify-content:center;gap:6px}
.bx-empty:hover{border-color:var(--accent);border-style:solid}
.bx-num{font-family:var(--font-mono);font-weight:700;font-size:15px;color:var(--subtext)}
.bx-name{font-size:11px;color:var(--text);line-height:1.15;max-width:100%;
  overflow:hidden;text-overflow:ellipsis}
.bx-add{font-size:10px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;
  color:var(--accent);margin-top:2px}
.bx-mcard{max-width:560px;text-align:left;max-height:84vh;display:flex;flex-direction:column}
.bx-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--border);font-size:15px}
.bx-filters{display:flex;gap:8px;margin-bottom:10px;flex-wrap:wrap}
.bx-filters .bx-search{flex:1;min-width:120px}
.bx-filters .bx-setfilter{flex:1;min-width:130px}
.bx-prange{display:flex;align-items:center;gap:5px}
.bx-prange input{width:74px}
/* The lazy-loaded fragment lives in #bx-buy-body; make it the flex column so the
   table area can scroll. min-height:0 is REQUIRED or the flex child grows to fit
   its content (default min-height:auto) and overflow:auto never kicks in. */
#bx-buy-body{display:flex;flex-direction:column;flex:1;min-height:0}
.bx-tablewrap{overflow:auto;-webkit-overflow-scrolling:touch;flex:1;min-height:0;
  border:1px solid var(--border);border-radius:8px}
.bx-table{width:100%;border-collapse:collapse;font-size:12.5px;table-layout:fixed}
.bx-table th:nth-child(1){width:37%}.bx-table th:nth-child(2){width:15%}
.bx-table th:nth-child(3){width:19%}.bx-table th:nth-child(4){width:13%}
.bx-table th:nth-child(5){width:16%}
/* Pokédex pool: narrower Card column than the fantasy default (owner) */
.pool-table .bx-table th:nth-child(1){width:21%}
.pool-table .bx-table th:nth-child(2){width:13%}
.pool-table .bx-table th:nth-child(3){width:34%}
.pool-table .bx-table th:nth-child(4){width:12%}
.pool-table .bx-table th:nth-child(5){width:20%}
.bx-table thead th{position:sticky;top:0;background:var(--surface);z-index:1;text-align:left;
  padding:8px 9px;font-size:10px;letter-spacing:.4px;text-transform:uppercase;color:var(--subtext);
  white-space:nowrap;border-bottom:1px solid var(--border)}
.bx-table th.num,.bx-table td.num{text-align:right;font-family:var(--font-mono)}
.bx-sort{cursor:pointer;user-select:none}
.bx-sort:hover{color:var(--text)}
.bx-sort.asc::after{content:" ▲";font-size:8px;color:var(--accent)}
.bx-sort.desc::after{content:" ▼";font-size:8px;color:var(--accent)}
.bx-table tbody tr{border-bottom:1px solid var(--border)}
.bx-table tbody tr:last-child{border-bottom:0}
.bx-table td{padding:6px 9px;vertical-align:middle;overflow:hidden}
.bx-card{display:flex;align-items:center;gap:8px}
/* General rule (works inline, e.g. Fantasy free agents); declared after
   .rb-mcard img{width:100%} so it also wins inside the binder modal. */
.bx-card .sfoil{width:32px;height:44px;flex-shrink:0;border-radius:4px}
.bx-card .sfoil>img{width:100%;height:100%;object-fit:cover;display:block}
img.bx-thumb{width:32px;max-width:32px;height:44px;object-fit:cover;border-radius:4px;
  background:var(--bg);cursor:zoom-in;flex-shrink:0}
.bx-cardname{min-width:0;display:flex;flex-direction:column;line-height:1.2;word-break:break-word}
.bx-rar{font-style:normal;font-size:10px;color:var(--subtext);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bx-setcell{color:var(--subtext);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bx-pricecell{font-weight:700;white-space:nowrap}
.bx-buybtn{padding:5px 7px;font-size:11px;width:100%}
.bx-qty{width:42px;padding:4px 5px;font-size:12px;text-align:center}
/* ── Paper Trading — portfolio selector cards ───────────────────────────────── */
.pf-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:12px}
.pf-card{display:block;background:var(--surface);border:1px solid var(--border);border-radius:12px;
  padding:14px 15px;text-decoration:none;color:var(--text);transition:border-color .15s,transform .12s}
.pf-card:hover{border-color:var(--accent);transform:translateY(-2px)}
.pf-top{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}
.pf-name{font-weight:700;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pf-tier{font-size:9px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;
  padding:2px 8px;border-radius:20px;background:var(--accent-dim);color:var(--accent);flex-shrink:0}
.pf-total{font-family:var(--font-mono);font-size:22px;font-weight:700;margin-bottom:6px}
.pf-meta{display:flex;flex-wrap:wrap;gap:4px 12px;font-family:var(--font-mono);font-size:11.5px}
/* roster List view — rich vertical rows (mirror the binder fields) */
.rl-row{display:flex;align-items:center;gap:11px;background:var(--paper);border:1px solid var(--border);
  border-radius:10px;padding:9px 11px;margin-bottom:10px}
.rl-img{width:54px;border-radius:6px;aspect-ratio:.72;object-fit:cover;background:var(--bg);flex-shrink:0;cursor:pointer}
.rl-info{flex:1;min-width:0;overflow:hidden}
.rl-slot{font-size:9px;text-transform:uppercase;letter-spacing:.4px;color:var(--subtext);font-family:var(--font-mono);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rl-name{font-weight:600;font-size:14px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rl-nums{text-align:right;flex-shrink:0}
.rl-price{font-family:var(--font-mono);font-weight:700;font-size:14px}
.rl-pnl{font-family:var(--font-mono);font-size:10px;white-space:nowrap}
.rl-sell{background:#7f1d1d;color:#fca5a5;border:1px solid #991b1b;border-radius:7px;padding:8px 14px;
  font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;flex-shrink:0}
.rl-sell:hover{background:#991b1b;color:#fecaca}
/* free-agents / holdings rows (mobile-first card list, replaces the wide table) */
.fa-row{display:flex;align-items:center;gap:11px;background:var(--paper);border:1px solid var(--border);
  border-radius:10px;padding:9px 11px;margin-bottom:9px}
.fa-img{width:48px;border-radius:5px;aspect-ratio:.72;object-fit:cover;background:var(--bg);flex-shrink:0}
.fa-info{flex:1;min-width:0;overflow:hidden}
.fa-name{font-weight:600;font-size:13.5px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fa-meta{display:flex;gap:10px;flex-wrap:wrap;font-size:10px;font-family:var(--font-mono);margin-top:3px;align-items:center}
.fa-meta .fa-set{color:var(--subtext);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:130px}
.fa-right{text-align:right;flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:6px}
.fa-price{font-family:var(--font-mono);font-weight:700;font-size:14px}
.fa-add{background:rgba(34,197,94,.08);color:#4ade80;border:1px solid rgba(74,222,128,.35);
  border-radius:4px;padding:6px 14px;font-size:11.5px;font-weight:600;letter-spacing:.3px;
  cursor:pointer;white-space:nowrap;transition:background .12s ease,border-color .12s ease}
.fa-add:hover{background:rgba(34,197,94,.16);border-color:#4ade80}

/* ── cards & panels (radius 8, padding 20) ─────────────────────────────────── */
.card{background:var(--paper);border:1px solid var(--border);border-radius:6px;
  padding:20px;margin-bottom:20px}
.grid-wrap{background:var(--paper);border:1px solid var(--border);border-radius:8px;padding:12px}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:6px}
.two-col>div{min-width:0}
@media(max-width:760px){.two-col{grid-template-columns:1fr}}

/* ── stat row ──────────────────────────────────────────────────────────────── */
.stat-row{display:flex;flex-wrap:wrap;gap:14px;margin:8px 0 4px}
.stat{background:var(--surface);border:1px solid var(--border);border-radius:8px;
  padding:14px 16px;min-width:130px;flex:1}
.stat span{display:block;color:var(--subtext);font-family:var(--font-mono);font-size:10px;
  text-transform:uppercase;letter-spacing:1px;margin-bottom:4px}
.stat b{font-size:19px;font-weight:700}

/* ── tiles (set tiles / league cards — 2px border, radius 12, hover accent) ─── */
.tile-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}
.tile{display:block;background:var(--paper);border:2px solid var(--border);border-radius:12px;
  padding:18px;text-decoration:none;color:var(--text);transition:border-color .15s}
.tile:hover{border-color:var(--accent)}
.tile-name{font-weight:600;font-size:15px;margin-bottom:12px}
.tile-row{display:flex;justify-content:space-between;font-size:12.5px;color:var(--subtext);margin-bottom:5px}
.tile-row b{color:var(--text);font-family:var(--font-mono)}

/* ── tables (SURFACE header, BORDER dividers, mono numerics) ───────────────── */
table.data{width:100%;border-collapse:collapse;font-size:13.5px;
  background:var(--paper);border:1px solid var(--border);border-radius:8px;overflow:hidden}
table.data thead th{text-align:left;color:var(--subtext);font-family:var(--font-mono);font-weight:500;
  font-size:11px;text-transform:uppercase;letter-spacing:.6px;padding:10px 12px;background:var(--surface);
  border-bottom:1px solid var(--border)}
table.data td{padding:9px 12px;border-bottom:1px solid var(--border)}
table.data tbody tr:last-child td{border-bottom:0}
table.data tbody tr:hover{background:var(--surface)}
.num{font-family:var(--font-mono);font-variant-numeric:tabular-nums;text-align:right}

/* ── forms & buttons ───────────────────────────────────────────────────────── */
select{appearance:none;-webkit-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%236b7080'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center;
  padding-right:24px !important;font-family:var(--font-mono);cursor:pointer}
input,select,textarea{background:var(--input);border:1px solid var(--border);
  border-radius:6px;padding:8px 12px;color:var(--text);font-size:14px;font-family:inherit}
input::placeholder{color:var(--subtext);opacity:.7}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-dim)}
.btn-primary{background:transparent;color:var(--accent);border:1px solid var(--accent);
  border-radius:4px;padding:7px 16px;cursor:pointer;font-weight:600;font-size:12.5px;
  font-family:inherit;letter-spacing:.3px;transition:background .12s ease,color .12s ease}
.btn-primary:hover{background:var(--accent);color:#0a0c12}
button{font-family:inherit}
button:not(.btn-primary):not(.btn-logout):not(.btn-danger):not(.btn-success):not(.ld-tab):not(.rt-btn):not(.rb-sell):not(.rl-sell):not(.fa-add){background:var(--surface);color:var(--subtext);
  border:1px solid var(--border);border-radius:6px;padding:8px 14px;cursor:pointer;
  font-size:13.5px;font-weight:600}
button:not(.btn-primary):not(.btn-logout):not(.btn-danger):not(.btn-success):not(.ld-tab):not(.rt-btn):not(.rb-sell):not(.rl-sell):not(.fa-add):hover{color:var(--text);border-color:var(--accent)}
/* Canonical button variants (old btn-danger/btn-success/btn-ghost/btn-sm) — token
   versions of the danger reds / success greens previously inlined per template. */
.btn-danger{background:#7f1d1d;color:#fca5a5;border:1px solid #991b1b;border-radius:6px;
  padding:6px 14px;cursor:pointer;font-size:12px;font-weight:600;font-family:inherit}
.btn-danger:hover{background:#991b1b;color:#fff}
.btn-success{background:#14532d;color:#86efac;border:1px solid #166534;border-radius:6px;
  padding:6px 14px;cursor:pointer;font-size:12px;font-weight:600;font-family:inherit}
.btn-success:hover{background:#166534;color:#fff}
.btn-sm{padding:4px 10px;font-size:11px}
.trade-form{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.trade-note{background:var(--accent-dim);border:1px solid var(--accent);border-left:4px solid var(--accent);
  color:var(--text);border-radius:6px;padding:10px 14px;font-size:13.5px;margin:0 0 16px}

/* ── chips / variant toggles (pill) ────────────────────────────────────────── */
.variant-row{display:flex;gap:6px;margin:12px 0;flex-wrap:wrap}
.chip{display:inline-block;padding:6px 14px;border:1px solid var(--border);border-radius:20px;
  background:var(--surface);color:var(--subtext);text-decoration:none;font-size:13px}
.chip:hover{color:var(--text);border-color:var(--accent)}
.chip.active{background:var(--accent);color:#fff;border-color:var(--accent)}

/* ── card thumbnails + lightbox (old TCGPlayer-CDN pattern) ────────────────── */
.card-thumb{height:auto;aspect-ratio:5/7;object-fit:contain;border-radius:4px;
  background:var(--surface);cursor:zoom-in;vertical-align:middle;display:inline-block}
.card-thumb-empty{display:inline-block;aspect-ratio:5/7;border-radius:4px;
  background:var(--surface);vertical-align:middle;width:42px}
td .card-thumb,td .card-thumb-empty{width:42px}
#tm26-lightbox{display:none;position:fixed;inset:0;background:rgba(0,0,0,.88);z-index:3000;
  flex-direction:column;align-items:center;justify-content:center;gap:10px;cursor:zoom-out}
#tm26-lightbox img{max-height:90vh;max-width:90vw;border-radius:12px;box-shadow:0 8px 60px rgba(0,0,0,.8)}
#tm26-lightbox.has-nav img{max-height:72vh}
/* Desktop cap (owner 2026-09-04: "on desktop I had them popup massive"). 90vh
   on a laptop rendered a ~810px-tall card. A px ceiling alongside the viewport
   units keeps phones exactly as they were — 92vw still governs there. Applies
   to the SOLO popup (direct children) and, via the stage below, to the
   browse mode. */
#tm26-lightbox > img, #tm26-lightbox > .lb-foil{
  max-height:min(86vh, 540px); max-width:min(92vw, 388px)}
#tm26-lightbox > .lb-foil img{width:100%;max-height:none;max-width:none}
#tm26-lightbox .lb-imgbox{height:min(72vh, calc(100vh - 210px), 560px);max-width:92vw;
  display:flex;align-items:center;justify-content:center}
#tm26-lightbox .lb-imgbox img{max-height:100%}
#tm26-lightbox .lb-foil{display:block;border-radius:12px;overflow:hidden;
  box-shadow:0 8px 60px rgba(0,0,0,.8)}
#tm26-lightbox .lb-foil img{display:block;box-shadow:none;border-radius:0}
#tm26-lightbox .lb-nav{cursor:pointer;width:72px;height:44px;border-radius:12px;padding:0;
  display:flex;align-items:center;justify-content:center;color:var(--text);
  background:rgba(28,32,46,.92);border:1px solid var(--border)}
#tm26-lightbox .lb-nav:disabled{opacity:.22;cursor:default}
#tm26-lightbox .lb-nav svg{width:24px;height:24px}
#tm26-lightbox .lb-row{display:flex;align-items:center;gap:10px;max-width:92vw}
#tm26-lightbox .lb-cap{font-family:var(--font-mono);font-size:12.5px;color:var(--text);
  background:rgba(19,22,31,.8);border:1px solid var(--border);padding:3px 12px;border-radius:8px;
  min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#tm26-lightbox .lb-set{flex:0 1 auto}
#tm26-lightbox .lb-price{flex:0 0 auto}
#tm26-lightbox .lb-buy{flex:0 0 auto;font-size:13px;padding:7px 18px}
#tm26-lightbox .lb-buy[disabled]{opacity:.4;cursor:default}
#tm26-lightbox .lb-x{position:absolute;top:12px;right:12px;width:44px;height:44px;border-radius:50%;
  cursor:pointer;background:rgba(28,32,46,.92);border:1px solid var(--border);color:var(--text);
  font-size:26px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0 0 3px}

/* ── lists ─────────────────────────────────────────────────────────────────── */
ul.plain{list-style:none;padding:0;margin:0}
ul.plain li{padding:8px 0;border-bottom:1px solid var(--border);font-size:14px}
ul.plain li:last-child{border-bottom:0}

/* ── footer ────────────────────────────────────────────────────────────────── */
.tm26-footer{max-width:1180px;margin:40px auto 0;padding:20px 24px;border-top:1px solid var(--border);
  display:flex;flex-direction:column;align-items:center;gap:8px;color:var(--subtext);
  font-family:var(--font-mono);font-size:10px;letter-spacing:.3px;text-align:center}
.tm26-footer a{color:var(--subtext);text-decoration:none}
.tm26-footer a:hover{color:var(--text)}
.tm26-footer .links{display:flex;gap:16px;flex-wrap:wrap;justify-content:center}

/* ── login ─────────────────────────────────────────────────────────────────── */
.login-body{display:flex;min-height:100vh;align-items:center;justify-content:center;background:var(--bg)}
.login-card{background:var(--paper);border:1px solid var(--border);border-radius:8px;
  padding:32px;width:340px;display:flex;flex-direction:column;gap:15px}
.brand-lg{font-family:var(--font-brand);font-weight:400;color:var(--accent);font-size:44px;
  text-align:center;letter-spacing:3px;margin-bottom:4px}
.login-card label{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--subtext)}
.error{color:var(--down);font-size:13px;margin:0}

/* ── Master Sets featured dashboard — fixed 2x2, fully contained ─────────────── */
.featured-wrap{position:relative;margin-bottom:8px}
.featured-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
.featured-chart{margin-bottom:0;overflow:hidden;min-width:0;display:flex;flex-direction:column}
.feat-reason{font-family:var(--font-mono);font-size:9px;font-weight:700;letter-spacing:.6px;
  text-transform:uppercase;color:var(--accent);margin-bottom:5px}
.feat-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin-bottom:6px;min-width:0}
.feat-head a{font-weight:600;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.feat-chart-box{height:190px;overflow:hidden}
.feat-chart-box>div{width:100%;height:100%}
/* Gold/silver/bronze podium — top accent + medal-coloured reason label. */
.featured-chart.feat-gold{border-top:3px solid #f4c95d}
.featured-chart.feat-silver{border-top:3px solid #c4c9d6}
.featured-chart.feat-bronze{border-top:3px solid #cd8a4d}
.featured-chart.feat-gold .feat-reason{color:#f4c95d}
.featured-chart.feat-silver .feat-reason{color:#c4c9d6}
.featured-chart.feat-bronze .feat-reason{color:#cd8a4d}
/* Carousel arrows retired — the 2x2 grid doesn't scroll. */
.carousel-arrow{display:none}
@media(max-width:640px){
  .featured-grid{grid-template-columns:1fr}   /* single column on phones */
}

/* ── card-search add results (watchlists / indexes / price targets) ─────────── */
.card-search-results{margin-top:8px;max-height:280px;overflow-y:auto;border:1px solid var(--border);
  border-radius:6px;background:var(--surface)}
.csr-row{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;
  padding:7px 12px;border-bottom:1px solid var(--border);background:none;text-align:left;margin:0}
.csr-row:last-child{border-bottom:0}
.csr-select{border:none;cursor:pointer;color:var(--text);font-size:13px}
.csr-select:hover{background:var(--paper);border-color:transparent}
.csr-name{font-size:13px}

/* ── AG Grid dark theme (old custom.css:529 — --ag-* mapped to TM26 tokens) ──── */
.ag-theme-alpine-dark{
  --ag-background-color:var(--surface);
  --ag-header-background-color:var(--paper);
  --ag-odd-row-background-color:#161923;
  --ag-border-color:var(--border);
  --ag-foreground-color:var(--text);
  --ag-header-foreground-color:var(--subtext);
  --ag-row-hover-color:var(--accent-dim);
  --ag-selected-row-background-color:var(--accent-dim);
  --ag-font-family:var(--font-ui);
  --ag-input-focus-border-color:var(--accent);
}
.ag-theme-alpine-dark .ag-header-cell{cursor:pointer;transition:background-color .15s ease}
.ag-theme-alpine-dark .ag-header-cell:hover{background-color:var(--surface);color:var(--text)}
.ag-theme-alpine-dark .ag-header-cell:hover .ag-header-cell-text{color:var(--text)}
.ag-theme-alpine-dark .ag-row-selected,
.ag-theme-alpine-dark .ag-row-selected:hover{background-color:var(--accent-dim)}

/* ── Header controls (theme picker · bell · hamburger) — old main.py:584 chrome ─ */
.header-controls{display:flex;align-items:center;gap:14px}
.theme-col{display:flex;flex-direction:column;align-items:center;gap:4px}
.theme-col>.lbl{font-family:var(--font-mono);font-size:10px;color:var(--subtext);
  letter-spacing:2px;text-transform:uppercase}

/* Theme picker (old .tm26-theme-picker, custom.css:856) */
.theme-picker{position:relative;display:inline-block}
.theme-trigger{display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 14px;
  background:var(--surface);border:1px solid var(--border);border-radius:8px;cursor:pointer;
  height:36px;transition:border-color .2s;user-select:none}
.theme-trigger:hover{border-color:var(--accent)}
.theme-trigger img{width:28px;height:28px;object-fit:contain;border-radius:4px;display:block}
.theme-chevron{color:var(--subtext);font-size:11px;line-height:1}
.theme-panel{position:absolute;top:calc(100% + 6px);right:0;background:var(--paper);
  border:1px solid var(--border);border-radius:10px;padding:6px;min-width:64px;z-index:1000;
  box-shadow:0 8px 32px rgba(0,0,0,.5);display:none}
.theme-panel.open{display:block}
.theme-option{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;
  cursor:pointer;transition:background .15s;border:none;background:none;width:100%}
.theme-option:hover{background:var(--surface)}
.theme-option img{width:40px;height:40px;object-fit:contain;border-radius:4px}
.theme-option.active{background:var(--accent-dim)}

/* Notification bell (old #notif-bell-btn / #notif-panel, main.py:639) */
.notif-wrap{position:relative;display:flex;align-items:center}
.notif-bell{background:transparent;border:none;cursor:pointer;font-size:18px;padding:4px;position:relative}
.notif-badge{position:absolute;top:0;right:0;background:#e63946;color:#fff;border-radius:50%;
  font-size:9px;min-width:14px;height:14px;display:none;align-items:center;justify-content:center;
  font-weight:700;font-family:var(--font-mono);pointer-events:none;padding:0 3px}
.notif-badge.show{display:flex}
.notif-panel{display:none;position:absolute;top:36px;right:0;z-index:3000;background:var(--paper);
  border:1px solid var(--border);border-radius:10px;width:300px;box-shadow:0 8px 24px rgba(0,0,0,.4);
  padding:12px;max-height:380px;overflow-y:auto}
.notif-panel.open{display:block}
.notif-item{padding:8px 6px;border-bottom:1px solid var(--border);font-size:12.5px}
.notif-item:last-child{border-bottom:0}
.notif-item .t{color:var(--subtext);font-family:var(--font-mono);font-size:10px}
.notif-empty{color:var(--subtext);font-size:12.5px;text-align:center;padding:14px}

/* Hamburger — hidden on desktop, shown ≤768px (old custom.css:921) */
.hamburger{display:none;background:none;border:1px solid var(--border);border-radius:6px;
  color:var(--text);cursor:pointer;padding:0 14px;height:36px;align-items:center;
  justify-content:center;transition:border-color .2s}
.hamburger:hover{border-color:var(--accent)}
.hamburger .bars{display:flex;flex-direction:column;gap:4px}
.hamburger .bars i{width:20px;height:2px;background:var(--text);display:block}

/* ── responsive header ─────────────────────────────────────────────────────── */
@media(max-width:600px){
  .brand{gap:11px}
  .brand-box .tm,.brand-box .yr{font-size:34px}
  .brand-text span{font-size:15px}      /* keep "The Technical Machine" on mobile, sized to fit */
  .brand-text .est{font-size:6px}
  .tabs{overflow-x:auto}
}
/* Mobile usability across ALL tabs — wide data tables scroll horizontally instead
   of overflowing/squishing; dense layouts stack; content padding tightens. */
@media(max-width:760px){
  .content{padding:16px 14px 22px}
  table.data{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}
  .stat-row{gap:10px}
  .stat{min-width:calc(50% - 10px)}
  .tile-grid{grid-template-columns:1fr}
  .trade-form{flex-direction:column;align-items:stretch}
  .trade-form input,.trade-form select,.trade-form button{width:100%}
  .subtabs{overflow-x:auto;flex-wrap:nowrap}
  h1{font-size:22px}
}
/* Mobile: collapse the header controls behind the hamburger (old custom.css:938) */
@media(max-width:768px){
  .hamburger{display:flex}
  /* Menu panel: flush under the header, right-aligned, with a tap-to-close
     backdrop so it reads as a sheet attached to the hamburger, not a floating
     card over the page. */
  .header-controls{position:absolute;top:100%;right:10px;background:var(--paper);
    border:1px solid var(--border);border-top-left-radius:0;border-top-right-radius:0;
    border-radius:0 0 12px 12px;padding:14px 16px 18px;z-index:200;
    flex-direction:column;align-items:stretch;gap:14px;
    width:min(280px,calc(100vw - 20px));
    box-shadow:0 18px 44px rgba(0,0,0,.6);display:none}
  .header-controls.open{display:flex}
  .tm26-header{position:relative}
  .menu-backdrop{position:fixed;inset:0;background:rgba(4,6,10,.55);z-index:150;display:none}
  .menu-backdrop.open{display:block}
  /* Section nav lives in the hamburger menu on mobile, GROUPED (Fantasy /
     Tools) — the grouping is messaging only; the desktop bar stays one row. */
  .tm26-nav{display:none}
  .nav-mobile{display:flex;flex-direction:column;gap:3px;width:100%;
    padding-bottom:12px;margin-bottom:0;border-bottom:1px solid var(--border)}
  .nav-mobile .tab{width:100%;text-align:left;border-radius:6px;border-bottom:none;
    padding:9px 12px;font-size:13px;margin-bottom:0}
  .nav-mobile .tab.active{background:var(--surface);color:var(--accent);
    box-shadow:inset 2px 0 0 var(--accent);border-bottom:none}
  .nav-mob-grp{color:var(--subtext);font-size:9.5px;font-family:var(--font-mono);
    letter-spacing:2px;text-transform:uppercase;margin:10px 0 3px;padding:0 4px}
  .nav-mob-grp:first-child{margin-top:2px}
  .header-controls .theme-col{align-items:flex-start;width:100%}
}

/* ── .tbl-wrap: scroll container for table.data. The mobile rule turns bare
   table.data into display:block (rows shrink-wrap -> the header band stops short
   of the card edge); inside a wrapper the table stays a real table and the
   WRAPPER scrolls. ─────────────────────────────────────────────────────────── */
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
.tbl-wrap table.data{display:table;width:100%;white-space:nowrap}

/* ── Draft pool loading overlay: any board request lights it (hx-indicator on
   #draft-board). htmx adds .htmx-request to the indicator while in flight. */
.pool-wrap{position:relative}
/* Reworked (owner 2026-09-04): the old overlay dimmed + blurred the whole pool
   on EVERY board request — background refetches (someone else's pick, the
   autopick daemon's checks, SSE syncs) made the room feel broken. Now: a small
   fixed pill, centered in the VIEWPORT regardless of scroll, pointer-events:
   none, and revealed only after 350ms in flight — a fast swap shows nothing
   at all. Content underneath stays fully visible and interactive. */
.pool-loading{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:950;
  pointer-events:none;display:flex;align-items:center;
  background:var(--paper);border:1px solid var(--border);border-radius:99px;
  padding:8px 18px;font-family:var(--font-mono);font-size:11px;color:var(--accent);
  letter-spacing:3px;box-shadow:0 8px 30px rgba(0,0,0,.5);
  opacity:0;visibility:hidden;transition:opacity .18s ease, visibility 0s linear .3s}
.pool-loading.htmx-request{opacity:1;visibility:visible;
  transition-delay:.35s,.35s}

/* ── BINDER SPREAD: two 3x3 pages side by side from laptop width up (owner
   2026-09-04 — one page across the whole content column made desktop cards
   huge). Mobile keeps ONE page per row, running vertically. Pages already cap
   at 540px each, so a pair fits the 1180px content column exactly.
   Every binder surface: My Team / opponent rosters (#roster-binder), the
   draft pool (#pool-grid) and the Pokédex challenge (#rb-book) — all three
   build the same .rb-page blocks, so one rule covers them.
   Row gap stays 0 — .rb-page carries its own margin-bottom. */
#roster-binder, #pool-grid, #rb-book{display:grid;grid-template-columns:1fr;
  gap:0 16px;align-items:start;margin-top:4px}
@media (min-width:940px){
  #roster-binder, #pool-grid, #rb-book{grid-template-columns:1fr 1fr}
}
/* Draft pool pockets: same binder look, a touch tighter than a roster pocket. */
#pool-grid .rb-pocket{padding:6px 5px 8px;gap:3px}
#pool-grid .sfoil{width:100%}
.dp-nm{font-size:12.5px;line-height:1.25;max-width:100%;overflow:hidden;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;word-break:break-word;min-height:2.5em}
.dp-dim{opacity:.45}
.dp-why{font-family:var(--font-mono);font-size:9px;color:#ff6b6b;line-height:1.2}
.dp-open{cursor:pointer}

/* ── Full-page navigation loading overlay (Pokédex gen/binder/pool tabs and
   any a.rt-btn nav) — same look as the draft pool-loading, fixed-position. */
.nav-loading{display:none;position:fixed;inset:0;z-index:2000;pointer-events:none;
  background:rgba(10,12,18,.55);backdrop-filter:blur(1px);
  align-items:flex-start;justify-content:center;padding-top:140px;
  font-family:var(--font-mono);font-size:12px;color:var(--accent);letter-spacing:3px}
.nav-loading.on{display:flex}

/* ── Horizontal chip-row scroll hints: arrows fade in/out at each edge while
   more content exists in that direction (JS toggles .on via scroll position). */
.chip-scroll-wrap{position:relative}
.chip-scroll-wrap .csw{position:absolute;top:0;bottom:3px;width:44px;z-index:4;display:none;
  align-items:center;pointer-events:none;font-size:30px;line-height:0;color:var(--accent);font-weight:700;
  padding-bottom:2px}
/* desktop (fine pointer): the arrows are clickable pagers; on touch they stay
   transparent so they never steal taps from chips under the gradient */
@media (hover:hover) and (pointer:fine){
  .chip-scroll-wrap .csw{pointer-events:auto;cursor:pointer}
}
.chip-scroll-wrap .csw.on{display:flex}
.chip-scroll-wrap .csw-l{left:0;justify-content:flex-start;padding-left:2px;
  background:linear-gradient(90deg,var(--paper) 25%,transparent)}
.chip-scroll-wrap .csw-r{right:0;justify-content:flex-end;padding-right:2px;
  background:linear-gradient(270deg,var(--paper) 25%,transparent)}

/* ── Draft-room action toast: fixed so pick rejections/confirmations are seen
   from anywhere in the scroll; fades out after 4s (swap re-creates it). */
.draft-toast{position:fixed;top:14px;left:50%;transform:translateX(-50%);z-index:1100;
  max-width:min(480px,92vw);box-shadow:0 10px 30px rgba(0,0,0,.55);pointer-events:none;
  animation:toastfade 4.5s ease forwards}
@keyframes toastfade{0%{opacity:0;transform:translate(-50%,-8px)}6%{opacity:1;transform:translate(-50%,0)}
  82%{opacity:1}100%{opacity:0;visibility:hidden}}
@media (prefers-reduced-motion: reduce){.draft-toast{animation:none}}

/* Swap-only free agency: buy-first select-sell mode. Ineligible roster cards
   (wrong slot, or unaffordable even with the sale) are dimmed + X'd. */
.swap-off{opacity:.38;filter:grayscale(.75)}
.swap-x{color:#ff6b6b;font-family:var(--font-mono);font-size:11px;white-space:nowrap;flex-shrink:0}

/* FA / card-picker table on narrow screens: the ACTION column is pinned right
   so Buy is never clipped; everything else scrolls horizontally under it. */
.bx-table td:last-child, .bx-table th:last-child{
  position:sticky; right:0; z-index:2; background:var(--paper);
  box-shadow:-8px 0 10px -8px rgba(0,0,0,.75); width:64px}
.bx-table thead th:last-child{background:var(--surface); z-index:3}
@media (max-width:760px){
  .bx-table{table-layout:auto; min-width:560px}
  .pool-table .bx-table th:nth-child(1){min-width:148px}
  .bx-table th:nth-child(1){width:auto;min-width:190px}
  .bx-table th:nth-child(2){width:auto;min-width:92px}
  .bx-table th:nth-child(3){width:auto;min-width:96px}
  .bx-table th:nth-child(4){width:auto;min-width:64px}
  .bx-pricecell{padding-right:12px}
}



/* Reverse Holofoil marker: TCGPlayer serves one photo per product, so a
   reverse looks identical to the normal printing. A faint cool glow AROUND
   the card edge distinguishes it without touching the artwork. Class goes
   straight on the <img> (no wrapper, no overlay, no animation). */
.rev-glow{box-shadow:0 0 0 1px rgba(150,220,255,.75), 0 0 10px 2px rgba(110,195,255,.45)}

/* SCROLL-DRIVEN glare (mobile-first): phones have no hover, so the light
   angle comes from the card's position in the viewport — a card catches the
   light as it scrolls up the screen, which is exactly how a foil behaves when
   you tilt it. --p is 0 (entering at the bottom) → 1 (leaving at the top),
   written by the scroll handler; only REVERSE HOLOS get it. */
.sfoil{position:relative;display:block;line-height:0;border-radius:6px;
  overflow:hidden;isolation:isolate}
.sfoil > img{display:block;width:100%}
.sfoil::after{content:'';position:absolute;inset:0;pointer-events:none;z-index:2;
  mix-blend-mode:overlay;filter:brightness(1.05) contrast(1.25) saturate(1.3);
  background-image:
    linear-gradient(100deg, transparent 38%,
      hsla(195,100%,97%,.78) 47%, hsla(205,85%,90%,.42) 51%,
      hsla(190,100%,97%,.30) 55%, transparent 64%),
    repeating-linear-gradient(102deg,
      rgba(255,120,115,.10) 0 7px, rgba(255,235,100,.09) 7px 14px,
      rgba(150,255,120,.09) 14px 21px, rgba(120,240,255,.09) 21px 28px,
      rgba(140,150,255,.10) 28px 35px);
  background-size:300% 300%, auto;
  background-repeat:no-repeat, repeat;
  /* the BAND travels corner-to-corner as the card crosses the viewport */
  background-position:calc(var(--p,.5) * 100%) calc(var(--p,.5) * 100%),
                      calc(var(--p,.5) * -60px) 0}
@media (prefers-reduced-motion: reduce){
  .sfoil::after{background-image:none}
}

/* HOLOFOIL sparkle-glare (scroll-driven, same --p as .sfoil). Holos never get
   a real photo — we only harvest reverse-holo photographs — so CSS is the only
   signal here. LIGHT ONLY (mix-blend-mode:screen, no tint layer): a warm glare
   band plus two drifting sparkle fields, so the art stays crisp. */
/* Scroll-driven glare BAND only. (Sparkle dot layers were tried and cut —
   at card size they read as dust/noise on the artwork, not foil.) */
/* PERF: the sweep is TRANSFORM-driven (GPU-composited). Moving
   background-position invalidated paint on a 300% gradient layer every scroll
   frame — that was the mobile choppiness. */
.sfoil.spark::after{
  inset:auto;left:-100%;top:-100%;width:300%;height:300%;
  mix-blend-mode:screen;filter:brightness(1.04) contrast(1.1);
  background-size:100% 100%;background-repeat:no-repeat;will-change:transform;
  transform:translate3d(calc((.5 - var(--p,.5)) * 66%), calc((.5 - var(--p,.5)) * 66%), 0)}
/* COSMOS ("Cosmo") holo — galaxy foil star twinkle. DISTINCT from the reverse
   holo, which gets the sweeping light band; a Holofoil gets STARS ONLY.
   Everything is MOTION-TRIGGERED off scroll: nothing animates while the page
   is still. The scroll handler turns position into a LOOPING triangle wave
   (--a / --b, inverses of each other, ~3.5 cycles per screen-height), so the
   two star fields wink in and out repeatedly as you scroll rather than doing
   one slow ramp per pass. They also drift in opposite directions (--p).
   Each sparkle is a real star: bright core + two crossed ellipse flares (the
   4-point glint). Placed irregularly — a repeating tile reads as dust, and
   sub-pixel dots are invisible at card size (both tried, both cut). */
.sfoil.holo::before, .sfoil.holo::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  mix-blend-mode:screen;background-repeat:no-repeat;animation:none;
  will-change:opacity,transform}
/* field A — brightens as the card rises up the viewport */
.sfoil.holo::before{z-index:1;
  opacity:var(--a, .5);
  transform:translate3d(calc(var(--p, .5) * 3px), calc(var(--p, .5) * -4px), 0);
  background-image:
    radial-gradient(ellipse 9px 1.3px at 19% 16%, rgba(255,255,255,.95), transparent 72%),
    radial-gradient(ellipse 1.3px 9px at 19% 16%, rgba(255,255,255,.95), transparent 72%),
    radial-gradient(circle 2.4px at 19% 16%, rgba(255,252,235,.8), transparent 75%),
    radial-gradient(ellipse 12px 1.6px at 72% 37%, rgba(255,255,255,1), transparent 70%),
    radial-gradient(ellipse 1.6px 12px at 72% 37%, rgba(255,255,255,1), transparent 70%),
    radial-gradient(circle 3px at 72% 37%, rgba(255,250,225,.85), transparent 72%),
    radial-gradient(ellipse 8px 1.2px at 38% 71%, rgba(255,255,255,.9), transparent 72%),
    radial-gradient(ellipse 1.2px 8px at 38% 71%, rgba(255,255,255,.9), transparent 72%),
    radial-gradient(ellipse 10px 1.4px at 86% 82%, rgba(255,255,255,.92), transparent 71%),
    radial-gradient(ellipse 1.4px 10px at 86% 82%, rgba(255,255,255,.92), transparent 71%),
    radial-gradient(ellipse 7px 1.1px at 8% 41%, rgba(255,255,255,.85), transparent 73%),
    radial-gradient(ellipse 1.1px 7px at 8% 41%, rgba(255,255,255,.85), transparent 73%),
    radial-gradient(ellipse 9px 1.3px at 57% 8%, rgba(255,255,255,.9), transparent 72%),
    radial-gradient(ellipse 1.3px 9px at 57% 8%, rgba(255,255,255,.9), transparent 72%),
    radial-gradient(ellipse 8px 1.2px at 29% 93%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 1.2px 8px at 29% 93%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 7px 1.1px at 93% 61%, rgba(255,255,255,.82), transparent 73%),
    radial-gradient(ellipse 1.1px 7px at 93% 61%, rgba(255,255,255,.82), transparent 73%)}
/* field B — the inverse: brightest as the card enters, fading as it leaves */
.sfoil.holo::after{z-index:2;
  opacity:var(--b, .5);
  transform:translate3d(calc(var(--p, .5) * -4px), calc(var(--p, .5) * 3px), 0);
  background-image:
    radial-gradient(ellipse 10px 1.4px at 51% 24%, rgba(255,255,255,.95), transparent 71%),
    radial-gradient(ellipse 1.4px 10px at 51% 24%, rgba(255,255,255,.95), transparent 71%),
    radial-gradient(circle 2.6px at 51% 24%, rgba(255,250,225,.8), transparent 74%),
    radial-gradient(ellipse 8px 1.2px at 13% 54%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 1.2px 8px at 13% 54%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 11px 1.5px at 64% 91%, rgba(255,255,255,.9), transparent 71%),
    radial-gradient(ellipse 1.5px 11px at 64% 91%, rgba(255,255,255,.9), transparent 71%),
    radial-gradient(ellipse 9px 1.3px at 34% 33%, rgba(255,255,255,.92), transparent 72%),
    radial-gradient(ellipse 1.3px 9px at 34% 33%, rgba(255,255,255,.92), transparent 72%),
    radial-gradient(ellipse 7px 1.1px at 79% 15%, rgba(255,255,255,.85), transparent 73%),
    radial-gradient(ellipse 1.1px 7px at 79% 15%, rgba(255,255,255,.85), transparent 73%),
    radial-gradient(ellipse 8px 1.2px at 22% 79%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 1.2px 8px at 22% 79%, rgba(255,255,255,.88), transparent 72%),
    radial-gradient(ellipse 10px 1.4px at 88% 47%, rgba(255,255,255,.9), transparent 71%),
    radial-gradient(ellipse 1.4px 10px at 88% 47%, rgba(255,255,255,.9), transparent 71%),
    radial-gradient(ellipse 7px 1.1px at 46% 57%, rgba(255,255,255,.8), transparent 73%),
    radial-gradient(ellipse 1.1px 7px at 46% 57%, rgba(255,255,255,.8), transparent 73%)}
@media (prefers-reduced-motion: reduce){
  .sfoil.holo::before{opacity:.5} .sfoil.holo::after{opacity:.5}
}
/* cool — Reverse Holofoil, incl. cards showing a real foil photograph */
.sfoil.spark::after{
  background-image:linear-gradient(100deg, transparent 44.5%,
    rgba(240,252,255,.45) 47.8%, rgba(190,235,255,.26) 49.2%, transparent 53%)}

/* Reverse-holo GLARE — the real thing, on the one surface big enough for it:
   the roster card modal. Technique follows simeydotme/pokemon-cards-css: a
   specular hot spot that TRACKS THE POINTER (that's what sells 'foil'; a
   constant animated film just looks like a filter), composed with overlay /
   color-dodge blends + brightness/contrast/saturate filters, plus a slight
   3D tilt so the highlight moves across the surface as you move. Applies only
   when .rb-mimgwrap carries a printing class. */
.rb-mimgwrap{position:relative;display:inline-block;line-height:0;
  border-radius:10px;overflow:hidden;isolation:isolate;
  transform:perspective(700px) rotateX(var(--ry,0deg)) rotateY(var(--rx,0deg));
  transition:transform .18s ease-out}
.rb-mimgwrap img{display:block;width:100%;border-radius:10px}
.rb-mimgwrap .glare, .rb-mimgwrap .shine{position:absolute;inset:0;pointer-events:none;
  opacity:0;transition:opacity .2s ease}
.rb-mimgwrap.foil .glare, .rb-mimgwrap.foil .shine{opacity:1}
/* specular hot spot — follows the pointer */
.rb-mimgwrap .glare{z-index:2;mix-blend-mode:overlay;
  filter:brightness(1.02) contrast(1.3);
  background-image:linear-gradient(100deg, transparent 36%,
    hsla(195,100%,97%,.80) 46%, hsla(205,85%,92%,.45) 50%,
    hsla(190,100%,97%,.30) 55%, transparent 65%);
  background-size:300% 300%;background-repeat:no-repeat;
  background-position:var(--mx,50%) var(--my,50%)}
/* rainbow sheen that shifts with the same pointer position */
.rb-mimgwrap.rev .shine{z-index:1;mix-blend-mode:color-dodge;
  filter:brightness(.9) contrast(1.5) saturate(1.4);
  background:
    repeating-linear-gradient(105deg,
      rgba(255,119,115,.10) 6%, rgba(255,237,95,.09) 12%, rgba(168,255,95,.09) 18%,
      rgba(131,255,247,.09) 24%, rgba(120,148,255,.10) 30%),
    repeating-linear-gradient(0deg, rgba(0,0,0,.14) 0 2px, transparent 2px 4px);
  background-position:calc(var(--mx,50%) * -.4) calc(var(--my,50%) * -.4), 0 0;
  background-size:200% 200%, auto}
@media (prefers-reduced-motion: reduce){ .rb-mimgwrap{transition:none;transform:none} }

/* ag-Grid wrapText: the alpine theme sets nowrap+ellipsis on .ag-cell-value, so
   columns declared wrapText still truncated ("Uncom…" for Uncommon). Let those
   cells wrap instead — the 54px row height holds two lines comfortably. */
.ag-theme-alpine-dark .ag-cell-wrap-text,
.ag-theme-alpine-dark .ag-cell-wrap-text .ag-cell-value{
  white-space:normal; text-overflow:clip; line-height:1.3;
}
