/* ============================================================================
   gf.css - the Gearforge design system. SOURCE OF TRUTH.

   Every token and shared component lives here and is documented, rendered
   live, in styleguide.html. The rule (Danny, 2026-08-07): new UI consumes
   these tokens and components; hardcoding a new value needs an explicit flag
   and Danny's sign-off first. If a value you need is missing, that is a
   conversation, not an inline style.

   Load order: this file is linked before any page stylesheet, so page CSS
   can override on same specificity. character.css consumes these tokens and
   defines its own --drawer-w.
   ========================================================================= */

/* ---------- fonts ---------- */
@font-face {
  font-family: 'GameFont';
  src: url('fonts/vcr-osd-mono.ttf');
  font-display: swap;
}
@font-face {
  /* tooltip body font is ChevyRay's Bird Seed (fGuiText17); drop the ttf in if you own it */
  font-family: 'GameFontBird';
  src: url('fonts/bird-seed.ttf');
  font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  /* type scale (2026-08-03 normalisation): chrome uses these four tokens;
     item cards keep fixed 12px+ for game-tooltip fidelity */
  --fs-xs: 12px; --fs-s: 13px; --fs-m: 14px; --fs-l: 16px;
  /* chrome palette */
  --bg: #14151c;
  --panel: #1d1f2a;
  --panel2: #242736;
  --border: #33374a;
  --text: #e8e9f0;
  --dim: #9a9fb5;
  --accent: #009ef3;
  --gold: #f9c22b;
  /* danger/negative: promoted 2026-08-07 from the same literal repeated six
     times across gf.css and character.css (weak damage, downgrade verdicts,
     dead-stat advice, clamp flash). Extraction of an existing value, not a
     new colour. */
  --danger: #e06c6c;
  /* tooltip-card palette (item cards only; chrome stays on the tokens above) */
  --tt-bg: #0c0912;
  --tt-border: #6a35a0;
  --tt-inner: #171021;
  --tt-stat: #58a6e8;
  --tt-buff: #27dcd3;
  --tt-green: #35d435;
  /* must match BORDER_COLORS.legendary in index.html's script */
  --tt-legendary: #C4783A;
  /* fonts: chrome uses --uifont, item cards use --gamefont */
  --gamefont: 'GameFontBird', 'GameFont', Consolas, 'Courier New', monospace;
  --uifont: system-ui, "Segoe UI", sans-serif;
  /* every control in a bar shares this height */
  --ctl-h: 34px;
  /* one page width for every page (2026-08-07, Danny: the pages had drifted
     to 1280/1280/1100/1080). index.html's planner mode widens on top of it. */
  --page-w: 1280px;
}

/* ---------- element palette ----------
   Accent colours for the game's damage and support elements, used by the
   Abilities & Relics page for element chips and conversion markers.
   NEW TOKEN FAMILY (2026-08-07), values carried from the relic-tree artifact;
   flagged for Danny's sign-off per the no-new-hardcode rule. */
:root {
  --e-fire: #d4642f; --e-cold: #6fa8d6; --e-lightning: #cfae33;
  --e-void: #9b6fd6; --e-physical: #9aa0b4; --e-explosive: #d68a3c;
  --e-healing: #5fb87a; --e-shielding: #6fc4c4;
}

/* The game is hard edges everywhere, so nothing here is rounded. The reset
   below is the backstop; do not reintroduce border-radius on new elements. */
* { box-sizing: border-box; margin: 0; border-radius: 0; }

/* The hidden attribute must beat every component display value. Author rules
   like ".btn { display: inline-flex }" outrank the browser's own
   "[hidden] { display: none }" whatever their specificity, because author
   styles win over the UA origin, so without this a button with hidden=true
   renders anyway. That bug shipped once (the trade board's carousel arrows,
   2026-08-07) and .gf-modal already carried a local workaround, so the rule
   belongs here once rather than per component. */
[hidden] { display: none !important; }

