/* Styles for the static guide pages.
 *
 * These pages are plain HTML in public/, not part of the React app: search
 * engines get the full article in the first response with no JavaScript, which
 * is the whole point of them existing separately. Keep them dependency-free —
 * no framework, no build step, no webfont that blocks the first paint.
 *
 * Palette and type follow brand/README.md. */

/*
  Cinzel, the display face the app uses.

  These pages named it in every heading rule and never loaded it, so every
  serif heading on the site was falling back to Times New Roman — which is most
  of why the guides read as a different, older product than the planner they
  belong to. Imported here rather than added to seven page generators; each of
  them already links this one stylesheet.
*/
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@500;600;700&display=swap');

/*
  One palette, shared with the app.

  The values below are src/index.css verbatim. These pages had grown their own
  set — a brighter gold, a blue-tinted border, a warmer body colour — so the
  planner and the guides were visibly different products sitting on the same
  domain. The old names are kept as aliases so existing rules still read
  naturally; they now resolve to the app's colours.
*/
:root {
  --bg: #06080f;
  --bg-panel: rgba(13, 17, 28, 0.94);
  --bg-panel-2: rgba(19, 24, 38, 0.92);
  --border: #232a3a;
  --border-light: #38445e;
  --border-gold: #6b5518;
  --gold-soft: rgba(212, 175, 55, 0.4);
  --text: #e2e2d8;
  --text-dim: #909aad;
  --gold: #e8b93d;
  --gold-deep: #a8780c;
  --accent: #4fa8ff;
  --danger: #e25555;
  --font: 'Segoe UI', system-ui, sans-serif;
  --font-display: 'Cinzel', 'Times New Roman', serif;

  /* Names these pages were written against. */
  --gold-light: #ffe9a8;
  --void: var(--bg);
  --abyss: #0b0f1a;
  --panel: var(--bg-panel);
  --line: var(--border);
  --parch: var(--text);
  --dim: var(--text-dim);
  --frost: var(--accent);
  --em: #2fbf8f;
  --ember: var(--danger);
  --arcane: #8b5cf6;
}

* {
  box-sizing: border-box;
}

/* The filter hides rows by setting the `hidden` attribute, which the UA style
   sheet turns into `display: none` — at the very bottom of the cascade. Any
   element with its own `display` beats it, so `.tk { display: grid }` left
   every filtered-out trinket on screen while the counter read "40 of 82".
   Nothing looked broken; it just did nothing. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--parch);
  font: 16.5px/1.65 var(--font);
  -webkit-text-size-adjust: 100%;
  /* `clip`, not `hidden`: it stops a talent tooltip near the edge from adding a
     horizontal scrollbar without turning the body into a scroll container (which
     would break position: sticky and anchor scrolling). */
  overflow-x: clip;
}

/* --- chrome ---------------------------------------------------------------- */

.top {
  border-bottom: 1px solid var(--line);
  background: rgba(6, 8, 15, 0.9);
  position: sticky;
  top: 0;
  z-index: 10;
  backdrop-filter: blur(8px);
}

.top-in,
.wrap,
.foot-in {
  max-width: 760px;
  margin: 0 auto;
  padding: 0 22px;
}

.top-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 58px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--parch);
  font-weight: 700;
  letter-spacing: 0.01em;
}

.brand img {
  width: 26px;
  height: 26px;
}

.brand b {
  color: var(--gold);
}

.cta {
  background: var(--gold);
  color: #11141d;
  text-decoration: none;
  font-weight: 700;
  font-size: 14px;
  padding: 8px 15px;
  border-radius: 7px;
  white-space: nowrap;
}

.cta:hover {
  background: var(--gold-light);
}

/* --- article --------------------------------------------------------------- */

.wrap {
  padding-top: 40px;
  padding-bottom: 72px;
}

.crumbs {
  font-size: 13px;
  color: var(--dim);
  margin-bottom: 20px;
}

.crumbs a {
  color: var(--dim);
}

h1 {
  font-family: var(--font-display);
  font-size: clamp(30px, 5.4vw, 44px);
  line-height: 1.1;
  margin: 0 0 14px;
  letter-spacing: 0.005em;
}

h1 .g {
  color: var(--gold);
}

.standfirst {
  font-size: 20px;
  line-height: 1.55;
  color: var(--dim);
  margin: 0 0 10px;
}

.byline {
  font-size: 13px;
  color: var(--dim);
  border-bottom: 1px solid var(--line);
  padding-bottom: 22px;
  margin-bottom: 34px;
}

h2 {
  font-family: var(--font-display);
  font-size: 27px;
  line-height: 1.25;
  margin: 46px 0 14px;
  color: var(--gold);
  scroll-margin-top: 74px;
}

