.gallery-page main#view { max-width: 72rem; margin: 0 auto; padding: 1rem 1.25rem 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: 72rem; margin: 0 auto; padding: 0.9rem 1.25rem 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 { font-size: 0.82rem; color: var(--muted); display: flex;
            gap: 0.35rem; align-items: center; }
#sortwrap[hidden] { display: none; }
#groupwrap[hidden] { display: none; }
#sortsel, #groupsel {
  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 two cards share a row inside the 72rem view; 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: build_gallery.py wraps each property
   fragment in its own .tb chip so "+3.5s Duration +3m Width +1m Height"
   reads as three bonuses, not a run-on blob. Chips keep value + label on
   one line and the row wraps between chips; loc-sourced tier descs are
   prose and never carry the class. */
.ac-tier-bonus .tb { display: inline-flex; align-items: baseline; gap: 0.3em;
                     margin: 0.1em 0.4em 0.1em 0; padding: 0.05em 0.5em;
                     border-radius: 5px; background: rgba(0, 0, 0, .28);
                     box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08); }
.ac-tier-bonus .tb:last-child { margin-right: 0; }
.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 as .flowwrap: 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-path flowchart (item detail). Tier columns flow left to right around
   the viewed item; the connector curves live in one absolutely positioned SVG
   that gallery.js's drawFlow measures off the real node boxes, so the mobile
   media query below only has to flip the flex axes -- the lines follow
   whatever layout results. .flowpath is width:max-content inside a scrolling
   .flowwrap so node rects measured against it are content coordinates and the
   SVG overlay covers every node even mid-scroll. */
.flowwrap { overflow-x: auto; margin: 0.4rem 0 0.6rem; }
.flowpath { position: relative; display: flex; align-items: center;
            gap: 2.4rem; width: max-content; max-width: none;
            padding: 0.5rem 0.25rem 0.75rem; }
.flowcol { display: flex; flex-direction: column; align-items: center;
           gap: 1rem; }
.flownode { position: relative; z-index: 1; }
.flownode.me .ai-item { outline: 2px solid var(--accent); outline-offset: 3px;
                        border-radius: 4px; }
.flowsvg { position: absolute; inset: 0; width: 100%; height: 100%;
           pointer-events: none; z-index: 0; color: var(--muted); }
.flowedge { fill: none; stroke: currentColor; stroke-width: 1.5;
            opacity: 0.75; }
/* Narrow viewports: the same chart top-to-bottom -- columns become rows and
   the whole path becomes a column. drawFlow's measured connectors switch to
   bottom->top on their own. */
@media (max-width: 40rem) {
  main#view .flowpath { flex-direction: column; align-items: center;
                        width: auto; gap: 1.6rem; }
  main#view .flowcol { flex-direction: row; flex-wrap: wrap;
                       justify-content: center; align-items: flex-start;
                       gap: 0.7rem; }
}

/* Hover build-path preview: the compact flowchart appendFlowPop grows the
   kit's .ac-pop with (gallery-side augment; the kit file is untouched).
   Dark like the card above it, since the pop floats over both themes. The
   viewport media query above deliberately excludes the pop (main#view
   scope): hover is a desktop affordance and the preview keeps the
   left-to-right shape at any width. */
.ac-pop .flowpop { margin-top: 8px; width: fit-content; max-width: 480px;
                   background: #20242b; border: 1px solid #39404b;
                   border-radius: 10px; padding: 7px 12px 10px;
                   box-shadow: 0 12px 30px rgba(0, 0, 0, .45); }
.ac-pop .flowcap { font-size: 10px; font-weight: 700;
                   text-transform: uppercase; letter-spacing: 0.08em;
                   color: #95a3af; margin: 0 0 3px; }
.ac-pop .flowpath { gap: 1.5rem; padding: 4px 2px 2px; }
.ac-pop .flowcol { gap: 0.5rem; }
.ac-pop .flowsvg { color: #8b98a5; }
.ac-pop .flownode.me .ai-item { outline-color: #d99b62; }
.flownode.dis .ai-item { opacity: 0.45; }
.empty { color: var(--muted); padding: 2rem 0; }
.bstamp { max-width: 72rem; margin: 2rem auto 1rem; padding: 0 1.25rem;
          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. */
