/*
 Ignite's Theme covers the semantic roles Bootstrap knows about (background,
 text, accent, links, type scale) — those live in Sources/Themes/SiteTheme.swift
 and are emitted as --bs-* variables. This file adds what the design uses and
 Bootstrap has no slot for: the tonal ramps, the stat-band ground, and the
 signature marks (fading rules, tags, labels, tabular numbers).

 Class names are `n-` prefixed so nothing here collides with Bootstrap's own
 .card, .btn, .nav, or .table.
*/

/* ──────────────────────────────────────────────────────────────────────────
   Themes

   Ignite stamps the active theme onto <html> as data-bs-theme, using an id it
   derives from the Swift type name: GoblinTheme → "goblin-light",
   MimicTheme → "mimic-dark". Every color below is a token, and every rule
   further down the file refers to tokens only, so a theme is nothing more than
   one of these blocks. Renaming either Swift type breaks these selectors.

   Goblin is also the :root default, which covers the moment before the theme
   script runs and any page rendered without the attribute.
   ────────────────────────────────────────────────────────────────────────── */

/* — Goblin: greens on a slate ground — */
:root,
[data-bs-theme="goblin-light"] {
  /* The green ramp, dark to light. Four steps come from the source palette —
     700 pine, 500 moss, 300 sage, and the 900 slate ground; the rest are
     extrapolated to fill the gaps and give the tints text can sit on. */
  --n-accent-900: #1c2b25;
  --n-accent-800: #22443a;
  --n-accent-700: #2b5748; /* pine */
  --n-accent-600: #3d6b56;
  --n-accent-500: #618764; /* moss */
  --n-accent-400: #7d9c73;
  --n-accent-300: #9cb080; /* sage */
  --n-accent-200: #b8c89f;
  --n-accent-100: #d6e0c4;
  --n-accent-50:  #eef3e6;

  /* Neutrals, tinted toward the ramp's hue so nothing reads cold against the
     green ground. 900 is the palette's slate, #273338. */
  --n-neutral-100: #eef2ea;
  --n-neutral-200: #dde3d7;
  --n-neutral-300: #cbd6c2;
  --n-neutral-400: #b0bda6;
  --n-neutral-500: #94a28c;
  --n-neutral-600: #74806e;
  --n-neutral-700: #4f5d55;
  --n-neutral-800: #3a4741;
  --n-neutral-900: #273338;
}

/* — Mimic: purples — */
[data-bs-theme="mimic-dark"] {
  /* The eight-step purple ramp. The two lightest steps are extrapolated
     tints; the source palette stops at #e0aaff. */
  --n-accent-900: #10002b;
  --n-accent-800: #240046;
  --n-accent-700: #3c096c;
  --n-accent-600: #5a189a;
  --n-accent-500: #7b2cbf;
  --n-accent-400: #9d4edd;
  --n-accent-300: #c77dff;
  --n-accent-200: #e0aaff;
  --n-accent-100: #efd6ff;
  --n-accent-50:  #f7ebff;

  --n-neutral-100: #f2ecf8;
  --n-neutral-200: #e3d9ef;
  --n-neutral-300: #d3c6e6;
  --n-neutral-400: #bcabd6;
  --n-neutral-500: #a495bd;
  --n-neutral-600: #86779f;
  --n-neutral-700: #665a7c;
  --n-neutral-800: #453c5c;
  --n-neutral-900: #2b2340;
}

/* Everything below is theme-independent: it either references the tokens above
   or describes shape rather than color. */