h3 {
  font-size: 19px;
  margin: 30px 0 10px;
  color: var(--parch);
}

p {
  margin: 0 0 18px;
}

a {
  color: var(--gold);
}

ul,
ol {
  margin: 0 0 18px;
  padding-left: 22px;
}

li {
  margin-bottom: 9px;
}

strong {
  color: var(--gold-light);
}

code {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 0.9em;
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 5px;
}

/* Answer box — the short answer, right under the question, for people who
   arrived from a search and want it in one sentence. */
.answer {
  background: linear-gradient(180deg, rgba(232, 185, 61, 0.11), rgba(232, 185, 61, 0.04));
  border: 1px solid rgba(232, 185, 61, 0.32);
  border-radius: 11px;
  padding: 19px 22px;
  margin: 0 0 32px;
}

.answer b {
  display: block;
  color: var(--gold);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  margin-bottom: 7px;
}

.answer p:last-child {
  margin-bottom: 0;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 18px 22px;
  margin: 0 0 26px;
}

.panel h3 {
  margin-top: 0;
}

.panel p:last-child,
.panel ul:last-child {
  margin-bottom: 0;
}

.warn {
  border-left: 3px solid var(--ember);
  background: rgba(226, 85, 85, 0.08);
}

.good {
  border-left: 3px solid var(--em);
  background: rgba(47, 191, 143, 0.08);
}

figure {
  margin: 30px 0;
}

figure svg {
  display: block;
  width: 100%;
  height: auto;
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 11px;
}

figcaption {
  font-size: 13.5px;
  color: var(--dim);
  margin-top: 10px;
  line-height: 1.5;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 26px;
  font-size: 15px;
}

th,
td {
  text-align: left;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
}

th {
  color: var(--dim);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* Table of contents */
.toc {
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 16px 22px;
  margin-bottom: 38px;
}

.toc b {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--dim);
}

.toc ol {
  margin: 10px 0 0;
  padding-left: 20px;
  font-size: 15.5px;
}

.toc li {
  margin-bottom: 5px;
}

/* FAQ */
.faq {
  border-top: 1px solid var(--line);
  padding-top: 8px;
}

.faq h3 {
  font-size: 17.5px;
  margin: 22px 0 8px;
}

/* Cards on the hub page */
/* ── reference cards ───────────────────────────────────────────────────────
   Each entry carries the game's own icon for what it is: a coin for bonus
   rolls, a rune for crests, a blade for damage. A column of identical
   text blocks made seven different tools look like seven paragraphs. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 14px;
  margin-bottom: 40px;
}

.card {
  display: grid;
  grid-template-columns: 44px 1fr;
  grid-template-rows: auto auto;
  column-gap: 14px;
  row-gap: 2px;
  align-content: start;
  padding: 18px 20px 20px;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 13px;
  background:
    radial-gradient(ellipse 70% 50% at 0% 0%, rgba(232, 185, 61, 0.07), transparent 70%),
    var(--bg-panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), 0 14px 30px -24px rgba(0, 0, 0, 0.9);
  transition: border-color .14s, transform .14s;
}

.card:hover {
  border-color: var(--border-gold);
  transform: translateY(-2px);
}

/* The icon spans both header rows so the kicker and title sit beside it. */
.card-icon {
  grid-row: 1 / span 2;
  width: 44px;
  height: 44px;
  border-radius: 9px;
  border: 1px solid var(--border-light);
  background: var(--bg-panel-2);
}

.card:hover .card-icon { border-color: var(--gold); }

.card h2 {
  grid-column: 2;
  font-family: var(--font-display);
  font-size: 17.5px;
  line-height: 1.25;
  margin: 0;
  color: var(--gold);
  text-wrap: balance;
}

.card p {
  grid-column: 1 / -1;
  margin: 10px 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--dim);
  text-wrap: pretty;
}

.card .kicker {
  grid-column: 2;
  margin: 0;
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.kicker {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--gold-deep);
  margin-bottom: 8px;
}

/* --- footer ---------------------------------------------------------------- */

.foot {
  border-top: 1px solid var(--line);
  padding: 26px 0 44px;
  font-size: 13.5px;
  color: var(--dim);
}

.foot-in {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  justify-content: space-between;
}

.foot a {
  color: var(--dim);
  margin-right: 15px;
}

.foot a:hover {
  color: var(--gold);
}

@media (max-width: 560px) {
  body {
    font-size: 16px;
  }
  .standfirst {
    font-size: 18px;
  }
  h2 {
    font-size: 23px;
  }
}

