/* Tactical Telemetry palette — this WAS overridden wholesale by
   theme-tactical.css's own :root on every route; merged in directly here
   now that the theme is permanent and site-wide, so there's one source of
   truth instead of a full second copy that silently wins every time.
   --border was raised from #333333 (1.4-1.6:1 against these panels — under
   the WCAG 3:1 non-text minimum) to #656565 (~3-3.4:1) so card/input edges
   stay visible on dim or low-quality screens instead of relying on the
   ~1.06:1 gap between --bg/--panel/--panel-2 alone. */
:root{
  --bg:#0a0a0a;
  --panel:#121212;
  --panel-2:#181818;
  --border:#656565;
  --text:#eaeaea;
  --muted:#888888;
  --accent:#ff2a2a;
  --accent-2:#4af626;
  --good:#4af626;
  --good-bg:rgba(74,246,38,.12);
  --bad:#ff2a2a;
  --bad-bg:rgba(255,42,42,.12);
  --warn:#ffb300;
  --warn-bg:rgba(255,179,0,.1);
  --radius:0;
  --radius-sm:0;
}
*{box-sizing:border-box}
body{
  margin:0;
  background:
    radial-gradient(circle at 15% -10%, #1c2438 0%, transparent 55%),
    radial-gradient(circle at 100% 0%, #221733 0%, transparent 50%),
    var(--bg);
  background-repeat:no-repeat;
  color:var(--text);
  font-family:'Inter',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
}
.wrap{max-width:960px;margin:0 auto;padding:24px 16px 90px}

/* .nav-bar-wrap only exists when JS (initApp in shared.js) wraps .nav-bar
   to add the scroll-edge fade below — position:relative anchor for
   .nav-fade, margin lives here instead of on .nav-bar so it still applies
   even before that wrapping runs (progressive enhancement, not required
   for the nav itself to work). */
.nav-bar-wrap{position:relative;margin-bottom:18px}
.nav-bar{display:flex;flex-wrap:wrap;gap:8px}
/* Signal more content past each edge — only visible while .nav-bar
   actually overflows in that direction (mobile's single scrollable row;
   the active tab can land scrolled toward either side, see initNavFade
   in shared.js). On desktop, where it wraps instead of scrolling, both
   stay hidden since there's nothing to scroll to on either side. */
.nav-fade{position:absolute;top:0;right:0;bottom:0;width:36px;pointer-events:none;
  background:linear-gradient(to right, transparent, var(--bg));opacity:0;transition:opacity .15s}
.nav-fade.visible{opacity:1}
.nav-fade-left{position:absolute;top:0;left:0;bottom:0;width:36px;pointer-events:none;
  background:linear-gradient(to left, transparent, var(--bg));opacity:0;transition:opacity .15s}
.nav-fade-left.visible{opacity:1}
.nav-link{display:inline-flex;align-items:center;min-height:44px;box-sizing:border-box;border:1px solid var(--border);border-radius:9px;padding:8px 13px;font-size:.82rem;font-weight:600;color:var(--muted);text-decoration:none;transition:border-color .15s,color .15s,background .15s}
.nav-link:hover{border-color:var(--accent);color:var(--text)}
.nav-link.active{background:var(--accent);border-color:var(--accent);color:#fff}

.topbar{display:flex;flex-wrap:wrap;gap:16px;justify-content:space-between;align-items:flex-start;margin-bottom:18px}
.brand-eyebrow{color:var(--muted);font-size:.72rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;margin:0 0 6px}
h1{font-size:1.5rem;margin:0 0 6px;letter-spacing:-.01em;display:flex;align-items:center;gap:8px}
.sub{color:var(--muted);font-size:.92rem;margin:0;max-width:520px;line-height:1.5}
.lang-switch{display:flex;border:1px solid var(--border);border-radius:10px;overflow:hidden;flex-shrink:0}
.lang-btn{display:inline-flex;align-items:center;min-height:44px;box-sizing:border-box;border:none;padding:8px 14px;background:var(--panel);color:var(--muted);font-weight:700;font-size:.78rem;cursor:pointer;font-family:inherit}
.lang-btn.active{background:var(--accent);color:#fff}
.lang-btn:not(.active):hover{background:var(--panel-2);color:var(--text)}

.intro-card{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);padding:18px 20px;margin-bottom:18px}
.intro-title{font-weight:700;font-size:.95rem;margin-bottom:10px;display:flex;align-items:center;gap:7px}
.intro-lead{margin:0 0 14px;font-size:.95rem;font-weight:600;color:var(--text)}
.intro-features{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px 18px;margin-bottom:14px}
.intro-feature{display:flex;align-items:flex-start;gap:9px;font-size:.85rem;color:var(--muted);line-height:1.45}
.intro-feature .ico{flex-shrink:0;font-size:1rem}
.intro-note{margin:0;padding-top:12px;border-top:1px solid var(--border);font-size:.78rem;color:var(--muted);line-height:1.5}
.intro-note .warn-icon{color:var(--warn);margin-right:3px}

.toolbar{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}
button{cursor:pointer;border:1px solid var(--border);background:var(--panel);color:var(--text);border-radius:9px;padding:10px 14px;font-size:.88rem;font-family:inherit;font-weight:600;transition:border-color .15s,background .15s}
button:hover{border-color:var(--accent)}
button.danger{border-color:var(--bad);color:var(--bad);background:transparent}
button.confirming{background:var(--bad);border-color:var(--bad);color:#fff;animation:pulse 1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.6}}

input[type=number],input[type=text],select{
  background:#0e1119;border:1px solid var(--border);color:var(--text);border-radius:8px;padding:9px 11px;font-size:16px;font-family:inherit;
  transition:border-color .15s;
}
input[type=number]:focus,select:focus{outline:none;border-color:var(--accent)}
input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
input[type=number]{-moz-appearance:textfield}

.card{background:var(--panel);border:1px solid var(--border);border-radius:var(--radius);padding:18px;margin-bottom:18px}
.card h2{margin:0 0 14px;font-size:.98rem;font-weight:700}
.stock-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px}
.stock-item label{display:block;font-size:.78rem;color:var(--muted);margin-bottom:5px;font-weight:600}
.stock-item input{width:100%;font-size:1.15rem;padding:10px 12px;font-weight:600}

.res-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:7px;vertical-align:middle;background:currentColor}

/* Original line-art resource icons (drawn from scratch, not derived from
   any game asset — see each comment for what it's based on). Each one is
   a real file under icons/ (not an inline data: URI) so it can be viewed,
   diffed and edited like any other SVG — no risk of the mask-image and
   -webkit-mask-image copies silently drifting apart. Rendered via CSS
   mask so every icon still picks up the resource's own color from the
   existing inline style="color:..." on .res-dot, same as the plain dot.
   Each icon's selector list below explicitly opts that resource in to the
   18px sizing + masking — a resource with no entry here simply keeps the
   plain small dot (safe fallback: data-res is set on every .res-dot
   across all 5 routes, but only resources listed below get an icon). */
.res-dot[data-res="FC"],
.res-dot[data-res="AFC"],
.res-dot[data-res="Hyperalloy"],
.res-dot[data-res="SealOfWisdom"],
.res-dot[data-res="SealOfKnowledge"],
.res-dot[data-res="CommonCoin"],
.res-dot[data-res="RareCoin"],
.res-dot[data-res="PreciousCoin"],
.res-dot[data-res="LegendaryCoin"],
.res-dot[data-res="PrisonerArmorData"],
.res-dot[data-res="PowerModule"],
.res-dot[data-res="AdvancedPowerModule"],
.res-dot[data-res="DataDisk"],
.res-dot[data-res="PlanetCoin"],
.res-dot[data-res="EquipmentParts"],
.res-dot[data-res="Magnet"],
.res-dot[data-res="PotentialCoil"],
.res-dot[data-res="PrecisionEquipment"],
.res-dot[data-res="HeroFragment"],
.res-dot[data-res="ExclusiveEquipPart"]{
  width:18px; height:18px;
  background-color:currentColor;
  mask-repeat:no-repeat; mask-position:center; mask-size:contain;
  -webkit-mask-repeat:no-repeat; -webkit-mask-position:center; -webkit-mask-size:contain;
}
/* FC — mechanical module: hexagonal housing + a central gauge dial */
.res-dot[data-res="FC"]{
  mask-image:url("icons/fc.svg");
  -webkit-mask-image:url("icons/fc.svg");
}
/* AFC — energy: a lightning bolt inside a circle */
.res-dot[data-res="AFC"]{
  mask-image:url("icons/afc.svg");
  -webkit-mask-image:url("icons/afc.svg");
}
/* SealOfWisdom — a wax-seal stamp: grip on top, neck, flared stamping
   base (the part that presses down) */
.res-dot[data-res="SealOfWisdom"]{
  mask-image:url("icons/seal-wisdom.svg");
  -webkit-mask-image:url("icons/seal-wisdom.svg");
}
/* SealOfKnowledge — a pawn-shaped seal stamp: round head, narrow neck,
   wide oval base — a distinct silhouette from Wisdom's flared stamp */
.res-dot[data-res="SealOfKnowledge"]{
  mask-image:url("icons/seal-knowledge.svg");
  -webkit-mask-image:url("icons/seal-knowledge.svg");
}
/* Trove Coins (Common/Rare/Precious/Legendary) — one shared icon (an open
   chest with a coin inside), since the 4 tiers are the same image in the
   reference, differing only by color — already handled automatically by
   each tier's own RES_ACCENT, same as every other icon here. */
.res-dot[data-res="CommonCoin"],
.res-dot[data-res="RareCoin"],
.res-dot[data-res="PreciousCoin"],
.res-dot[data-res="LegendaryCoin"]{
  mask-image:url("icons/trove-coin.svg");
  -webkit-mask-image:url("icons/trove-coin.svg");
}
/* PrisonerArmorData — simplified: a rectangular data card with a lightning
   bolt directly on it (dropped the extra circle — simpler at small size) */
.res-dot[data-res="PrisonerArmorData"]{
  mask-image:url("icons/prisoner-armor-data.svg");
  -webkit-mask-image:url("icons/prisoner-armor-data.svg");
}
/* PowerModule / AdvancedPowerModule — a battery with a lightning bolt; one
   shared shape, colors already differ (blue vs yellow) via RES_ACCENT */
.res-dot[data-res="PowerModule"],
.res-dot[data-res="AdvancedPowerModule"]{
  mask-image:url("icons/power-module.svg");
  -webkit-mask-image:url("icons/power-module.svg");
}
/* DataDisk — a disc inside a square case */
.res-dot[data-res="DataDisk"]{
  mask-image:url("icons/data-disk.svg");
  -webkit-mask-image:url("icons/data-disk.svg");
}
/* PlanetCoin — a coin with a ringed planet (Saturn-like) inside */
.res-dot[data-res="PlanetCoin"]{
  mask-image:url("icons/planet-coin.svg");
  -webkit-mask-image:url("icons/planet-coin.svg");
}
/* EquipmentParts — simplified: just a hex bolt head with a center socket,
   viewed top-down (dropped the shaft + thread lines — too busy small) */
.res-dot[data-res="EquipmentParts"]{
  mask-image:url("icons/equipment-parts.svg");
  -webkit-mask-image:url("icons/equipment-parts.svg");
}
/* Magnet — a horseshoe magnet with striped pole caps */
.res-dot[data-res="Magnet"]{
  mask-image:url("icons/magnet.svg");
  -webkit-mask-image:url("icons/magnet.svg");
}
/* PotentialCoil — a wound coil/inductor symbol */
.res-dot[data-res="PotentialCoil"]{
  mask-image:url("icons/potential-coil.svg");
  -webkit-mask-image:url("icons/potential-coil.svg");
}
/* PrecisionEquipment — a gear */
.res-dot[data-res="PrecisionEquipment"]{
  mask-image:url("icons/precision-equipment.svg");
  -webkit-mask-image:url("icons/precision-equipment.svg");
}
/* HeroFragment — a single jigsaw puzzle piece */
.res-dot[data-res="HeroFragment"]{
  mask-image:url("icons/hero-fragment.svg");
  -webkit-mask-image:url("icons/hero-fragment.svg");
}
/* ExclusiveEquipPart — a generic weapon (a sabre): blade, crossguard, grip.
   User's call: the real resource covers many weapon types (sabre, hook,
   laser pistol, cannon...) with no single consistent reference, so this is
   deliberately the simplest generic "weapon" glyph rather than any specific
   one of them. */
.res-dot[data-res="ExclusiveEquipPart"]{
  mask-image:url("icons/exclusive-equip-part.svg");
  -webkit-mask-image:url("icons/exclusive-equip-part.svg");
}
/* Hyperalloy — material block: an isometric wireframe cube */
.res-dot[data-res="Hyperalloy"]{
  mask-image:url("icons/hyperalloy.svg");
  -webkit-mask-image:url("icons/hyperalloy.svg");
}

.summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px}
.res-card{border:1px solid var(--border);border-left:3px solid var(--accent-color,var(--border));border-radius:var(--radius-sm);padding:14px 16px;background:var(--panel-2)}
.res-card .name{font-size:.76rem;color:var(--accent-color,var(--muted));text-transform:uppercase;letter-spacing:.05em;font-weight:700;display:flex;align-items:center}
.res-card .need{font-size:1.55rem;font-weight:800;margin:6px 0;letter-spacing:-.02em}
.res-card .missing{display:inline-flex;align-items:center;font-size:.82rem;font-weight:700;padding:3px 10px;border-radius:20px}
.missing.bad{color:var(--bad);background:var(--bad-bg)}
.missing.good{color:var(--good);background:var(--good-bg)}

.cat-title{font-size:1.05rem;font-weight:700;margin:28px 0 12px;display:flex;align-items:center;gap:8px}
.route-part{margin-top:36px}
.route-part:first-child{margin-top:0}
.part-header{font-size:1.15rem;font-weight:800;letter-spacing:-.01em;display:flex;align-items:center;gap:9px;padding-bottom:12px;margin-bottom:16px;border-bottom:2px solid var(--border)}
.rarity-badge{display:inline-flex;align-items:center;font-size:.78rem;font-weight:800;letter-spacing:.04em;padding:4px 14px;border-radius:20px;margin:22px 0 10px;color:var(--badge-color);border:1px solid var(--badge-color);background:var(--panel-2)}
.part-header+.rarity-badge{margin-top:0}
.qty-control{display:flex;align-items:center;gap:10px;margin-bottom:14px}
.add-item{border-color:var(--accent);color:var(--accent);background:rgba(91,140,255,.08)}
.add-item:hover{background:rgba(91,140,255,.16)}
.add-item:disabled{cursor:not-allowed;opacity:.45}
.research-group{border:1px solid var(--border);border-radius:var(--radius);margin-bottom:12px;background:var(--panel);overflow:hidden}
/* A real <button> now (was a <div>, keyboard-inaccessible) — reset the
   generic button{} chip styling below so it still reads as a plain
   header row, not a bordered button. */
.group-head{display:flex;align-items:center;gap:10px;width:100%;padding:13px 16px;
  border:none;border-radius:0;background:none;color:inherit;font:inherit;text-align:left;
  cursor:pointer;transition:background .15s}
.group-head:hover{background:var(--panel-2)}
.group-head:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.group-icon{font-size:1.15rem}
.group-name{font-weight:700;flex:1}
.group-badge{font-size:.72rem;padding:3px 9px;border-radius:20px;border:1px solid var(--border);color:var(--muted);font-weight:600}
.group-badge.active{border-color:var(--accent);color:var(--accent);background:rgba(91,140,255,.1)}
.group-chevron{color:var(--muted);transition:transform .18s;font-size:.8rem}
.group-chevron.open{transform:rotate(90deg)}
.group-body{display:none;padding:0 12px 12px}
.group-body.open{display:block}

.track{border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:10px;background:var(--panel-2);overflow:hidden}
/* Border-only, not colored text: this and .missing.bad below both used
   the same --accent red, so a flagged track's *name* (e.g. "Bureau du
   Directeur") read identically to a "Manque X" deficit badge — two
   unrelated meanings sharing one color. A vivid-enough red to pass 4.5:1
   on these dark panels has very little room to also look distinct from
   --bad (checked: darkening it enough to look different drops it under
   AA), so the fix is structural instead of a second red — the flagged
   track keeps its red edge marker, but the name goes back to plain text. */
.track.track-accent{border-left-width:3px;border-left-color:var(--accent-color)}
.track-head{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:13px 16px}
.track-name{font-weight:600;flex:1;min-width:160px}
.track-badge{font-size:.72rem;padding:3px 9px;border-radius:20px;border:1px solid var(--border);color:var(--muted);font-weight:600}
.track-badge.active{border-color:var(--accent);color:var(--accent);background:rgba(91,140,255,.1)}
.track-controls{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;font-size:.8rem;color:var(--muted);width:100%}
.track-controls .field{display:flex;align-items:center;gap:6px;flex:1 1 130px;font-weight:600}
.track-controls select{flex:1;min-width:0;max-width:100%}
.track-controls.paired-controls{margin-top:8px;padding-top:10px;border-top:1px dashed var(--border)}
.paired-label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--accent-2);flex:1 1 100%}