:root {
  /* Both themes are dark, so browser chrome — scrollbars, form controls — is
     dark in both. */
  color-scheme: dark;

  --n-divider: color-mix(in srgb, var(--n-accent-600) 55%, transparent);

  --n-space-1: 2.8px;
  --n-space-2: 5.6px;
  --n-space-3: 8.4px;
  --n-space-4: 11.2px;
  --n-space-6: 16.8px;
  --n-space-8: 22.4px;

  --n-radius-sm: 4px;
  --n-radius-md: 8px;
  --n-radius-lg: 14px;

  /* Elevation on a dark ground: a hairline edge plus ambient darkness. */
  --n-shadow-sm: 0 0 0 1px var(--n-accent-800);
  --n-shadow-md: 0 0 0 1px var(--n-accent-700), 0 6px 18px rgb(0 0 0 / 55%);
  --n-shadow-lg: 0 0 0 1px var(--n-accent-600), 0 16px 40px rgb(0 0 0 / 65%);
}

h1, h2, h3, h4, h5, h6 { letter-spacing: -0.015em; }
h6 { letter-spacing: 0.08em; text-transform: uppercase; }

a { text-underline-offset: 3px; }
::selection { background: color-mix(in srgb, var(--n-accent-300) 30%, transparent); }
:focus-visible { outline: 2px solid var(--n-accent-300); outline-offset: 2px; }

/* Rules fade to transparent at both ends — the design's signature. The ramp is
   48px an end. Freestanding rules fade; box outlines stay solid. */
.n-rule {
  height: 1px; border: 0; margin: var(--n-space-4) 0;
  background: linear-gradient(to right,
    transparent, var(--n-divider) 48px,
    var(--n-divider) calc(100% - 48px), transparent);
}

/* Small uppercase label, used for stat names and section kickers. */
.n-label {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--n-neutral-500);
}

/* Kicker: the accent-colored label above a title. */
.n-kicker {
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--n-accent-300);
}

/* Stat values line up in columns, so they need tabular figures. */
.n-num { font-variant-numeric: tabular-nums; }

.n-muted { color: color-mix(in srgb, var(--bs-body-color) 55%, transparent); }

/* Text tones, as classes rather than inline colors, so they follow the theme. */
.n-text-secondary { color: var(--n-neutral-300); }
.n-text-tertiary { color: var(--n-neutral-500); }
.n-brand-dot { color: var(--n-accent-300); }

.n-tag {
  display: inline-flex; align-items: center; font-size: 11px;
  letter-spacing: 0.02em; padding: 3px 10px;
  border-radius: calc(var(--n-radius-md) * 0.75);
}
/* Both fills sit two or more steps below the tint they carry — moss is too
   light to hold 11px text at AA. */
.n-tag-accent { background: var(--n-accent-700); color: var(--n-accent-50); }
.n-tag-solid { background: var(--n-accent-600); color: var(--n-accent-50); }
.n-tag-neutral { background: var(--n-neutral-800); color: var(--n-neutral-100); }
.n-tag-outline { border: 1px solid var(--n-accent-300); color: var(--n-accent-300); }

/* A tag that can be picked. Unselected it reads as a neutral tag; selected it
   takes the accent outline, driven by aria-pressed so the styling and the
   accessible state can't drift apart. Ignite's Button brings Bootstrap's .btn,
   hence the reset. */
.n-pill-toggle.btn {
  font-size: 11px; letter-spacing: 0.02em; line-height: inherit;
  padding: 3px 10px;
  border: 1px solid transparent; border-radius: calc(var(--n-radius-md) * 0.75);
  background: var(--n-neutral-800); color: var(--n-neutral-100);
}
.n-pill-toggle.btn:hover { border-color: var(--n-accent-400); }

/* Options with nothing behind them: still readable, clearly not clickable. */
.n-pill-toggle.btn:disabled,
.n-letter.btn:disabled {
  opacity: 0.35;
  cursor: default;
}
.n-pill-toggle.btn:disabled:hover { border-color: transparent; }
.n-letter.btn:disabled:hover { color: var(--n-neutral-500); }
/* How the filter hides things. A class rather than the `hidden` attribute,
   because Swift renders the initially-over-limit cards with it too; !important
   because .n-card sets display:flex and would otherwise win. */