/* ── data tables ───────────────────────────────────────────────────────────
   The overview pages are a tool, not an article: dense rows, filter chips,
   sortable headers. Wider than the prose column, because a table squeezed
   into 760px is a table nobody reads. */

.wide {
  max-width: 1180px;
}

.toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin: 0 0 18px;
}

.toolbar input[type='search'] {
  flex: 1 1 240px;
  min-width: 180px;
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 13px;
  color: var(--parch);
  font: inherit;
  font-size: 14.5px;
}

.toolbar input[type='search']:focus {
  outline: none;
  border-color: var(--gold);
}

.chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.chip {
  cursor: pointer;
  user-select: none;
  padding: 6px 12px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: var(--abyss);
  color: var(--dim);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
}

.chip:hover {
  border-color: var(--gold);
  color: var(--parch);
}

.chip.on {
  background: var(--gold);
  border-color: var(--gold);
  color: #11141d;
}

.tally {
  color: var(--dim);
  font-size: 13px;
  white-space: nowrap;
}

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

table.data th {
  text-align: left;
  color: var(--dim);
  font-size: 11px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

table.data th[data-sort] {
  cursor: pointer;
  user-select: none;
}

table.data th[data-sort]:hover {
  color: var(--gold);
}

table.data th[data-sort]::after {
  content: '↕';
  opacity: 0.3;
  margin-left: 5px;
  font-size: 10px;
}

table.data th.sorted-desc::after {
  content: '↓';
  opacity: 1;
  color: var(--gold);
}

table.data th.sorted-asc::after {
  content: '↑';
  opacity: 1;
  color: var(--gold);
}

table.data td {
  padding: 7px 10px;
  border-bottom: 1px solid #161f33;
  vertical-align: middle;
}

table.data tr.alt td {
  background: rgba(255, 255, 255, 0.014);
}

table.data tr:hover td {
  background: rgba(232, 185, 61, 0.05);
}

table.data a {
  text-decoration: none;
  font-weight: 600;
}

table.data a:hover {
  text-decoration: underline;
}

.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.rank {
  color: var(--dim);
  text-align: right;
  font-variant-numeric: tabular-nums;
  width: 34px;
}

/* Inline proportional bar inside a table cell. */
.minibar {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold));
  margin-top: 3px;
}

.role-tag {
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dim);
}

.none-shown {
  color: var(--dim);
  font-style: italic;
  padding: 20px 4px;
}

@media (max-width: 720px) {
  table.data .hide-sm {
    display: none;
  }
  table.data th,
  table.data td {
    padding: 7px 6px;
  }
}

/* ── spec switcher ─────────────────────────────────────────────────────────
   Collapsed by default: it is navigation, not content, and 27 links above the
   headline would bury the page you actually opened. */

.spec-switch {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--abyss);
  margin: 0 0 26px;
}

.spec-switch summary {
  cursor: pointer;
  padding: 10px 16px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--dim);
  list-style: none;
  user-select: none;
}

.spec-switch summary::-webkit-details-marker {
  display: none;
}

.spec-switch summary::before {
  content: '▸';
  margin-right: 8px;
  color: var(--gold);
}

.spec-switch[open] summary::before {
  content: '▾';
}

.spec-switch summary:hover {
  color: var(--parch);
}

.switch-body {
  padding: 4px 16px 14px;
  border-top: 1px solid var(--line);
}

.switch-row {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 10px;
  align-items: baseline;
  padding: 5px 0;
}

.switch-row b {
  font-size: 12.5px;
  white-space: nowrap;
}

.switch-row a {
  display: inline-block;
  padding: 3px 9px;
  margin: 2px 4px 2px 0;
  border-radius: 6px;
  font-size: 13px;
  text-decoration: none;
  color: var(--parch);
  background: var(--panel);
  border: 1px solid var(--line);
}

.switch-row a:hover {
  border-color: var(--gold);
}

@media (max-width: 560px) {
  .switch-row {
    grid-template-columns: 1fr;
    gap: 2px;
  }
}

/* ── rotation ──────────────────────────────────────────────────────────────
   The opener reads left to right like a bar; the sustained loop is a ranked
   list. Icons come from Wowhead's CDN by name. */

.rota-tabs {
  display: flex;
  gap: 6px;
  margin: 0 0 14px;
  flex-wrap: wrap;
}

.rota-strip {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  padding: 14px;
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 8px;
}

.spell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 58px;
  text-align: center;
}

.spell img {
  width: 42px;
  height: 42px;
  border-radius: 7px;
  border: 1px solid var(--border-light);
  background: #11141d;
  display: block;
}