/* ---------- control bar ----------
   Each control shares --ctl-h, one border, one font and one set of states,
   so the block reads as one panel rather than five borrowed widgets.
   The game font stays on the item cards; chrome uses the UI font, which is
   legible at 12px in a way a pixel font is not. */
.controls {
  border: 1px solid var(--border); background: var(--panel);
  padding: .75rem .8rem; margin-bottom: 1rem;
  display: flex; flex-direction: column; gap: .55rem;
}
.crow { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; }
.flabel { width: 3.6rem; flex: none; }
.fgroup { display: flex; align-items: center; gap: .45rem; }
.fgroup .flabel { width: auto; }
.chip, select, .btn, .btn-primary {
  height: var(--ctl-h); padding: 0 .65rem; cursor: pointer;
  background: var(--panel2); border: 1px solid var(--border); color: var(--dim);
  font-family: var(--uifont); font-size: var(--fs-s);
  display: inline-flex; align-items: center; gap: .4rem;
}
.chip:hover, .btn:hover, select:hover { border-color: var(--dim); color: var(--text); }
.chip.active { border-color: var(--gold); color: var(--text); background: var(--bg); }
.chip:focus-visible, .btn:focus-visible, .btn-primary:focus-visible,
#search:focus-visible, select:focus-visible, #buildBtn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
/* ---------- label ----------
   THE uppercase label style (merged 2026-08-07 from a .05-.12em spread across
   six files, Danny's call): one size, one case, one letter-spacing. Two
   documented colour uses: dim for inline and control labels (default), gold
   for section headings (.gold). Nothing else may set its own uppercase-label
   metrics. */
.gf-label, .flabel, .gf-table th {
  font-family: var(--uifont); font-weight: 400; color: var(--dim);
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .09em;
}
.gf-label.gold { color: var(--gold); }

/* ---------- muted small text ----------
   THE muted secondary style (merged 2026-08-07 from .count, meta and hint
   variants, Danny's call). --fs-s because half its members are sentences;
   the fragment members gain 1px. .count adds bar layout only; it survives on
   relics.html, and was removed from the index and trade bars outright. */
.gf-muted, .count { color: var(--dim); font-size: var(--fs-s); }
.count { margin-left: auto; white-space: nowrap; }

/* ---------- or-divider ----------
   A rule with a word in it, for a form offering two ways to do the same thing.
   Layout only: compose it with .gf-label (`class="gf-or gf-label"`) so the text
   comes from THE label style rather than inventing a second set of uppercase
   metrics, which the label merge exists to prevent. */
.gf-or { display: flex; align-items: center; gap: .6rem; margin: .35rem 0; }
.gf-or::before, .gf-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* ---------- primary button ----------
   The one gold, filled action on a view: submit, post listing, copy build
   link. Gold so it cannot be missed against the dark chrome (Danny,
   2026-08-07). Everything else stays .btn; never two primaries side by side.
   Declared after the cluster above so its overrides win on class="btn
   btn-primary" too. */
.btn-primary {
  background: var(--gold); border-color: var(--gold);
  color: var(--bg); font-weight: 600;
}
.btn-primary:hover { filter: brightness(1.08); color: var(--bg); border-color: var(--gold); }
.btn-primary:disabled { opacity: .45; cursor: not-allowed; filter: none; }

/* ---------- text input ----------
   Canonical form of index.html's #search; new pages use the class. */