.n-hidden { display: none !important; }

.n-filter-empty { font-size: 13px; }

/* — long-form pages —
   Prose gets a measure it can be read at, rather than running the full shell. */
.n-prose {
  display: flex; flex-direction: column;
  gap: var(--n-space-8);
  max-width: 68ch;
}
.n-prose p { max-width: 68ch; }
/* A Method section's body: the last paragraph or list shouldn't add space
   below it, since the sections are already spaced by .n-prose's gap. */
.n-method-body > :last-child { margin-bottom: 0; }
.n-method-body li + li { margin-top: 4px; }

/* Long-form pages that run the full shell width, matching their header. */
.n-prose-wide, .n-prose-wide p { max-width: none; }
/* — footer — */
.n-footer { padding-block: 0 32px; }
.n-footer-row {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--n-space-4) var(--n-space-8);
  padding-top: var(--n-space-4);
}
/* Notices run the full width, stacked one per source, set off from the credit
   row above by a small gap. */
.n-footer-notices {
  display: flex; flex-direction: column;
  gap: var(--n-space-3);
  margin-top: var(--n-space-6);
}
.n-footer-notices a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.n-footer-notices a:hover { color: var(--bs-link-color); }
.n-footer-links { display: flex; gap: var(--n-space-6); font-size: 13px; }
.n-footer-links a { color: var(--n-neutral-400); text-decoration: none; }
.n-footer-links a:hover { color: var(--bs-body-color); }

.n-pill-toggle.btn[aria-pressed="true"] {
  background: transparent;
  border-color: var(--n-accent-300);
  color: var(--n-accent-300);
}

.n-surface {
  background: var(--bs-secondary-bg);
  border-radius: var(--n-radius-md);
  padding: var(--n-space-8);
}
.n-elev-sm { box-shadow: var(--n-shadow-sm); }
.n-elev-md { box-shadow: var(--n-shadow-md); }
.n-elev-lg { box-shadow: var(--n-shadow-lg); }

/* ══════════════════════════════════════════════════════════════════════════
   Layout & components

   The page is a fixed-width shell with full-bleed bands inside it, so Body
   drops Bootstrap's .container (see MainLayout) and widths are managed here.
   Everything collapses to one column on narrow screens.
   ══════════════════════════════════════════════════════════════════════ */

.n-shell { width: 100%; max-width: 1120px; margin: 0 auto; }

/* Horizontal gutter, shared by every band so their content lines up. */
.n-pad { padding-inline: 32px; }

/* — nav — */
.n-nav {
  display: flex; align-items: center; gap: var(--n-space-8);
  padding-block: 14px;
  border-bottom: 1px solid var(--n-divider);
}
.n-nav-brand { font-weight: 600; font-size: 16px; letter-spacing: -0.01em; }
.n-nav-links { display: flex; gap: var(--n-space-6); font-size: 13px; }
.n-nav-links a { color: var(--n-neutral-400); text-decoration: none; }
.n-nav-links a:hover { color: var(--bs-body-color); }
.n-spacer { flex: 1; }

/* — buttons — */
.n-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  font-weight: 500; font-size: 14px; line-height: 1.2;
  color: var(--bs-body-color); background: transparent;
  border: 1px solid transparent;
  padding: var(--n-space-2) calc(var(--n-space-3) * 1.2);
  border-radius: var(--n-radius-md);
}
.n-btn-primary { color: var(--n-accent-300); border-color: var(--n-accent-500); }
.n-btn-primary:hover {
  color: var(--n-accent-200);
  background: color-mix(in srgb, var(--n-accent-400) 18%, transparent);
}
.n-btn-secondary { border-color: var(--n-divider); color: var(--bs-body-color); }
.n-btn-secondary:hover { background: color-mix(in srgb, var(--n-accent-400) 12%, transparent); }
.n-btn-ghost { color: var(--n-accent-300); padding-inline: var(--n-space-1); }
.n-btn-ghost:hover { color: var(--n-accent-200); }
.n-btn-block { width: 100%; margin-top: var(--n-space-2); }
.n-btn-lg { font-size: 15px; padding: var(--n-space-4) var(--n-space-6); }