.spell .step {
  position: absolute;
  top: -5px;
  left: 4px;
  background: var(--gold);
  color: #11141d;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  padding: 2px 5px;
  border-radius: 20px;
}

.spell small {
  font-size: 10px;
  line-height: 1.2;
  color: var(--dim);
  word-break: break-word;
}

.rota-arrow {
  color: #3a4a6b;
  font-size: 15px;
  align-self: flex-start;
  margin-top: 18px;
}

.loop-row {
  display: grid;
  grid-template-columns: 44px 1fr 74px 1fr;
  gap: 12px;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid #161f33;
  font-size: 14px;
}

.loop-row img {
  width: 34px;
  height: 34px;
  border-radius: 6px;
  border: 1px solid var(--border-light);
}

.loop-row .pct {
  text-align: right;
  color: var(--gold);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.loop-row .then {
  color: var(--dim);
  font-size: 12.5px;
}

/* ── stat donut ────────────────────────────────────────────────────────── */

.donut-wrap {
  display: flex;
  gap: 26px;
  align-items: center;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 20px 22px;
  margin-bottom: 26px;
}

.donut-key {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: 14px;
  min-width: 190px;
}

.donut-key div {
  display: flex;
  align-items: center;
  gap: 9px;
}

.donut-key i {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  flex: none;
}

.donut-key b {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--parch);
}

/* ── priority list ─────────────────────────────────────────────────────── */

.prio { counter-reset: prio; margin: 0 0 20px; }

.prio-step {
  display: grid;
  grid-template-columns: 30px 40px 1fr;
  gap: 12px;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid #161f33;
}

.prio-step:hover { background: rgba(232, 185, 61,.05); }

.prio-step .n {
  color: var(--gold);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  text-align: right;
  font-size: 14px;
}

.prio-step img {
  width: 36px; height: 36px; border-radius: 7px;
  border: 1px solid var(--border-light); background: #11141d;
}

.prio-step b { display: block; font-size: 15px; }

.prio-step .cond {
  display: block;
  color: var(--dim);
  font-size: 13px;
  margin-top: 1px;
}

/* Each step reads as an instruction: "Cast X when Y", with the abilities it
   names carrying their icons inline. */
.prio-say { font-size: 15px; line-height: 1.6; }

.sref {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  font-weight: 600;
  color: var(--gold);
}

.sref img {
  width: 18px; height: 18px;
  border-radius: 4px;
  border: 1px solid var(--border-light);
  vertical-align: middle;
}

/* A step whose condition is too tangled to state briefly. The label is the
   whole message: press this one by feel, not by rule. */
.prio-step .situational { color: var(--dim); font-style: normal; font-size: 13.5px; }

/* ── talent tree ───────────────────────────────────────────────────────── */

/* One tree per block, stacked, at every width. Three side by side only fit by
   breaking out of the article and shrinking each one, and a talent tree is
   read by following its lines — legibility beats fitting them all on screen. */
.tree-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin-bottom: 18px;
  /* No wider than the widest tree plus its padding. Left at full article width
     the boxes stand 700px wide around a 376px tree, which reads as three mostly
     empty panels. */
  max-width: calc(var(--twmax) * 1px + 30px);
  margin-inline: auto;
}

.tree-col {
  background: var(--abyss);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 14px;
  width: 100%;
  /* Deliberately not clipped: tooltips rise out of the top row and hang past
     the edge columns, and a scroll container would cut them off. */
  overflow: visible;
}

.tree-col h4 {
  margin: 0 0 10px;
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
}

/* Nodes are positioned absolutely on the game's own grid; the SVG underneath
   carries the connector lines. Everything is proportional — the canvas keeps
   its aspect ratio and the contents scale with it.

   The width does two jobs at once. The widest tree is drawn at its natural
   size (--twmax) or the space available, whichever is smaller, so nodes never
   scale up past the size they were designed at. Every other tree is then drawn
   at that same scale via its own --tw, which keeps a compact hero tree compact
   instead of stretching it to fill the block — and keeps every node in every
   tree exactly the same size. */
.tree-canvas {
  position: relative;
  width: calc(min(100%, var(--twmax) * 1px) * var(--tw) / var(--twmax));
  margin-inline: auto;
}
.tree-canvas > svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.tnode {
  position: absolute;
  width: var(--tnode);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid #212b40;
  background: #0b0e16 center/cover no-repeat;
  /* Unpicked nodes stay legible as shape but recede — the tree should read as
     a path taken through it, not as 40 equally-weighted icons. */
  filter: grayscale(1) brightness(.4);
  opacity: .55;
  cursor: default;
}