table{width:100%;border-collapse:collapse;font-size:.82rem;margin-top:10px}
th,td{padding:8px 8px;text-align:left;border-bottom:1px solid var(--border)}
th{color:var(--muted);font-weight:700;font-size:.7rem;text-transform:uppercase;letter-spacing:.04em}
.empty-hint{color:var(--muted);font-size:.85rem;font-style:italic;margin:0}
.breakdown{margin-top:4px;overflow-x:auto}
.breakdown th,.breakdown td{white-space:nowrap}
.breakdown td.cost-cell{white-space:normal;min-width:180px}
.auto-tag{color:var(--warn);font-size:.72rem}
.estimated-wrap{display:inline-block;position:relative}
.estimated-tag{display:inline-block;border:1px solid var(--warn);color:var(--warn);background:none;
  border-radius:4px;font-size:.68rem;line-height:1;padding:2px 4px;margin-left:4px;cursor:pointer;
  font-family:inherit}
.estimated-tag[aria-expanded=true]{background:var(--warn-bg)}
.estimated-note{position:absolute;left:0;top:calc(100% + 4px);z-index:5;width:max-content;max-width:220px;
  background:var(--panel-2);border:1px solid var(--warn);color:var(--text);font-size:.72rem;
  line-height:1.35;padding:6px 8px;white-space:normal}