/* — inputs — */
.n-input {
  width: 100%; min-height: 36px; padding: 6px 10px;
  font: inherit; font-size: 14px;
  color: var(--bs-body-color); caret-color: var(--n-accent-300);
  background: var(--n-accent-800);
  border: 1px solid var(--n-divider); border-radius: var(--n-radius-md);
}
.n-input::placeholder { color: var(--n-neutral-600); }
.n-input:hover { border-color: var(--n-accent-500); }

/* A filter menu with something chosen reads like a pressed pill. */
select.n-input[data-selected] { border-color: var(--n-accent-300); color: var(--n-accent-300); }
.n-input:focus-visible { border-color: var(--n-accent-300); outline-offset: 0; }

/* — cards — */
.n-card {
  display: flex; flex-direction: column; gap: var(--n-space-2);
  padding: var(--n-space-4);
  border-radius: var(--n-radius-md);
  background: var(--bs-secondary-bg);
  box-shadow: var(--n-shadow-sm);
  position: relative;
}
.n-card:has(.n-card-link:hover) { box-shadow: 0 0 0 1px var(--n-accent-500), var(--n-shadow-sm); }
.n-card-title { font-weight: 500; font-size: 17px; line-height: 1.2; }
/* The title link covers the card, so the whole card opens the conversion. */
.n-card-link { color: inherit; text-decoration: none; }
.n-card-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.n-card-link:focus-visible { outline: none; }
.n-card:has(.n-card-link:focus-visible) { outline: 2px solid var(--n-accent-300); outline-offset: 2px; }
.n-card-body { margin: 0; font-size: 13px; color: var(--n-neutral-300); flex: 1; }
.n-card-meta {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; color: var(--n-neutral-500);
}

/* — grids —
   Every grid drops to a single column at the same breakpoint so the page
   reflows as one piece rather than in stages. */
.n-grid-2, .n-grid-3, .n-grid-4, .n-hero, .n-bestiary {
  display: grid; gap: var(--n-space-8);
}
.n-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.n-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--n-space-4); }
.n-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--n-space-6); }
.n-hero { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); align-items: end; }

/* The figures hang from the top of the hero, level with the kicker, with the
   rule closing them off underneath — the dead space belongs below them. */
.n-hero-aside { align-self: start; }
.n-bestiary { grid-template-columns: 200px minmax(0, 1fr); }

@media (max-width: 860px) {
  .n-grid-2, .n-grid-3, .n-grid-4, .n-hero, .n-bestiary {
    grid-template-columns: minmax(0, 1fr);
  }
  .n-pad { padding-inline: 20px; }

  /* The nav becomes two rows: brand and palette switch on the first, section
     links on their own below. The switch is a site-wide setting, so it reads
     better beside the brand than as a fourth item under the links. */
  .n-nav { flex-wrap: wrap; row-gap: var(--n-space-3); gap: var(--n-space-4); }
  .n-nav-brand { order: 1; margin-right: auto; }
  .n-theme-toggle { order: 2; }
  .n-nav-links { order: 3; flex-basis: 100%; }
  .n-spacer { display: none; }
}

/* — stat rows —
   Label left, value right, with a hairline between rows. Used by both halves
   of a side-by-side statblock, so the two columns stay on the same baseline. */
.n-row {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--n-space-4); align-items: baseline;
  padding: 5px 0;
}
.n-row + .n-row { border-top: 1px solid color-mix(in srgb, var(--bs-body-color) 8%, transparent); }
.n-row-was .n-num { color: var(--n-neutral-500); }