.tnode.on {
  filter: none;
  opacity: 1;
  border-color: #3d4c6d;
  cursor: help;
  box-shadow: 0 0 0 1px rgba(232, 185, 61,.18);
}

/* Square nodes are choice nodes in game; keep that tell. */
.tnode.choice { border-radius: 9px; }
.tnode.on.choice { border-color: var(--gold); }

.tnode .rk {
  position: absolute;
  right: -4px; bottom: -4px;
  background: #11141d;
  border: 1px solid var(--gold);
  color: var(--gold);
  border-radius: 20px;
  font-size: 9.5px;
  font-weight: 800;
  padding: 1px 4px;
  line-height: 1.25;
}

/* Tooltip. No JS: a positioned child revealed on hover and focus. */
.tnode .tip {
  position: absolute;
  bottom: calc(100% + 9px);
  left: 50%;
  transform: translateX(-50%);
  width: 250px;
  background: #070a12;
  border: 1px solid var(--gold);
  border-radius: 9px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--parch);
  /* `display: none` rather than hidden-but-present: a visibility-hidden tooltip
     still counts toward its container's scroll width, which put a scrollbar
     under every tree. */
  display: none;
  z-index: 40;
  pointer-events: none;
  text-align: left;
  box-shadow: 0 8px 26px rgba(0,0,0,.65);
}

.tnode:hover .tip, .tnode:focus-visible .tip { display: block; }
.tnode:hover, .tnode:focus-visible { z-index: 41; }
.tnode .tip b { color: var(--gold); display: block; margin-bottom: 3px; }
.tnode .tip i { color: var(--dim); font-style: normal; font-size: 11.5px; }

/* Copy the import string. One button, not a wall of base64. */
.import-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}

.copy-btn {
  background: var(--gold);
  color: #10131c;
  border: none;
  border-radius: 8px;
  padding: 9px 16px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
}

.copy-btn:hover { filter: brightness(1.08); }
.copy-btn.done { background: #4ade80; }
.copy-hint { color: var(--dim); font-size: 13px; }

/* ── best in slot, as the character pane ──────────────────────────────────
 *
 * Three columns: eight slots down the left, the spec in the middle, eight down
 * the right, icons outboard. It is the planner's own gear sheet, which is the
 * game's — someone checking a list is holding it against their character pane,
 * and a single column of cards makes them find each slot by reading the name.
 *
 * The previous version was two columns of cards that collapsed to one on any
 * narrow screen while keeping the right column's right-alignment, so half the
 * list sat flush right against nothing. */
.gs {
  display: grid;
  grid-template-columns: 1fr minmax(120px, 190px) 1fr;
  gap: 10px 18px;
  align-items: start;
  margin: 0 0 30px;
  /*
    Wider than the article it sits in.

    The prose column is 760px because that is a comfortable measure to read;
    this is not prose. Three columns of item name, source and enchant inside
    760px leaves about 185px per side, which wraps "The Venomous Abyss —
    Ula'tek" onto two lines in every slot. The sheet breaks out to its own
    width and centres itself — body has `overflow-x: clip`, so the negative
    margin cannot produce a scrollbar.
  */
  width: min(1040px, calc(100vw - 44px));
  margin-left: 50%;
  transform: translateX(-50%);
}

.gs-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.gs-slot {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 5px 7px;
  border-radius: 8px;
  min-width: 0;
}

.gs-slot:hover {
  background: var(--bg-panel-2);
}

/* The right column mirrors: text first, running inward toward the figure. */
.gs-r {
  flex-direction: row;
  text-align: right;
  justify-content: flex-end;
}

.gs-icon {
  flex: none;
  line-height: 0;
}

.gs-icon img {
  width: 44px;
  height: 44px;
  border-radius: 7px;
  border: 1px solid var(--border-light);
  background: var(--abyss);
}

.gs-icon-empty {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 7px;
  border: 1px dashed var(--line);
}

.gs-text { min-width: 0; }

.gs-name {
  display: block;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
}

.gs-name:hover { text-decoration: underline; }

.gs-sub {
  display: block;
  font-size: 11.5px;
  color: var(--dim);
}

.gs-ilvl {
  color: var(--gold);
  font-weight: 700;
}

.gs-src {
  display: block;
  font-size: 11.5px;
  color: var(--dim);
  opacity: 0.82;
}

/* Enchant green, gems blue — the colours the planner uses for the same two
   things, so the eye does not have to relearn them between the two. */
.gs-enh {
  display: block;
  font-size: 11px;
  line-height: 1.5;
}

.gs-ench { color: var(--em); }
.gs-gem { color: var(--frost); }
.gs-enh span + span { margin-left: 8px; }
.gs-r .gs-enh span + span { margin-left: 0; margin-right: 8px; }

.gs-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding-top: 26px;
  text-align: center;
}

