/* Dynamic width. The gallery is grids, boards and cards -- none of which is
   prose, and all of which show more of themselves the more room they get --
   so it takes the canvas rather than a fixed reading column, with one gutter
   variable shared by the controls row, the view and the footer stamp so the
   three stay in line at every width. Prose inside the gallery caps itself
   (.groupnote); the docs and research pages are untouched and keep the
   reading measure assets/style.css gives them. */
.gallery-page { --pad: clamp(1rem, 2vw, 3rem); }
.gallery-page main#view { max-width: none; margin: 0 auto;
                          padding: 1rem var(--pad) 4rem; }
#app.loading #controls, #app.loading #view { display: none; }
#boot { padding: 3rem 1.5rem; color: var(--muted); }
#app:not(.loading) #boot { display: none; }

#controls {
  display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center;
  max-width: none; margin: 0 auto; padding: 0.9rem var(--pad) 0;
}
#tabs a {
  font-size: 0.95rem; font-weight: 600; color: var(--muted); text-decoration: none;
  padding: 0.25rem 0.7rem; border-radius: 6px;
}
#tabs a.on { color: var(--accent); background: var(--code-bg); }
#controls input[type=search] {
  font: inherit; font-size: 0.88rem; padding: 0.3rem 0.6rem; color: var(--fg);
  background: var(--panel); border: 1px solid var(--rule); border-radius: 6px;
  flex: 0 1 16rem;
}
#togglewrap, #ghostwrap, #shopartwrap, #arenawrap { font-size: 0.82rem; color: var(--muted);
              display: flex; gap: 0.35rem; align-items: center; cursor: pointer; }
/* display:flex beats the UA's [hidden] rule, so restate it: the ability-icons,
   arena and sort controls only appear on item-tile routes (see render()),
   and the ghost-abilities toggle only on the hero grid. */
#shopartwrap[hidden] { display: none; }
#arenawrap[hidden] { display: none; }
#ghostwrap[hidden] { display: none; }
#sortwrap, #groupwrap, #catwrap { font-size: 0.82rem; color: var(--muted);
            display: flex; gap: 0.35rem; align-items: center; }
#sortwrap[hidden] { display: none; }
#groupwrap[hidden] { display: none; }
#catwrap[hidden] { display: none; }
#sortsel, #groupsel, #catsel {
  font: inherit; font-size: 0.82rem; padding: 0.25rem 0.5rem; color: var(--fg);
  background: var(--panel); border: 1px solid var(--rule); border-radius: 6px;
}
/* Grouped layouts disable the sort select outright (attribute + this dimming)
   rather than silently ignoring it; render() drives both together. */
#sortwrap.dim { opacity: 0.45; }
#summary { margin-left: auto; color: var(--muted); font-size: 0.8rem; }

:root {
  --slot-weapon: #c98a3d; --slot-vitality: #71a84e; --slot-spirit: #a476d9;
}

/* Hero grid: portrait-style boxes, sized to hold their own next to the shop
   tiles on the items page. Sorted by complexity, shown as the diamond row. */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
        gap: 0.6rem; margin: 0.75rem 0 1.5rem; }
.tile {
  display: flex; flex-direction: column; align-items: center; gap: 0.45rem;
  padding: 0.9rem 0.6rem 0.75rem; text-align: center;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 10px;
  color: var(--fg); text-decoration: none; font-size: 0.9rem; min-width: 0;
}
.tile:hover { border-color: var(--accent); }
.tile img { width: 60px; height: 60px; object-fit: contain; border-radius: 8px;
            background: var(--code-bg); flex: 0 0 auto; }
.tile-noimg { width: 60px; height: 60px; border-radius: 8px; flex: 0 0 auto;
              background: var(--code-bg); border: 1px dashed var(--rule); }