.gf-input {
  height: var(--ctl-h);
  background: var(--bg); border: 1px solid var(--border); color: var(--text);
  padding: 0 .7rem; font-size: var(--fs-m); font-family: var(--uifont); outline: none;
}
.gf-input::placeholder { color: #6a6f85; }
.gf-input:focus { border-color: var(--accent); }
.gf-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ---------- header / nav ----------
   The slim page header that replaces the landing hero: wordmark left, links
   right. Wordmark, not a logo: the Third-Party Extensions policy bans the
   Soulbound name/logo/branding from a fan tool's name and icon. */
.gf-header {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .6rem 0 .9rem; margin-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.gf-header .logo { width: 200px; max-width: 48vw; height: auto; image-rendering: pixelated; display: block; }
/* The per-page tagline chip that used to sit beside the wordmark was removed
   2026-08-07 (Danny): the nav already says which page you are on, so it was
   repeating itself. Its rules went with it rather than lingering as dead CSS. */
.gf-nav { display: flex; gap: .45rem; margin-left: auto; flex-wrap: wrap; }
.gf-nav a {
  height: var(--ctl-h); padding: 0 .8rem; display: inline-flex; align-items: center;
  background: var(--panel2); border: 1px solid var(--border); color: var(--dim);
  font-family: var(--uifont); font-size: var(--fs-s); text-decoration: none;
}
.gf-nav a:hover { border-color: var(--dim); color: var(--text); }
.gf-nav a[aria-current="page"] { border-color: var(--gold); color: var(--text); background: var(--bg); }
.gf-nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* ---------- WIP marker ----------
   Says a feature is live but incomplete, which is more honest than letting
   someone find the gaps. Promoted here 2026-08-07 when the nav needed it too:
   it had been a one-off `#buildBtn .wip` in character.css and an entry in the
   styleguide's exceptions register. Same values, now shared by the planner
   toggle and the nav, so the register lost an entry instead of gaining one.

   Deliberately NOT a .chip: it is a static marker inside a control, never
   interactive itself, so it takes no control height, no hover and no focus
   ring. That is what stops it reading as a nested button. */
.wip {
  font-family: var(--uifont); font-size: var(--fs-xs); letter-spacing: .09em;
  line-height: 1; color: var(--bg); background: var(--gold); padding: .18rem .28rem;
}
.gf-nav .wip { margin-left: .45rem; }

/* ---------- table ----------
   Chrome data table on the shared tokens (pattern carried over from the
   local loot browser, palette translated to the chrome tokens). */
.gf-table { border-collapse: collapse; width: 100%; background: var(--panel); border: 1px solid var(--border); }
.gf-table th, .gf-table td {
  text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--border);
  vertical-align: top; overflow-wrap: anywhere;
}
.gf-table td { font-size: var(--fs-s); }
/* text metrics come from the .gf-label cluster above */
.gf-table th { background: var(--panel2); }
.gf-table tr:hover td { background: var(--panel2); }
.gf-scroll { overflow-x: auto; }

/* ---------- modal shell ----------
   Canonical form of index.html's #suggest overlay. Square by the reset:
   the #suggest original carries legacy radii; the canonical does not. */
.gf-modal {
  position: fixed; inset: 0; z-index: 60; display: flex;
  align-items: center; justify-content: center; background: rgba(6,4,12,.7);
}
.gf-modal[hidden] { display: none; }
.gf-modal .box {
  background: var(--panel); border: 1px solid var(--border);
  font-family: var(--uifont); padding: 1.1rem; width: min(440px, 92vw);
  display: flex; flex-direction: column; gap: .7rem;
}
.gf-modal h3 { font-weight: 400; font-size: var(--fs-l); }
.gf-modal .row { display: flex; gap: .6rem; justify-content: flex-end; }

/* ---------- toast ----------
   The one transient confirmation on a page. Redesigned 2026-08-07 (Danny:
   too small, no prominence, and the last rounded corners on the site): gold
   fill so it speaks with the same voice as .btn-primary, square per the
   reset, sized to be noticed. Judgement calls, flagged: z-index 70 so it
   clears the modal overlay (60), and a small rise on entry. */
#toast {
  position: fixed; bottom: 1.6rem; left: 50%; z-index: 70;
  transform: translate(-50%, .4rem);
  background: var(--gold); color: var(--bg);
  padding: .8rem 1.5rem; font-family: var(--uifont);
  font-size: var(--fs-m); font-weight: 600;
  opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ---------- item cards ----------
   The tooltip-fidelity card, moved verbatim from index.html (2026-08-07) so
   styleguide.html can render the variants. DELIBERATE EXCEPTION to the type
   scale: .95rem body, 1.05rem title, fixed 12px section text, in --gamefont,
   because the card imitates the in-game tooltip. The .grid layout stays in
   index.html; planner-mode reveal rules in character.css still apply because
   this file loads first. Rarity title/border colours are data, applied by
   the card renderer as inline styles (RARITY_COLORS / BORDER_COLORS in
   index.html's script; --tt-legendary must match BORDER_COLORS.legendary). */
.tt {
  background: var(--tt-bg); border: 1px solid var(--tt-border);
  font-family: var(--gamefont);
  font-size: .95rem; line-height: 1.35; /* card fidelity: not on the chrome scale */
  image-rendering: pixelated;
  display: flex; flex-direction: column;
  /* browser skips layout/paint of off-screen cards; keeps 1000 cards cheap */
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;
}
.tt { transition: filter .18s ease; position: relative; }
.tt:hover { filter: brightness(1.12); }
/* only the datamined-only entries, which have no wiki page, copy their id */
.tt.copyable { cursor: pointer; }
/* datamined cards: compact, not stretched to the row's tallest card */
.tt.datamined { align-self: start; contain-intrinsic-size: auto 150px; }
.tt-dm {
  color: #8b90a8; font-size: 12px; font-family: var(--uifont);
  margin-top: .55rem; line-height: 1.45;
}
/* Symmetric side padding keeps the name optically centred even though the
   action icons only sit on the right. */
.tt-title {
  margin: 6px; border: 1px solid var(--tt-border); background: var(--tt-inner);
  text-align: center; padding: .3rem 2.4rem; font-size: 1.05rem; /* card fidelity */
  overflow-wrap: anywhere; position: relative;
}
.tt-acts {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  display: flex; gap: .1rem;
}
.tt-act {
  background: none; border: none; cursor: pointer; color: #8b90a8;
  font: .9rem/1 var(--uifont); padding: .2rem .25rem;
  opacity: 0; transition: opacity .15s, color .15s;
}
.tt:hover .tt-act, .tt-act:focus-visible { opacity: 1; }
.tt-act:hover { color: var(--text); }
/* no hover on touch, so never hide the only route to the wiki */
@media (hover: none) { .tt-act { opacity: 1; } }
.tt-body { padding: 0 .8rem .6rem; flex: 1; display: flex; flex-direction: column; }
.tt-head {
  display: flex; gap: .6rem; align-items: flex-start;
  border-bottom: 2px solid #373737; padding-bottom: .55rem;
}
.tt-head .lines { flex: 1; min-width: 0; }
.tt-icon {
  width: 52px; height: 52px; flex: none; display: flex; align-items: center;
  justify-content: center; margin-top: .2rem;
}
.tt-icon img { width: 52px; height: 52px; object-fit: contain; image-rendering: pixelated; }
.tt-icon .noicon { color: #6a6f85; font-size: 1.1rem; }
.tt-sub { font-size: 1rem; }
.tt-level { color: #fff; }
.tt-sec { margin-top: .55rem; }
.tt-sec h4 { color: #fff; font-size: .98rem; font-weight: 400; }
.tt-stat { color: #fff; }
.tt-stat b { font-weight: 400; color: var(--tt-stat); }
.tt-buff { color: var(--tt-buff); }
.tt-sig { color: var(--tt-legendary); }
.tt-white { color: #fff; }
.tt-legacy { color: var(--dim); font-size: 12px; margin-top: .55rem; }
.tt-req-h { color: var(--gold); margin-top: .55rem; }
.tt-req { color: var(--tt-green); }
.tt-roll-h { color: var(--gold); margin-top: .55rem; font-size: 12px; }
.tt-roll { color: #b9a7e6; font-size: 12px; }
/* Arcadia-sourced layer: legendary effects, hidden stats, drop chances */
.tt-recipe-h { color: var(--gold); margin-top: .55rem; font-size: 12px; }
.tt-recipe-meta { color: #8d8fa0; font-size: 12px; }
.tt-recipe { color: #cfd1dd; font-size: 12px; }
.tt-ingrow { display: flex; align-items: center; gap: .4rem; min-height: 20px; }
.tt-ingrow img {
  width: 16px; height: 16px; object-fit: contain; image-rendering: pixelated;
  flex: none;
}
.tt-ing {
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.tt-ing:hover, .tt-ing:focus-visible { color: #fff; }
.tt-fx-h { color: var(--gold); margin-top: .55rem; font-size: 12px; }
.tt-fx { color: var(--tt-legendary); font-size: 12px; }
.tt-fx-sub { color: #8d8fa0; font-size: 12px; }
.tt-hidden { color: #8d8fa0; font-size: 12px; margin-top: .35rem; }
.tt-drop { color: var(--dim); } /* was the token's own value written literally */
/* margin-top:auto = the flexible gap that evens the cards out */
.tt-src-h { color: var(--gold); margin-top: auto; padding-top: .55rem; font-size: 12px; }
.tt-src { color: #cfd1dd; font-size: 12px; }
.tt-src.unknown { color: var(--dim); }
/* ---------- hover tip ----------
   Native title tooltips do not show reliably in testing (Danny, 2026-08-08),
   so info hovers are a real pseudo-element: instant, card-styled, tokens
   only. Put plain text in data-tip. Two exclusions, by construction: replaced
   elements (inputs) cannot render pseudo-elements, and .abslot already owns
   its ::after - both keep title attributes. */
[data-tip] { position: relative; }
[data-tip]:not(button):not(.btn) { cursor: help; }
[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute; left: 0; bottom: calc(100% + 4px); z-index: 40;
  width: max-content; max-width: 280px;
  background: var(--tt-bg); border: 1px solid var(--tt-border);
  padding: .35rem .55rem;
  color: var(--text); font: 12px/1.4 var(--uifont); font-weight: 400;
  white-space: pre-line; text-transform: none; letter-spacing: normal;
  text-align: left;
}

/* collapsed source list: the full list opens on hover in a card-styled pop.
   A real element, not a title attribute - native tooltips proved unreliable
   (Danny, 2026-08-07). Tokens/card colours only. */
.tt-srcs { position: relative; cursor: help; }
.tt-srcs .tt-srcpop {
  display: none; position: absolute; left: 0; bottom: calc(100% + 4px);
  z-index: 40; min-width: 230px; max-width: 320px;
  background: var(--tt-bg); border: 1px solid var(--tt-border);
  padding: .45rem .6rem;
}
.tt-srcs:hover .tt-srcpop { display: block; }
.tt-flavour { color: #8d8fa0; margin-top: .55rem; border-top: 2px solid #373737; padding-top: .45rem; font-size: 12px; }
.tt-sell {
  border-top: 1px solid var(--tt-border); margin-top: .6rem;
  padding: .4rem .8rem; display: flex; justify-content: space-between;
}
.tt-sell .v { color: var(--gold); }
.tt-sell .lbl { color: #fff; }

.tt-community { color: var(--tt-green); font-size: 12px; }

/* ---------- planner block on the card (only in planner mode) ----------
   Ticking an affix reveals its value box: a checkbox alone would throw away
   the range, which is the whole point of the roll table. */
.tt-plan { display: none; }
body.planner .tt-plan {
  display: block; border-top: 1px solid var(--tt-border);
  margin-top: .6rem; padding: .5rem .8rem .6rem;
}
/* the read-only roll list is redundant once the tick list replaces it */
body.planner .tt.plan .tt-roll-h, body.planner .tt.plan .tt-roll { display: none; }
.tt-plan .hdr {
  display: flex; justify-content: space-between; color: var(--gold);
  font-size: 12px; margin-bottom: .2rem;
}
.tt-plan .cnt { color: var(--dim); }
.tt-plan .cnt.full { color: var(--tt-green); }
/* min-height = the number input's height, so ticking a box (which swaps the
   range text for the input) cannot change the row height and nudge the grid */
.tt-plan .prow {
  display: flex; align-items: center; gap: .35rem; font-size: 12px;
  color: #b9a7e6; padding: .05rem 0; min-height: 24px;
}
.tt-plan .prow.off { opacity: .4; }
.tt-plan .prow.off label { cursor: not-allowed; }
.tt-plan .prow label {
  display: flex; align-items: center; gap: .35rem; flex: 1; min-width: 0;
  cursor: pointer;
}
.tt-plan .prow .nm { flex: 1; min-width: 0; }
.tt-plan .prow .rg { color: #8d8fa0; }
/* the legendary-effect tick's caveat: it is its own roll and costs no pick */
.tt-plan .fxnote { color: #8d8fa0; font-size: 12px; padding-bottom: .15rem; }
.tt-plan input[type=checkbox] { accent-color: var(--tt-border); margin: 0; }
.tt-plan input[type=number] {
  width: 68px; height: 20px; background: var(--tt-inner);
  border: 1px solid var(--tt-border);
  color: var(--text); font: 11px var(--gamefont); padding: 0 .25rem;
}
/* out-of-range entry snapped back to the limit: show the snap */
.tt-plan input.clamped { animation: clampflash .6s ease; }
@keyframes clampflash {
  /* the 88-alpha glow keeps a literal: a var() cannot carry the alpha */
  0%, 60% { border-color: var(--danger); box-shadow: 0 0 6px #e06c6c88; }
  100% { border-color: var(--tt-border); box-shadow: none; }
}
/* compare-with-verdict: candidate vs whatever holds the slot it would take */
.tt-vs {
  border-top: 1px dashed var(--tt-border); margin-top: .5rem; padding-top: .4rem;
  font-size: 12px; color: #8d8fa0; cursor: help; line-height: 1.4;
}
.tt-vs .up { color: var(--tt-green); }
.tt-vs .dn { color: var(--danger); }
.tt-vs .mix { color: var(--gold); }
.tt-vs .ev { color: var(--dim); }
.tt-vs .sub { color: #8b90a8; }
.tt-plan .acts { display: flex; gap: .4rem; margin-top: .5rem; }
.tt-plan .acts button {
  flex: 1; background: var(--panel2); border: 1px solid var(--tt-border);
  color: var(--text); font: .85rem var(--uifont); padding: .4rem; cursor: pointer;
}
.tt-plan .acts button:hover { border-color: #fff; }
.tt-plan .acts button.uneq { color: var(--dim); background: none; }

/* ---------- footer ----------
   Carries the two mandatory policy notices; their wording is fixed by
   Spiderware's policies and must be copied verbatim onto every page. */
footer {
  margin-top: 2.5rem; padding-top: 1.2rem; border-top: 1px solid var(--border);
  color: var(--dim); font-size: var(--fs-s); text-align: center;
  display: flex; flex-direction: column; gap: .5rem;
}
footer a { color: var(--accent); text-decoration: none; }
footer a:hover { text-decoration: underline; }
footer .credit strong { color: var(--text); font-weight: 600; }
/* was two off-token greys (#7a7f94/#666b80); mapped to --dim 2026-08-07 */
footer .disclaimer { color: var(--dim); font-size: var(--fs-xs); max-width: 62ch; margin: 0 auto; }
footer .disclaimer .q { font-family: var(--gamefont); color: var(--dim); }
footer .notice { color: var(--dim); font-size: var(--fs-xs); max-width: 66ch; margin: 0 auto; }
footer .colophon { color: var(--dim); font-size: var(--fs-xs); }