.gs-crest {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 2px solid var(--border-gold);
  background: var(--abyss);
  margin-bottom: 8px;
}

.gs-spec {
  font-family: var(--font-display);
  font-size: 19px;
  color: var(--gold);
  line-height: 1.15;
}

.gs-cls {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
}

.gs-avg {
  margin-top: 10px;
  font-size: 11.5px;
  color: var(--dim);
}

/* What the fast variant moves, named before the sheet that contains it. */
.swap-list {
  list-style: none;
  padding: 0;
  margin: 0 0 24px;
  font-size: 15px;
}

.swap-list li {
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  margin: 0;
}

.swap-from { color: var(--dim); }

/*
  One column on a phone.

  The middle column goes first so the sheet still opens with what it is about,
  and the right-hand slots stop mirroring — mirroring only reads as mirroring
  when the pair it mirrors is beside it.
*/
@media (max-width: 720px) {
  .gs { grid-template-columns: 1fr; }
  .gs-mid { order: -1; padding-top: 0; }
  .gs-r { flex-direction: row; text-align: left; justify-content: flex-start; }
  .gs-r .gs-icon { order: -1; }
  .gs-r .gs-enh span + span { margin-left: 8px; margin-right: 0; }
}

/* ── reference link ────────────────────────────────────────────────────────
   Points at the encounter journal's ability text, which now lives on its own
   page. It used to sit inline at the bottom of every boss guide and ran longer
   than the guide itself — thirty spells of Blizzard's wording underneath advice
   whose whole purpose is not to be that. */
.ref-link {
  display: block;
  padding: 16px 20px;
  margin: 0 0 26px;
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold-deep);
  border-radius: 10px;
  text-decoration: none;
  color: inherit;
}

.ref-link:hover {
  border-color: var(--border-light);
  border-left-color: var(--gold);
}

.ref-kicker {
  display: block;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 4px;
}

.ref-title {
  display: block;
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--gold);
  margin-bottom: 3px;
}

.ref-note {
  display: block;
  font-size: 14px;
  color: var(--dim);
  line-height: 1.55;
}

/* How a number was arrived at, as a footnote rather than a section. It was a
   heading, two paragraphs and a warning panel — more words defending the chart
   than the chart itself contained. */
.method {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--dim);
  border-top: 1px solid var(--line);
  padding-top: 14px;
  margin: 26px 0 0;
}

/* ── boss cards ────────────────────────────────────────────────────────────
   A raid roster, not an article. Each boss shows its own face — the round
   Encounter Journal portrait — with its number, its drop count and a line of
   lore. The list before this was eight stacked paragraphs of identical shape,
   which made an eight-boss raid look like a table of contents. */
.boss-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(228px, 1fr));
  gap: 14px;
  margin: 0 0 40px;
}

.boss-card {
  position: relative;
  display: grid;
  grid-template-rows: auto auto auto 1fr;
  justify-items: center;
  text-align: center;
  gap: 8px;
  padding: 22px 16px 18px;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 14px;
  background:
    radial-gradient(ellipse 80% 55% at 50% 0%, rgba(232, 185, 61, 0.09), transparent 70%),
    var(--bg-panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035), 0 14px 30px -22px rgba(0, 0, 0, 0.9);
  transition: border-color .14s, transform .14s;
}

.boss-card:hover {
  border-color: var(--border-gold);
  transform: translateY(-2px);
}

/* The kill order, top-left, the way a journal numbers them. */
.boss-order {
  position: absolute;
  top: 10px;
  left: 12px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--gold-deep);
}

/* The journal portraits are 56px native, so anything larger is upscaled
   softness. 60 keeps them crisp and still reads as the card subject. */
.boss-face img,
.boss-face-blank {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--border-light);
  background: var(--bg-panel-2);
  display: block;
}

.boss-card:hover .boss-face img { border-color: var(--gold); }

.boss-name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--gold);
  text-wrap: balance;
}

.boss-stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--dim);
}

.boss-stats span {
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 2px 9px;
}

.boss-lore {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--dim);
  text-wrap: pretty;
}

/* ── priority list groups ──────────────────────────────────────────────────
   A rotation is a tree of lists, and flattening it without showing the joins
   produces one undifferentiated column of thirty casts. The heading names the
   branch and states the condition that reaches it once, instead of repeating
   that condition on every line inside it. */
.prio-group {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 22px 0 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}

.prio-group:first-child { margin-top: 4px; }