footer{color:var(--muted);font-size:.78rem;text-align:center;margin-top:36px}
.footer-logo{display:block;height:200px;width:auto;margin:12px auto 0}

/* Fixed bar mirroring "what's missing" so the numbers stay on screen while
   scrolling through tracks far below the summary card — see renderStickyBar
   in shared.js. Tappable: jumps back up to the full summary/breakdown. */
.sticky-bar{position:fixed;left:0;right:0;bottom:0;z-index:50;cursor:pointer;
  background:rgba(15,18,27,.92);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  border-top:1px solid var(--border);
  padding:10px 16px calc(10px + env(safe-area-inset-bottom));}
.sticky-bar:hover,.sticky-bar:focus-visible{background:rgba(21,26,36,.96)}
.sticky-bar:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.sticky-bar-inner{max-width:960px;margin:0 auto;display:flex;gap:10px;overflow-x:auto;
  -ms-overflow-style:none;scrollbar-width:none}
.sticky-bar-inner::-webkit-scrollbar{display:none}
.sticky-chip{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;font-size:.82rem;
  font-weight:600;color:var(--accent-color,var(--text));white-space:nowrap;
  border:1px solid var(--border);border-radius:20px;padding:6px 12px;background:var(--panel-2)}
.sticky-chip b{font-weight:800;color:var(--text)}