/* The 5e ability scores under the source column, dimmed like its rows. */
.n-abilities {
  display: grid; grid-template-columns: auto repeat(3, 1fr);
  gap: 4px var(--n-space-4); align-items: baseline;
  margin-top: var(--n-space-4); padding-top: var(--n-space-4);
  border-top: 1px solid color-mix(in srgb, var(--bs-body-color) 8%, transparent);
}
.n-abilities > :nth-child(4n + 2), .n-abilities > :nth-child(4n + 3), .n-abilities > :nth-child(4n) { text-align: right; }
.n-abilities .n-num { color: var(--n-neutral-500); }
.n-abilities .n-ability-proficient { color: var(--bs-body-color); }

/* Immunities, senses, languages: set off from the scores the same way. */
.n-stat-details {
  margin-top: var(--n-space-4); padding-top: var(--n-space-4);
  border-top: 1px solid color-mix(in srgb, var(--bs-body-color) 8%, transparent);
}

/* The Daggerheart half of a comparison, marked off by an accent edge. */
.n-column-new { border-left: 1px solid var(--n-accent-600); padding-left: var(--n-space-6); }
@media (max-width: 860px) {
  .n-column-new { border-left: 0; border-top: 1px solid var(--n-accent-600); padding-left: 0; padding-top: var(--n-space-6); }
}

/* A full comparison's four cells: 5e and Daggerheart numbers, a rule, then
   5e and Daggerheart features. Side by side they form two aligned rows. */
.n-statblock-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  column-gap: var(--n-space-6);
}
.n-statblock-grid > .n-rule { grid-column: 1 / -1; }

/* Stacked, each side stays together: 5e numbers and features, then the
   Daggerheart numbers and features under one accent rule. */
@media (max-width: 860px) {
  .n-statblock-grid { grid-template-columns: 1fr; row-gap: var(--n-space-6); }
  .n-statblock-grid > .n-rule { display: none; }
  .n-sb-old-stats { order: 1; }
  .n-sb-old-features { order: 2; }
  .n-sb-new-stats { order: 3; }
  .n-sb-new-features { order: 4; border-top: 0; padding-top: 0; }
}

/* Phone widths. "Color Theme:" is what pushes the first nav row over — the two
   named buttons carry the meaning on their own, and dropping the label keeps
   the header at two rows instead of three. */
@media (max-width: 520px) {
  .n-theme-toggle .n-label { display: none; }
}