.prio-group-name {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
}

.prio-group-when {
  font-size: 13px;
  color: var(--dim);
}

/* ── opener ────────────────────────────────────────────────────────────────
   What to cast before the countdown ends, from the APL's precombat list. The
   section was previously waiting on sim cast sequences that were never
   collected, so every spec page simply had no opener at all. */
.opener {
  list-style: none;
  counter-reset: openstep;
  margin: 0 0 30px;
  padding: 0;
}

.open-step {
  display: grid;
  grid-template-columns: 26px 30px 1fr;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  margin: 0;
  border-bottom: 1px solid var(--line);
  counter-increment: openstep;
}

.open-step::before {
  content: counter(openstep);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  color: var(--gold);
  text-align: right;
}

.open-step img,
.open-noicon {
  width: 30px;
  height: 30px;
  border-radius: 6px;
  border: 1px solid var(--border-light);
  background: var(--bg-panel-2);
}

.open-body { font-size: 15px; }
.open-body b { color: var(--text); }

/* The timing is the part people came for — "2s before the pull". */
.open-at {
  display: inline-block;
  margin-left: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold);
  border: 1px solid var(--gold-soft);
  border-radius: 20px;
  padding: 1px 8px;
}

.open-when {
  display: block;
  font-size: 13px;
  color: var(--dim);
  margin-top: 1px;
}

/* ── how it plays ──────────────────────────────────────────────────────────
   Two or three sentences computed from the reference parse. Deliberately not
   hand-written character notes: 27 of those would be unverifiable, and the
   numbers say something the prose could not. */
.plays {
  list-style: none;
  margin: 0 0 10px;
  padding: 0;
}

.plays li {
  position: relative;
  padding: 0 0 0 20px;
  margin-bottom: 12px;
  font-size: 16px;
  line-height: 1.6;
  text-wrap: pretty;
}

.plays li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 10px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gold-deep);
}

/* ── spec cards ────────────────────────────────────────────────────────────
   The icon is the ability the spec casts most in its reference parse, which is
   both verified and more descriptive than a class crest. The left edge carries
   the class colour, so the grid is scannable by class without a label. */
.spec-card {
  border-left: 3px solid var(--class-colour, var(--gold-deep));
}

.spec-card:hover {
  border-left-color: var(--class-colour, var(--gold));
}

.spec-card h2 { color: var(--class-colour, var(--gold)); }

/* ── raid and dungeon cards ────────────────────────────────────────────── */
.inst-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 12px;
  margin-bottom: 34px;
}

.inst-card {
  display: grid;
  grid-template-columns: 52px 1fr;
  gap: 14px;
  align-items: center;
  padding: 14px 16px;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg-panel);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  transition: border-color .14s, transform .14s;
}

.inst-card:hover {
  border-color: var(--border-gold);
  transform: translateY(-2px);
}

.inst-art img,
.inst-art-blank {
  display: block;
  width: 52px;
  height: 52px;
  border-radius: 9px;
  border: 1px solid var(--border-light);
  background: var(--bg-panel-2);
  object-fit: cover;
}

.inst-kind {
  display: block;
  font-size: 10.5px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.inst-name {
  display: block;
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--gold);
  line-height: 1.25;
  margin: 1px 0 2px;
}

.inst-stats {
  display: block;
  font-size: 12.5px;
  color: var(--dim);
}

/* ── loot rows ─────────────────────────────────────────────────────────────
   Icon beside the name, the same way the planner's item list reads. A name on
   its own is a string; with its icon it is the thing you are looking for. */
.loot-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.loot-item img {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 5px;
  border: 1px solid var(--border-light);
  background: var(--bg-panel-2);
}

.loot-item a { text-decoration: none; font-weight: 600; }
.loot-item a:hover { text-decoration: underline; }
.loot-item small { display: block; color: var(--dim); font-size: 11px; }

/* ---------- item tooltips ----------
 *
 * The contents are Wowhead's markup styled by Wowhead's universal.css, which is
 * linked in the head. What that stylesheet deliberately does NOT provide is the
 * box and where it sits: `.wowhead-tooltip` ships as `display:none;
 * visibility:hidden; position:static !important`, because their script sets all
 * of that inline when it opens one. We open our own, so we supply it here.
 *
 * The !important flags are answering !important, not shouting for the sake of
 * it — `position:static !important` in their sheet would otherwise pin the
 * tooltip into the table cell it belongs to. */