/* Below 600px the breakdown table can't fit From/To/Cost side by side without
   horizontal scroll clipping the Cost column — the whole point of the app.
   Reflow each row into a stacked card instead; data-label (set in shared.js)
   supplies the per-cell caption via ::before since <th> is hidden here. */
@media (max-width:600px){
  /* One scrollable row instead of wrapping onto 2-3 lines — on a phone the
     5 nav buttons otherwise push the actual page content well below the
     fold before a visitor sees anything. Same one-tap access as before
     (no hamburger/collapsed menu), just reclaiming vertical space. */
  .nav-bar{flex-wrap:nowrap;overflow-x:auto;-ms-overflow-style:none;scrollbar-width:none}
  .nav-bar::-webkit-scrollbar{display:none}
  .nav-link{flex-shrink:0}
  .breakdown table,.breakdown thead,.breakdown tbody{display:block;width:100%}
  .breakdown thead{display:none}
  /* tr as a flex row (not block) so From/To can share one line while the
     target name and cost each keep a full-width line of their own. */
  .breakdown tr{display:flex;flex-wrap:wrap;column-gap:14px;border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:10px;padding:10px 12px;background:var(--panel-2)}
  .breakdown td{display:block;border-bottom:none;padding:5px 0;white-space:normal;min-width:0}
  .breakdown td::before{content:attr(data-label);display:block;color:var(--muted);font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin-bottom:2px}
  .breakdown td:first-child{flex:0 0 100%;font-weight:700;font-size:.95rem}
  .breakdown td:nth-child(2),.breakdown td:nth-child(3){flex:0 0 auto}
  .breakdown td.cost-cell{flex:0 0 100%;font-weight:700;color:var(--text);font-size:.92rem}
}