/* — feature list (adversary actions) — */
.n-features { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.n-feature-name { color: var(--n-accent-300); }
.n-feature-kind { color: var(--n-neutral-500); }
.n-feature-text { color: var(--n-neutral-300); }
/* 5e entries: the name keeps the accent so it's as easy to find as a
   Daggerheart feature's, in the SRD's italic; the text is dimmed like the 5e
   numbers so the Daggerheart side still reads as the answer. */
.n-feature-was .n-feature-name { font-style: italic; }
.n-feature-was .n-feature-text { color: var(--n-neutral-500); }
.n-feature-groups { display: flex; flex-direction: column; gap: var(--n-space-6); }
/* An environment's description reads like a Daggerheart statblock's: italic. */
.n-environment-description { font-style: italic; }

/* Difficulty, impulses, adversaries: one row of label-over-value cells.
   Difficulty is a number, so it takes only what it needs; the two text
   fields share the rest, and everything stacks on a phone. */
.n-environment-stats {
  display: grid; grid-template-columns: auto 1fr 1fr;
  gap: var(--n-space-4) var(--n-space-8);
  margin-top: var(--n-space-4);
}
.n-environment-stats > * > * { display: block; }
.n-environment-stats .n-label { margin-bottom: 4px; }
.n-environment-difficulty { font-size: 22px; line-height: 1.1; }
@media (max-width: 860px) {
  .n-environment-stats { grid-template-columns: 1fr; }
}

/* Rules for a whole 5e list, under its heading: dimmed like the entries. */
.n-feature-intro { margin: 8px 0 0; font-size: 13px; color: var(--n-neutral-500); }
/* A paragraph break inside a feature's text, which is inline after its name. */
.n-feature-break { display: block; height: 6px; }

/* — segmented control —
   One control made of adjoining options, currently just the theme toggle. The
   filter rail used to use it too, before tier became individual pills. */
.n-seg {
  display: inline-flex; width: max-content; overflow: hidden;
  border: 1px solid var(--n-divider); border-radius: var(--n-radius-md);
}

/* — theme toggle —
   Ignite's Button always carries Bootstrap's .btn, so the first rule strips it
   back to a plain segment. Which option reads as selected comes from the
   data-bs-theme attribute the theme script sets, so the markup needs no state
   and the highlight is correct on the very first paint. */
.n-theme-toggle { display: flex; align-items: center; gap: var(--n-space-3); }
.n-theme-toggle .n-label { white-space: nowrap; }
.n-theme-option.btn {
  padding: 7px 12px; font-size: 13px; line-height: 1.2;
  color: var(--n-neutral-400); background: transparent;
  border: 0; box-shadow: none; border-radius: 0;
}

/* End segments follow the container's inner curve, so a selected fill meets
   the border instead of being sliced square by the overflow clip. Declared
   after the .btn reset above, which zeroes all four corners first. */
.n-seg > :first-child {
  border-start-start-radius: calc(var(--n-radius-md) - 1px);
  border-end-start-radius: calc(var(--n-radius-md) - 1px);
}
.n-seg > :last-child {
  border-start-end-radius: calc(var(--n-radius-md) - 1px);
  border-end-end-radius: calc(var(--n-radius-md) - 1px);
}
.n-theme-option + .n-theme-option { border-left: 1px solid var(--n-divider); }
.n-theme-option.btn:hover { color: var(--bs-body-color); }

[data-bs-theme="mimic-dark"] .n-theme-mimic.btn,
[data-bs-theme="goblin-light"] .n-theme-goblin.btn {
  color: var(--n-accent-200);
  background: color-mix(in srgb, var(--n-accent-400) 22%, transparent);
}

/* — alphabet index — */
.n-alphabet {
  display: flex; flex-wrap: wrap; gap: 4px 8px;
  font-size: 12px;
}

/* Letters are buttons, but drawn as plain text — 26 tags would swamp the rail.
   Hence the reset of Bootstrap's .btn. */
.n-letter.btn {
  padding: 0 2px; font-size: 12px; line-height: 1.4;
  color: var(--n-neutral-500); background: transparent;
  border: 0; border-radius: var(--n-radius-sm);
}
.n-letter.btn:hover { color: var(--bs-body-color); }
.n-letter.btn[aria-pressed="true"] {
  color: var(--n-accent-200);
  background: color-mix(in srgb, var(--n-accent-400) 22%, transparent);
}

/* A headline number over its caption. */
.n-stat > * { display: block; }
.n-stat .n-num { line-height: 1.15; }

/* — small arrangements —
   Rows of buttons and rows of tags wrap rather than overflow. */
.n-btn-row { display: flex; flex-wrap: wrap; gap: var(--n-space-4); }
.n-pill-row { display: flex; flex-wrap: wrap; gap: var(--n-space-2); }

/* A section heading with its trailing link pushed to the far edge. */
.n-section-head {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 12px; margin-bottom: var(--n-space-6);
}

/* The inset panel a statblock sits in — one step darker than its card. */
.n-panel {
  background: var(--bs-body-bg);
  border-radius: var(--n-radius-md);
  padding: var(--n-space-6);
  box-shadow: var(--n-shadow-sm);
}

.n-filters { display: flex; flex-direction: column; gap: var(--n-space-6); }
.n-recent { display: flex; flex-direction: column; gap: var(--n-space-6); align-items: flex-start; }
.n-recent .n-grid-3 { width: 100%; }