.wh-tip.wowhead-tooltip {
  display: block !important;
  visibility: visible !important;
  position: absolute !important;
  /*
    Sized to its contents, not to the room left over.

    `width: auto` on an absolutely positioned box means shrink-to-fit against
    the space between `left` and the edge of the page — and `left` is set by
    the previous hover. Placing a tooltip near the right-hand side left almost
    no room, so it came back 113px wide with every line wrapped, which then
    pushed the next placement further right still. `max-content` asks for the
    width the text actually wants and ignores where the box happens to sit;
    max-width is what stops a set-bonus list running off the screen.
  */
  width: max-content !important;
  max-width: 340px;
  z-index: 90;
  padding: 10px 12px 12px;
  border: 1px solid var(--border-light);
  border-radius: 10px;
  background: #05070d;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.66);
  font-size: 13px;
  line-height: 1.45;
  pointer-events: none;
}

.wh-tip.wowhead-tooltip[hidden] { display: none !important; }

/*
  Strip the frame Wowhead paints inside the cells, because we are drawing it.

  Their outer <td> carries `background: url(tooltip.png)` — the box texture,
  tiled. Two top-level tables means two tiled cells, and the seam between them
  reads as a stray horizontal rule across the middle of the item. The padding
  is theirs for the same reason: an inset from a border we have already drawn.

  This is Wowhead's own reset, not an invention — universal.css applies exactly
  these two declarations to the outer row when a tooltip is frameless. Scoped
  to the direct children so the nested tables (the slot row, the set bonus
  list) keep the padding they are supposed to have.
*/
.wh-tip.wowhead-tooltip > table > tbody > tr > td,
.wh-tip.wowhead-tooltip > table > tbody > tr > th {
  background: none;
  padding: 0;
}

/*
  Undo this stylesheet's own table styling inside the tooltip.

  guide.css styles bare `table`, `th` and `td` for the data tables on these
  pages, and those selectors reach into injected markup they were never meant
  to touch. Most of it loses to universal.css on specificity, but the
  properties Wowhead does not set come straight through — which is why the
  armour type rendered as "LEATHER" with letter-spacing.
*/
.wh-tip.wowhead-tooltip table {
  /*
    `table { width: 100% }` is the worst of them. The tooltip sizes itself to
    its contents, and a table asking for 100% of a width that is still being
    worked out resolves to almost nothing — the box came out 122px wide with
    every line wrapped three times.
  */
  width: auto;
  margin: 0;
  font-size: inherit;
}

.wh-tip.wowhead-tooltip th {
  text-transform: none;
  letter-spacing: normal;
}

/* No class line. Season 2 gear carries no class requirement, so Wowhead's
   "Classes: Demon Hunter" on a catalyst piece is describing which class the
   token turns into rather than who may equip it — read as a restriction on a
   loot page, it is simply wrong. Hidden rather than stripped from the HTML so
   the markup stays byte-identical to what the planner receives. */
.wh-tip .wowhead-tooltip-item-classes { display: none; }

/* ── written rotation ─────────────────────────────────────────────────────
 *
 * Rules, not a numbered list. The generated priority list is a flattened
 * decision tree and needs numbers because the order is the whole point; these
 * are the handful of rules that tree encodes, and numbering them would imply a
 * strictness that "use Backstab outside a stealth window" does not have. */
.rot-spend {
  background: linear-gradient(180deg, rgba(232, 185, 61, 0.1), rgba(232, 185, 61, 0.03));
  border: 1px solid rgba(232, 185, 61, 0.28);
  border-left-width: 3px;
  border-radius: 9px;
  padding: 13px 17px;
  margin: 0 0 22px;
}

.rot-mode h4,
.rot-open + h4 {
  margin: 24px 0 8px;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.rot-list {
  list-style: none;
  padding: 0;
  margin: 0 0 6px;
}

.rot-list > li {
  position: relative;
  padding: 8px 0 8px 20px;
  margin: 0;
  border-bottom: 1px solid var(--line);
  line-height: 1.55;
}

.rot-list > li:last-child { border-bottom: 0; }

/* A marker that reads as a priority step without pretending to be a number. */
.rot-list > li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 17px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0.55;
}

.rot-open {
  counter-reset: rot;
  list-style: none;
  padding: 0;
  margin: 0 0 20px;
}

.rot-open > li {
  counter-increment: rot;
  position: relative;
  padding: 8px 0 8px 32px;
  margin: 0;
  border-bottom: 1px solid var(--line);
  line-height: 1.55;
}

.rot-open > li:last-child { border-bottom: 0; }

/* The opener IS an order, so it keeps its numbers. */
.rot-open > li::before {
  content: counter(rot);
  position: absolute;
  left: 0;
  top: 8px;
  width: 20px;
  text-align: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--gold);
  opacity: 0.75;
}