.detail .art .tile-noimg { display: block; width: 13rem; height: 13rem; }
.tile .nm { overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.tile .cx { color: var(--muted); font-size: 0.66rem; letter-spacing: 0.18em; }
.tile.off { opacity: 0.45; }
.badge {
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.08rem 0.4rem; border-radius: 999px; background: var(--warn-bg);
  color: var(--warn); font-weight: 700; flex: 0 0 auto;
}

/* Ghost ability rows ("show abilities" on the hero grid): one row per hero,
   the hero's own grid tile as the anchor, slim grey ability cards beside it.
   Hover lifts the grayscale and pops the full kit card. */
.ghostrow { display: flex; gap: 0.7rem; align-items: center;
            margin: 0.4rem 0; }
.ghostrow .tile { flex: 0 0 8.5rem; }
.ghostcards { flex: 1; min-width: 0; display: grid;
              grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
              gap: 0.4rem; }
.ghostcard { display: flex; align-items: center; gap: 0.5rem; min-width: 0;
             padding: 0.35rem 0.5rem; border-radius: 8px;
             background: var(--panel); border: 1px solid var(--rule);
             text-decoration: none; color: var(--muted);
             filter: grayscale(1); opacity: 0.6;
             transition: filter 0.12s ease, opacity 0.12s ease; }
.ghostcard .gc-icon { width: 34px; height: 34px; flex: 0 0 auto;
                      object-fit: contain; border-radius: 6px;
                      background: #12151a; }
/* Every published ability carries an icon at this build; keep the no-image
   fallback row-sized if a future build drops one. */
.ghostcard .tile-noimg { width: 34px; height: 34px; }
.gc-name { flex: 1 1 auto; min-width: 0; font-size: 0.82rem;
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gc-type { flex: 0 0 auto; font-size: 0.6rem; text-transform: uppercase;
           letter-spacing: 0.06em; border-left: 3px solid var(--gc-accent);
           padding-left: 0.4rem; }
.ghostcard:hover, .ghostcard:focus-visible {
  filter: none; opacity: 1; border-color: var(--gc-accent); color: var(--fg);
}

/* Item shop grid: rows of kit item icons (.ai-item). The tile's look lives in
   ability-card.css; only the wrapping layout and the link shell belong here.
   Grid tiles are 96px, comparison/effect rows 80px (set in gallery.js). */
.shopgrid { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 0.6rem 0 1.4rem;
            align-items: flex-start; }
.shopgrid-row { gap: 0.5rem; }
.shoplink { display: block; flex: 0 0 auto; color: inherit;
            text-decoration: none; }
.shoplink:hover .ai-item, .shoplink:focus-visible .ai-item {
  outline: 2px solid var(--ai-accent); outline-offset: 1px;
}
/* Disabled items: dim the kit tile and say why from the gallery side -- the
   kit's markup and CSS stay untouched. */
.shoplink.off .ai-item { opacity: 0.45; }
/* The kit's gun preset re-lightens the art well even on dark tiles; the
   ability icons are white silhouettes, so force the dark well everywhere.
   The default shop art is opaque and fills the well (object-fit: cover), so
   the well colour only shows behind silhouettes and art-less tiles. */
.shoplink .ai-item.ai--dark { --ai-art-bg: #12151a; }
.offcap { display: block; margin-top: 0.15rem; text-align: center;
          font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.08em;
          color: var(--warn); }

h2.slot { border: 0; padding: 1rem 0 0; font-size: 1.1rem; }
/* Group-by section headers: the slot headers' shape without a slot colour --
   grouped sections span all three categories, the tiles keep the slot tint. */
h2.group { border: 0; padding: 1rem 0 0; font-size: 1.1rem; }
h2.slot.weapon { color: var(--slot-weapon); }
h2.slot.vitality { color: var(--slot-vitality); }
h2.slot.spirit { color: var(--slot-spirit); }
h3.tier { margin: 0.8rem 0 0.2rem; font-size: 0.78rem; color: var(--muted);
          text-transform: uppercase; letter-spacing: 0.06em; }

.back { display: inline-block; margin: 0.5rem 0 1rem; color: var(--link);
        text-decoration: none; font-size: 0.85rem; }
.detail { display: flex; gap: 1.5rem; flex-wrap: wrap; }
.detail .art img { width: 13rem; max-width: 40vw; border-radius: 10px;
                   background: var(--code-bg); }
.detail .body { flex: 1 1 24rem; min-width: 0; }
.metaline { color: var(--muted); font-size: 0.85rem; margin: 0.2rem 0 1rem; }
/* The stat-comparison soul-threshold selector; the select shares the
   sort/group controls' styling. */
.threshrow { display: flex; gap: 0.35rem; align-items: center;
             color: var(--muted); font-size: 0.82rem; margin: 0.5rem 0 0.3rem; }
.threshrow select {
  font: inherit; font-size: 0.82rem; padding: 0.25rem 0.5rem; color: var(--fg);
  background: var(--panel); border: 1px solid var(--rule); border-radius: 6px;
}
.cmpbtn { display: inline-block; margin-top: 0.6rem; padding: 0.35rem 0.9rem;
  background: var(--code-bg); border: 1px solid var(--rule); border-radius: 6px;
  color: var(--link); text-decoration: none; font-size: 0.85rem; font-weight: 600; }
.cmpbtn:hover, .cmpbtn:focus-visible { border-color: var(--accent); }

/* Per-hero progression chart on the stat-comparison page. Text wears text
   tokens; series color lives only on the strokes. The invisible .sc-hit
   twin widens each line's hover/click target beyond the 2px mark. */
.statchart { margin: 0.4rem 0 1.2rem; background: #171c22;
             border: 1px solid var(--rule); border-radius: 8px;
             padding: 0.6rem 0.6rem 0.1rem; }
.statchart svg { width: 100%; height: auto; display: block; }
.sc-line { fill: none; stroke-width: 2; opacity: 0.38; }
.sc-hit { fill: none; stroke: transparent; stroke-width: 12; }
.statchart a:hover .sc-line, .statchart a:focus-visible .sc-line {
  opacity: 1; stroke-width: 3; }
.sc-line.me { opacity: 1; stroke-width: 3.5; }
.sc-grid { stroke: rgba(255, 255, 255, 0.08); }
.sc-marker { stroke: rgba(255, 255, 255, 0.35); stroke-dasharray: 3 3; }
.sc-tick { fill: var(--muted); font-size: 10px; }
.sc-melabel { fill: var(--fg); font-size: 11px; font-weight: 600; }
.sc-note { color: var(--muted); font-size: 0.72rem; margin: 0.15rem 0 0.45rem; }

.statrows { margin: 0 0 1rem; display: flex; flex-direction: column;
            gap: 0.25rem; font-size: 0.88rem; max-width: 26rem; }
.statrow { display: grid; grid-template-columns: 4rem 1fr auto;
           gap: 0 0.9rem; align-items: baseline;
           color: inherit; text-decoration: none; border-radius: 5px; }
.statrow .v { font-variant-numeric: tabular-nums; font-weight: 600; }
.statrow .l { color: var(--muted); }
.statrow .cmp { color: var(--muted); font-size: 0.72rem; visibility: hidden; }
.statrow:hover .cmp, .statrow:focus-visible .cmp { visibility: visible;
                                                   color: var(--link); }
.statrow:hover .l { color: var(--link); }

/* Roster comparison: one proportional bar per hero, viewed hero highlighted. */
.statbars { display: flex; flex-direction: column; gap: 0.3rem;
            max-width: 42rem; margin: 1rem 0 1.5rem; }
.statbar { display: grid; grid-template-columns: 9rem 1fr 3.5rem;
           gap: 0.6rem; align-items: center; font-size: 0.85rem;
           color: var(--fg); text-decoration: none; }
.statbar .sb-name { text-align: right; color: var(--muted); overflow: hidden;
                    text-overflow: ellipsis; white-space: nowrap; }
.statbar .sb-track { background: var(--code-bg); border-radius: 4px;
                     height: 0.8rem; overflow: hidden; }
.statbar .sb-fill { display: block; height: 100%; border-radius: 4px;
                    background: var(--accent); opacity: 0.45; }
.statbar.me .sb-fill { opacity: 1; }
.statbar.me .sb-name { color: var(--fg); font-weight: 700; }
.statbar:hover .sb-name, .statbar:focus-visible .sb-name { color: var(--link); }
.statbar .sb-val { font-variant-numeric: tabular-nums; }
h2.armshead { border: 0; padding: 0.8rem 0 0; font-size: 1rem; }

/* Power increases: the hero's automatic soul-threshold boosts, rendered with
   the kit's progression table below the base stats. The kit styles .ac-prog
   for its dark card body, so the block brings its own dark panel and accent;
   type is sized down because these rows carry eight columns, not four. The
   row override MUST keep the kit's repeat(var(--ac-prog-n)) column count --
   a fixed template here is what broke the table into wrapped pairs. */
.pi-block { margin: 0 0 1.2rem; max-width: 48rem; }
.pi-block .ac-prog { --ac-accent: #5b8fae; margin-top: 0.4rem;
                     background: #171c22; border: 1px solid var(--rule); }
.pi-block .ac-prog-col { font-size: 10px; letter-spacing: 0.06em; }
.pi-block .ac-prog-label { font-size: 13px; }
.pi-block .ac-prog-step { font-size: 13px; }
.pi-block .ac-prog-row { grid-template-columns: 7rem repeat(var(--ac-prog-n), 1fr);
                         padding: 4px 0; }
.pi-note { color: var(--muted); font-size: 0.78rem; margin: 0.3rem 0 0; }

/* Game highlight spans inside ability-card descriptions. The card body is dark
   regardless of the site theme, so these colors are fixed, not theme variables. */
.ac-desc .highlight { color: #fff; font-weight: 700; }
.ac-desc .attr { color: #8fc4e0; font-weight: 600; }
.ac-desc .highlight_spirit { color: #cdb1ee; font-weight: 600; }
.ac-desc .highlight_weapon { color: #e8b06a; font-weight: 600; }
.ac-desc .highlight_courage, .ac-desc .highlight_special { color: #a3d47e; font-weight: 600; }
.ac-desc .diminish { color: #95a3af; font-size: 0.9em; }
.ac-desc .kbd {
  font-family: ui-monospace, Consolas, monospace; font-size: 0.78em;
  background: rgba(0, 0, 0, .35); border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 4px; padding: 0.05em 0.35em;
}
/* Inline stat icons: substituted for the game's AbilityPropertyIcon panels at
   build time (render_desc / STAT_ICONS), and leading item stat rows on the
   detail page (itemCardData markers -> subStatIcons). Sized to the text line,
   colors baked in from the game's own wash-color variables. The second class
   names the stat (prop_tech_damage, ...) for targeting; the sizing is shared. */
.statico { height: 1em; width: auto; vertical-align: middle;
           margin: 0 0.15em 0.1em; }
/* Keep an icon-led stat value on one line: the kit's .ac-detail flexbox lets
   the val span wrap between the icon and its number when the pair is wide
   ("[shield] +4.5%"); the values are short, so nowrap cannot overflow the
   panel. Gallery-side override -- the kit's own files stay untouched. */
.itemcard .ac-detail-val { white-space: nowrap; }

/* Ability cards: centered wrapping rows below the hero's icon + details row.
   520px lets several cards share a row at desktop widths; narrower screens
   wrap to one centered card per row. Cards in the same row stretch to the
   tallest (flex line stretch); the card is a column so its dark body fills
   the extra height, with the stat panel pinned to the bottom edge. */
.abilities { display: flex; flex-wrap: wrap; justify-content: center;
             gap: 1rem; margin-top: 1.5rem; }
.abilities .ac-card { width: 520px; max-width: 100%;
                      display: flex; flex-direction: column; }
.abilities .ac-body { flex: 1; display: flex; flex-direction: column; gap: 18px; }
.abilities .ac-body .ac-note { margin-top: 0; }
.abilities .ac-body .ac-panel { margin-top: auto; }

/* Ability tier ladders: a static reference site has no player state, so the
   kit's 'locked' dimming (a shop affordance) is suppressed -- upgrade rows are
   the content here. The base row keeps its 'owned' accent highlight. */
.gallery-page .ac-tier--locked { opacity: 1; }

/* Derived multi-bonus tier rows are handed to the kit as a list of fragments
   (ability_tiers), so "+3.5s Duration +3m Width +1m Height" arrives as three
   boxed .ac-tier-line columns rather than one run-on blob -- the kit styles
   them; nothing is needed here. Loc-sourced tier descs are prose and stay a
   single unboxed string. */
.itemcard { margin-top: 0.5rem; }
/* The buy panel: the kit's .ac-shell docks a fixed 208px .ac-side to the
   card's right, and the panel never flex-shrinks -- narrow viewports would
   squeeze the card into the leftover sliver. Two-stage reflow, gallery-side
   override (the kit's own files stay untouched):
   - in between full width and the split, the card may shrink under its
     560px design width (min-width: 0 lifts the flex min-content floor, so
     the pair can never force a sideways page scroll);
   - at the flowchart's own 40rem breakpoint the shell becomes a column and
     the grey panel drops below the card at full card width. */
.itemcard .ac-shell > .ac-card { min-width: 0; }
@media (max-width: 40rem) {
  .itemcard .ac-shell { flex-direction: column; align-items: stretch; }
  .itemcard .ac-side { width: auto; }
  /* The hero page's power table is the one nine-column .ac-prog; its 1fr
     tracks bottom out above a phone width and the header's soul values
     spill past the page edge. Same scrolling recipe the kit's board uses:
     the panel scrolls inside itself (max-content rows so the row rules span
     the scrolled width) and the page body never scrolls sideways. */
  .pi-block .ac-prog { overflow-x: auto; }
  .pi-block .ac-prog-row { width: max-content; min-width: 100%; }
}

/* Build paths, everywhere: the kit's item board (.ib-*) lays items out in
   tier columns and draws one measured SVG arrow per component relation.
   Three surfaces share it, so a build path reads the same wherever it is
   met -- the item page's chart, the hover preview inside .ac-pop, and the
   progression page's per-section boards. The board is a dark pane by design,
   like the card, which is why none of these overrides reach for the page's
   theme variables. Geometry (arrow measuring, drag-to-pan, the redraw on
   resize) is the kit's mountItemBoardArrows; the gallery only mounts it.

   The kit writes each node as a plain <div>, so the gallery drops a stretched
   anchor inside (boardLinks) rather than restructuring the grid: nodes keep a
   real href -- middle-click, open-in-new-tab and keyboard focus all work --
   and the hover trigger stays on the node the kit put data-ability on. */
.ib-node { position: relative; }
.ib-hit { position: absolute; inset: 0; z-index: 3; border-radius: 8px; }
.ib-hit:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
/* The kit's gun preset re-lightens the art well; the extracted icons are
   white silhouettes, so force the dark well here as the shop tiles do. */
.ib-node .ai-item.ai--dark { --ai-art-bg: #12151a; }

/* Node states. The kit ships owned / next / locked for a player's build; a
   static reference site has no player, so the gallery spends that vocabulary
   on its own meanings. `me` and `off` are its own strings, which the kit does
   not recognise and therefore leaves the connectors neutral.

   `locked` is the kit's, deliberately reused: a chain member carried into a
   section it does not belong to -- most often because the line crosses shop
   categories. It must stay READABLE, because being able to see where the line
   goes is the whole reason it is drawn, so the kit's heavy dimming is undone
   here and replaced with a dashed outline. The kit's matching dashed
   connector, restored to a visible contrast, is then exactly the "this link
   leaves the section" cue -- and because the patched kit takes a link's state
   from both of its ends, the cue shows whichever way the arrow points. The
   outline is never the only signal: the section heading counts only its own
   matches. */
.ib-node--me { box-shadow: 0 0 0 2px var(--accent),
                           0 8px 22px rgba(0, 0, 0, .5); }
.ib-node--off .ai-item { opacity: 0.45; }
.ib-node--locked { opacity: 0.66; filter: none;
                   outline: 1px dashed rgba(226, 236, 244, .45);
                   outline-offset: 2px; border-radius: 8px; }
.ib-node--locked:hover, .ib-node--locked:focus-within { opacity: 1; }
.ib-links path.is-locked { stroke: rgba(226, 236, 244, .46);
                           stroke-dasharray: 6 5; }
.ib-links polygon.is-locked { fill: rgba(226, 236, 244, .46); }

/* Item page: the chart sits under the card, at the page's own width. */
.flowwrap { margin: 0.4rem 0 0.6rem; }

/* Hover preview: the same board, chip-sized, appended below the kit's card
   by appendFlowPop (gallery-side augment; the kit file is untouched). The pop
   shrinks to fit, and .ib-board is an overflow container that would collapse
   in it, so the width is pinned to the content and capped. */
.ac-pop .flowpop { margin-top: 8px; }
.ac-pop .flowcap { font-size: 10px; font-weight: 700;
                   text-transform: uppercase; letter-spacing: 0.08em;
                   color: #95a3af; margin: 0 0 3px; }
.ac-pop .ib-board { width: max-content; max-width: 460px;
                    --ib-gap-x: 44px; --ib-gap-y: 10px; }
.ac-pop .ib-inner { padding: 10px 14px 16px; }

/* Progression page: one board per section, each its own scroll pane. The
   section heads carry a caption of their own; .group is the items page's
   grouped-section header, reused so both pages read the same. */
.boardsec { margin: 0.5rem 0 1.8rem; }

/* Tracks grow with the page but stop: minmax(col, track) rather than 1fr.
   Unbounded tracks turn a wide canvas into nothing but longer arrows, which
   is how a compact board stops reading as one -- the tile stays put and the
   distance between tiers runs away from it. The ceiling keeps the gutter in
   proportion to the tile at any width, and what is left over is simply
   unused: a board is as wide as its four tiers need, not as wide as the
   window. min-width keeps the kit's own overflow behaviour, so below the
   natural width the board scrolls sideways instead of crushing the columns. */
.boardsec .ib-inner {
  width: auto; min-width: max-content;
  grid-template-columns:
    repeat(var(--ib-cols, 4), minmax(var(--ib-col), var(--ib-track)));
}
.boardsec .ib-col-head, .boardsec .ib-node { width: var(--ib-col); }
/* Gutters and rows scale with the tile rather than keeping the kit's defaults,
   which were set for a tile half again as large. */
.boardsec .ib-board {
  --ib-track: clamp(140px, 12vw, 240px);
  --ib-gap-x: clamp(32px, 2.4vw, 68px);
  --ib-gap-y: 12px;
}
/* The pool is the exception to "tiles stay at the column width": it has no
   arrows to line up with, so it spreads across the whole track and packs to
   fit. That makes it the one part of a board that turns surplus width into
   more visible items instead of longer arrows -- and it is where most of a
   category lives. 86px keeps a cell above the kit's 72px name-plate floor, so
   the pool keeps readable names at every width. */
.boardsec .ib-loose {
  width: auto;
  grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
}
.boardsec .ib-loose .ai-item { --ai-w: 86px; }
/* Both of the board's own knobs are viewport expressions rather than pixel
   counts -- see BOARD_COL / BOARD_PANE, which the kit writes through verbatim
   because it only appends "px" to numbers. They live there, not here, so one
   place decides a board's geometry. */
/* The one run of prose on a page that is otherwise as wide as the window, so
   it keeps a reading measure of its own. */
.groupnote { color: var(--muted); font-size: 0.78rem; margin: 0.15rem 0 0;
             max-width: 92ch; }

.empty { color: var(--muted); padding: 2rem 0; }
.bstamp { max-width: none; margin: 2rem auto 1rem; padding: 0 var(--pad);
          color: var(--muted); font-size: 0.75rem; }

/* Crowd-control chips ("Applies") and the effect pages. Ability cards are
   wrapped in .abwrap so the chip row can sit under the card without touching
   renderAbilityCard's own markup; the wrapper takes over the card's old row
   sizing and the card stretches to fill it. */
.abilities .abwrap { width: 520px; max-width: 100%;
                     display: flex; flex-direction: column; }
.abilities .abwrap .ac-card { width: 100%; flex: 1 1 auto; }
.fx-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center;
            margin: 0.45rem 0 0; }
.itemcard .fx-chips { margin: 0.8rem 0 0; }
.fx-cap { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em;
          color: var(--muted); margin-right: 0.15rem; }
.fx-chip { font-size: 0.78rem; padding: 0.12rem 0.55rem; border-radius: 999px;
           border: 1px solid var(--rule); background: var(--panel);
           color: var(--link); text-decoration: none; }
.fx-chip:hover, .fx-chip:focus-visible { border-color: var(--accent); }
.fx-hero { margin: 1.2rem 0 0.3rem; font-size: 0.95rem; }
.fx-hero a { color: var(--fg); text-decoration: none; }
.fx-hero a:hover, .fx-hero a:focus-visible { color: var(--link); }
.fx-abilities { justify-content: flex-start; margin-top: 0.4rem; }
/* Effect-page cards swap the ability icon for the hero's card art in the
   kit's own header band (effectCardData); no extra layout is needed here --
   the kit masks .ac-art into the right of .ac-top by itself. */
