/* Eirik Aarnes: "analysis board" design.
   Dark only, like an engine analysis board. This is a deliberate choice, not a missing light mode.
   Fonts: Inter and JetBrains Mono (SIL Open Font License, see fonts/). */

@font-face {
  font-family: "Inter";
  src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #0d1012;
  --surface: #13171a;
  --surface-2: #181d21;
  --line: #232a2f;
  --line-strong: #323a40;
  --text: #e9ecee;
  --muted: #8d979e;
  --faint: #5d676e;
  --accent: #7fe0aa;
  --accent-ink: #0b1a12;
  --accent-soft: rgba(127, 224, 170, 0.1);
  --square: rgba(255, 255, 255, 0.035);
  --todo-bg: #5a4a00;
  --todo-text: #fff3a3;

  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  --gutter: clamp(1rem, 4vw, 2rem);
  --max: 70rem;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-feature-settings: "ss01", "cv11";
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--accent); color: var(--accent-ink); }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
a:hover { text-decoration-thickness: 2px; }
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--gutter); }

/* ---------- Header ---------- */
.site-header { border-bottom: 1px solid var(--line); }
.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 2rem;
  align-items: center;
  justify-content: space-between;
  padding-top: 1.1rem;
  padding-bottom: 1.1rem;
}
.site-name {
  font: 600 0.82rem/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  text-decoration: none;
}
.site-name::before { content: "♘ "; color: var(--accent); letter-spacing: 0; }
.site-nav { display: flex; flex-wrap: wrap; gap: 0.3rem 1.4rem; font: 500 0.8rem/1.6 var(--mono); }
.site-nav a { color: var(--muted); text-decoration: none; }
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--text); }
.site-nav a[aria-current="page"]::before { content: "▸ "; color: var(--accent); }

/* ---------- Type ---------- */
h1, h2, h3 { line-height: 1.12; font-weight: 700; letter-spacing: -0.025em; margin: 0; }
h1 { font-size: clamp(2.5rem, 7vw, 5rem); letter-spacing: -0.04em; }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); margin-bottom: 1rem; }
h3 { font-size: 1.2rem; letter-spacing: -0.015em; margin-bottom: 0.5rem; }
p { margin: 0 0 1rem; }
strong { font-weight: 650; }

.kicker {
  display: inline-block;
  font: 500 0.75rem/1.4 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}
.kicker .n { color: var(--accent); margin-right: 0.6em; }

.lead { font-size: clamp(1.15rem, 2vw, 1.35rem); line-height: 1.55; color: var(--text); max-width: 38em; }
.muted { color: var(--muted); }
.prose { max-width: 40em; }

/* ---------- Hero ---------- */
.hero {
  position: relative;
  padding: clamp(3.5rem, 10vw, 7.5rem) 0 clamp(3rem, 7vw, 5rem);
  isolation: isolate;
}
.hero::after {
  /* a faint board in the corner */
  content: "";
  position: absolute;
  z-index: -1;
  top: 0; right: calc(var(--gutter) * -1); bottom: 0;
  width: min(34rem, 60%);
  background: conic-gradient(var(--square) 0 25%, transparent 0 50%, var(--square) 0 75%, transparent 0) 0 0 / 3.5rem 3.5rem;
  -webkit-mask-image: radial-gradient(closest-side at 70% 45%, #000 30%, transparent);
  mask-image: radial-gradient(closest-side at 70% 45%, #000 30%, transparent);
}
.hero h1 { max-width: 16ch; margin-bottom: 1.6rem; }
.hero h1 .quiet { display: block; color: var(--muted); }
.hero .lead { margin-bottom: 2rem; }

.actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.8rem 1.15rem;
  border-radius: 6px;
  font: 600 0.85rem/1 var(--mono);
  text-decoration: none;
  border: 1px solid var(--line-strong);
  color: var(--text);
  background: transparent;
  transition: border-color 0.15s, background 0.15s, transform 0.15s;
}
.btn:hover { border-color: var(--text); }
.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.btn.primary:hover { transform: translateY(-1px); }
.btn .arrow { transition: transform 0.15s; }
.btn:hover .arrow { transform: translateX(3px); }

/* ---------- Sections ---------- */
section { padding: clamp(3rem, 7vw, 5rem) 0; border-top: 1px solid var(--line); }
.section-head { display: grid; gap: 0.25rem; margin-bottom: 2rem; max-width: 42em; }
.section-head p { color: var(--muted); margin: 0; }

/* ---------- Move list (the path so far) ---------- */
/* Like the panel beside an analysis board: an evaluation bar, and a list of moves that open. */
.analysis { position: relative; display: grid; gap: 0.6rem; margin: 0 0 2rem; }
.evalbar {
  position: relative;
  height: 0.4rem;
  border-radius: 3px;
  background: #24292d;
  box-shadow: 0 0 0 1px var(--line-strong);
  overflow: hidden;
}
.evalbar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--fill, 50%);
  background: #f4f4f1;
  transition: width 0.45s ease-out;
}
@media (min-width: 40rem) {
  /* upright in the margin, the way it stands beside a board */
  .evalbar {
    position: absolute;
    top: 0; bottom: 0;
    left: calc(var(--gutter) * -0.5 - 0.3rem);
    width: 0.6rem;
    height: auto;
  }
  .evalbar-fill {
    inset: auto 0 0 0;
    width: auto;
    height: var(--fill, 50%);
    transition: height 0.45s ease-out;
  }
}
@media (prefers-reduced-motion: reduce) {
  .evalbar-fill { transition: none; }
}

.moves {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  overflow: hidden;
}
/* eval, name, note, and room for the chevron: shared by the row and by the analysis under it */
.moves { --move-cols: 4.5rem minmax(8rem, 13rem) 1fr 1rem; }
.moves li { border-top: 1px solid var(--line); }
.moves li:first-child { border-top: 0; }
.move {
  display: grid;
  grid-template-columns: var(--move-cols);
  gap: 0.25rem 1.25rem;
  align-items: baseline;
  width: 100%;
  margin: 0;
  padding: 1rem 1.25rem;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  transition: background 0.15s;
}
.move:focus-visible { outline-offset: -3px; border-radius: 8px; }
.moves .eval { position: relative; font: 600 0.9rem/1.4 var(--mono); color: var(--accent); }
.moves .what { font-weight: 650; }
.moves .note { color: #8fa598; } /* a quiet tint of the engine green */
.moves .ann { font-family: var(--mono); color: var(--accent); margin-left: 0.25em; }
.moves li.now .eval { color: var(--muted); }
.cursor {
  display: inline-block;
  width: 0.55em;
  height: 1.05em;
  margin-left: 0.2em;
  vertical-align: -0.15em;
  background: var(--accent);
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .cursor { animation: none; } }

/* The deeper analysis under a row, set in the note's column. Open by default; eval.js closes
   them and opens one at a time. */
.deep { display: grid; grid-template-rows: 1fr; }
.deep > div {
  display: grid;
  grid-template-columns: var(--move-cols);
  gap: 0 1.25rem;
  min-height: 0;
  padding: 0 1.25rem;
  overflow: hidden;
}
.deep p {
  grid-column: 3;
  margin: 0;
  padding-bottom: 1.1rem;
  max-width: 40em;
  color: var(--muted);
}

@media (max-width: 40rem) {
  .moves { --move-cols: 3.5rem 1fr 1rem; }
  .moves .note { grid-column: 2; }
  .deep p { grid-column: 2; }
}

.method {
  border-left: 2px solid var(--accent);
  padding: 0.25rem 0 0.25rem 1.25rem;
  max-width: 40em;
  color: var(--text);
}
.method p:last-child { margin-bottom: 0; }

/* ---------- Cards ---------- */
.grid { display: grid; gap: 1rem; }
@media (min-width: 46rem) {
  .grid.two { grid-template-columns: repeat(2, 1fr); }
  .grid.three { grid-template-columns: repeat(3, 1fr); }
}
.card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1.4rem 1.4rem 1.1rem;
  transition: border-color 0.15s, transform 0.15s;
}
.card:hover { border-color: var(--line-strong); }
.card p { color: var(--muted); }
.card p strong { color: var(--text); }
.card .tag {
  font: 500 0.7rem/1.4 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 0.9rem;
}
.card .tag .ann { color: var(--accent); letter-spacing: 0; margin-right: 0.5em; }
.card .more { margin-top: auto; font: 600 0.8rem/1.4 var(--mono); }
.card .more a { text-decoration: none; }
.card .more a:hover { text-decoration: underline; }

.card.offer { padding: 1.8rem; }
.card.offer h3 { font-size: 1.5rem; }
.card.offer.feature { border-color: var(--accent); background: linear-gradient(180deg, var(--accent-soft), transparent 70%), var(--surface); }

.links { list-style: none; padding: 0; margin: 0 0 1rem; }
.links li { margin: 0.25rem 0; }
.links li::before { content: "→ "; color: var(--accent); font-family: var(--mono); }

.group-title {
  font: 500 0.72rem/1.4 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 2.25rem 0 0.9rem;
}
.group-title:first-child { margin-top: 0; }
.meta { font: 500 0.78rem/1.5 var(--mono); color: var(--faint); margin: 0 0 0.75rem; }

/* ---------- Background / CV ---------- */
.split { display: grid; gap: 2.5rem; }
@media (min-width: 52rem) { .split { grid-template-columns: 1.3fr 1fr; gap: 4rem; } }

.cv { list-style: none; padding: 0; margin: 0 0 1.5rem; }
.cv li {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: 0 1rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--line);
}
.cv li:first-child { border-top: 1px solid var(--line); }
.cv .when { font: 500 0.82rem/1.9 var(--mono); color: var(--muted); }
.cv.plain li { grid-template-columns: 1fr; }
@media (max-width: 30rem) { .cv li { grid-template-columns: 1fr; } }

.facts { margin: 0; }
.facts dt { font: 500 0.72rem/1.4 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); margin-top: 1.1rem; }
.facts dt:first-child { margin-top: 0; }
.facts dd { margin: 0.2rem 0 0; }

/* ---------- Price table ---------- */
.price { list-style: none; padding: 0; margin: 0; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
.price li {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: 0.2rem 1.25rem;
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--line);
}
.price li:first-child { border-top: 0; }
.price .k { font: 500 0.8rem/1.9 var(--mono); color: var(--muted); }
.price .v strong { font-size: 1.15rem; }
.price li.free .v strong { color: var(--accent); }
@media (max-width: 30rem) { .price li { grid-template-columns: 1fr; } }

/* ---------- Contact ---------- */
.contact-line {
  font-size: clamp(1.4rem, 4.5vw, 2.6rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.2;
  word-break: break-word;
}
.contact-line a { color: var(--text); text-decoration-color: var(--accent); text-decoration-thickness: 2px; }
.contact-line a:hover { color: var(--accent); }

/* ---------- Callout (philosophy page) ---------- */
.callout {
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1.25rem;
  margin: 1.5rem 0 0;
}
.callout p:last-child { margin-bottom: 0; }

/* Placeholders for missing facts. build.sh refuses to publish while any are left. */
.mangler {
  background: var(--todo-bg);
  color: var(--todo-text);
  border-radius: 4px;
  padding: 0 0.3em;
  font-size: 0.92em;
}

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--line); padding: 2rem 0 3rem; }
.site-footer .wrap {
  display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; justify-content: space-between;
  font: 500 0.78rem/1.6 var(--mono); color: var(--faint);
}
.site-footer a { color: var(--muted); }

/* ==========================================================================
   Motion. Everything below belongs to board.js, eval.js and tree.js.
   ========================================================================== */

/* ---------- Move list: rows print like engine lines and open (eval.js) ---------- */
.moves.is-live .move { cursor: pointer; }
.moves.is-live .move:hover { background: var(--surface-2); }
.moves.is-live .move::after {
  /* a small chevron: this row opens */
  content: "";
  grid-column: -2;
  grid-row: 1;
  align-self: center;
  justify-self: end;
  width: 0.45rem;
  height: 0.45rem;
  margin-right: 0.15rem;
  border: solid var(--faint);
  border-width: 0 1.5px 1.5px 0;
  transform: translateY(-25%) rotate(45deg);
  transition: transform 0.25s ease, border-color 0.15s;
}
.moves.is-live .move:hover::after { border-color: var(--text); }
.moves.is-live .move[aria-expanded="true"]::after { transform: translateY(25%) rotate(-135deg); border-color: var(--accent); }
.moves.is-live .deep {
  grid-template-rows: 0fr;
  visibility: hidden;
  transition: grid-template-rows 0.3s ease, visibility 0s 0.3s;
}
.moves.is-live .deep.is-open {
  grid-template-rows: 1fr;
  visibility: visible;
  transition: grid-template-rows 0.3s ease, visibility 0s;
}
.moves.is-printing li { opacity: 0; visibility: hidden; }
.moves.is-printing li.is-in {
  opacity: 1;
  visibility: visible;
  animation: moves-print 0.65s cubic-bezier(0.2, 0.6, 0.2, 1) both;
}
@keyframes moves-print {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
.moves .depth {
  position: absolute;
  left: 0; top: 100%;
  font: 500 0.62rem/1.5 var(--mono);
  letter-spacing: 0.02em;
  color: var(--faint);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.moves .depth.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .moves.is-live .move::after, .moves.is-live .deep, .moves.is-live .deep.is-open { transition: none; }
}
@media print {
  .moves.is-printing li { opacity: 1; visibility: visible; }
  .moves.is-live .deep { grid-template-rows: 1fr; visibility: visible; }
}

/* ---------- Hero board (board.js) ----------
   The whole board is in view. It is as tall as the hero and stands against its right edge;
   on a phone that is the full width. Its squares run on beyond the board, fainter, and fade
   out towards the left, so the hero is covered without cropping the board. The hero is made
   tall enough for the board to be worth looking at.
   Each piece of text carries its own dark backdrop with a soft edge, so the board is dimmed
   exactly where there is text and nowhere else. The backdrop strengths are set for contrast:
   with the brightest arrow straight behind it, small text keeps 4.5:1 and the headline 3:1. */
.hero.has-board {
  --hb-veil: 13, 16, 18; /* --bg */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  min-height: calc(min(100vw, max(20rem, min(44rem, 100vh - 8.5rem))) + 2rem);
  min-height: calc(min(100vw, max(20rem, min(44rem, 100svh - 8.5rem))) + 2rem);
  padding-top: 2rem;
  padding-bottom: 2rem;
}
.hero.has-board::after { content: none; }
.hero-board {
  --hb-white: #aab2b7;
  --hb-black: #47515a;
  /* The Cburnett pieces on a dark board. The white ones are a soft light grey with dark lines.
     The black ones are black, as on lichess, but their outline and inner lines are light instead
     of black, so that they read at a glance on both square colours. */
  --pc-light: #b9c1c6;
  --pc-ink: #14181b;
  --pc-dark: #060708;
  --pc-edge: #aeb7bd;
  --pc-line: #c9d0d4;
  position: absolute;
  z-index: -1;
  top: 0.5rem;
  left: calc(var(--gutter) * -1);
  width: calc(100% + var(--gutter) * 2);
  height: calc(100% - 1rem);
  pointer-events: none;
}
@media (min-width: 62rem) {
  /* the squares that run on to the left of the board fade out */
  .hero-board {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 40%);
    mask-image: linear-gradient(to right, transparent, #000 40%);
  }
}
.hb-outer { fill: rgba(255, 255, 255, 0.026); }
.hero.has-board > .kicker,
.hero.has-board > .lead {
  background: rgba(var(--hb-veil), 0.86);
  box-shadow: 0 0 0.9rem 0.7rem rgba(var(--hb-veil), 0.86);
}
.hero.has-board > h1 {
  background: rgba(var(--hb-veil), 0.72);
  box-shadow: 0 0 1.75rem 1.25rem rgba(var(--hb-veil), 0.72);
}
.hero.has-board .btn:not(.primary) { background: rgba(var(--hb-veil), 0.86); }

.hb-squares { fill: rgba(255, 255, 255, 0.045); }
.hb-last { fill: var(--accent); opacity: 0; transition: opacity 0.3s ease; }
.hb-last.is-on { opacity: 0.09; }
.hb-last.is-fresh { animation: hb-land 0.9s ease-out; }
@keyframes hb-land { 0% { opacity: 0.4; } 100% { opacity: 0.09; } }
.hb-pieces { transition: opacity 0.8s ease; }
.hero-board.is-clearing .hb-pieces,
.hero-board.is-clearing .hb-last { opacity: 0; }
.hb-pc { transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease; }
.hb-pc.is-taken { opacity: 0; transition-delay: 0s, 0.28s; }
.hb-pc.is-away { opacity: 0.28; }
.hb-w { fill: var(--hb-white); }
.hb-b { fill: var(--hb-black); }
.hb-pc .hb-cut { fill: var(--bg); }
.hb-pc .hb-slit { fill: none; stroke: var(--bg); stroke-width: 3.4; stroke-linecap: round; }

/* Calculation: ghost pieces and their trail. Thin, dashed and a dim version of the engine
   green, so that it belongs with the move that is played but can never be mistaken for it. */
.hero-board {
  --hb-think: #5c9a7a;
  --gh-light: #a7cbb8; --gh-ink: #13231b;
  --gh-dark: #0c1410; --gh-edge: #6fae8c; --gh-line: #8fc0a6;
}
.hb-ghost { opacity: 0; transition: transform 0.42s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.22s ease; }
.hb-ghost.is-on { opacity: 0.7; }
.hb-ghost.hb-w { fill: var(--gh-light); --pc-light: var(--gh-light); --pc-ink: var(--gh-ink); }
.hb-ghost.hb-b { fill: var(--gh-dark); --pc-dark: var(--gh-dark); --pc-edge: var(--gh-edge); --pc-line: var(--gh-line); }
.hb-arrow { opacity: 0; transition: opacity 0.22s ease-out; }
.hb-calc.is-on { opacity: 0.62; }
.hb-calc line { stroke: var(--hb-think); stroke-width: 4; stroke-linecap: round; stroke-dasharray: 9 10; }
.hb-calc polygon { fill: var(--hb-think); }

/* The move that is played: solid engine green, drawn in one stroke, with a glow. */
.hb-best { filter: drop-shadow(0 0 9px rgba(127, 224, 170, 0.55)); }
.hb-best.is-on { opacity: 0.95; transition-duration: 0.08s; }
.hb-best line {
  stroke: var(--accent);
  stroke-width: 13;
  stroke-linecap: round;
  stroke-dashoffset: var(--len);
  transition: stroke-dashoffset 0.2s cubic-bezier(0.3, 0, 0.2, 1);
}
.hb-best.is-on line { stroke-dashoffset: 0; }
.hb-best polygon { fill: var(--accent); opacity: 0; transition: opacity 0.1s ease 0.14s; }
.hb-best.is-on polygon { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .hero-board * { transition: none !important; }
}

/* ---------- Variation tree ("Sidevarianter", tree.js) ----------
   A list of labels and two links. What is written first here is the finished tree, standing
   still: an indented outline on a phone, a tree that runs left to right from 66rem, with the
   nodes nudged off the grid so it reads as a sketch. That is what reduced motion shows, with
   lines drawn by tree.js. Further down, .is-journey turns the list into a framed window in
   which the view follows one line of the tree at a time. */
.tree {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 0;
}
.tree li { position: relative; z-index: 1; margin: 0.55rem 0 0 calc(var(--d) * 1rem); }
.tree li:first-of-type { margin-top: 0; }
.tree .chip {
  display: inline-block;
  padding: 0.28rem 0.62rem;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface);
  font-size: 0.9rem;
  font-weight: 550;
  line-height: 1.3;
  white-space: nowrap;
  transition: color 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}
.tree .root .chip {
  border-color: var(--muted);
  font: 600 0.74rem/1.5 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.tree .struck .chip { color: #7b858c; border-color: var(--line); }
.tree .faded .chip { color: var(--muted); border-color: var(--line); }

/* The two live ends: where the tree leads now. */
.tree .end { margin-right: 2.75rem; }
.tree .end:last-of-type { margin-top: 1.4rem; margin-right: 0; }
.tree .end a {
  position: relative;
  display: block;
  padding: 0.85rem 1rem 0.9rem;
  border: 1px solid var(--accent);
  border-radius: 10px;
  background: linear-gradient(180deg, var(--accent-soft), transparent 75%), var(--surface);
  color: var(--text);
  text-decoration: none;
  transition: border-color 0.4s ease, box-shadow 0.2s ease, transform 0.15s ease;
}
.tree .end a:hover { box-shadow: 0 0 0 1px var(--accent); transform: translateY(-1px); }
.tree .end .tag {
  display: block;
  margin-bottom: 0.35rem;
  font: 500 0.7rem/1.4 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  transition: color 0.4s ease;
}
.tree .end h3 { margin: 0; font-size: 1.05rem; }
.tree .end p { margin: 0.3rem 0 0; color: var(--muted); }
.tree .end p strong { color: var(--text); }
.tree .end .go {
  position: absolute;
  right: 1rem; top: 0.85rem;
  font: 600 1rem/1 var(--mono);
  color: var(--accent);
  transition: color 0.4s ease, transform 0.15s ease;
}
.tree .end a:hover .go { transform: translateX(3px); }

@media (min-width: 66rem) {
  .tree:not(.is-journey) {
    display: grid;
    grid-template-columns: repeat(5, max-content) minmax(12.5rem, 15rem);
    column-gap: 1rem;
    grid-auto-rows: minmax(2.9rem, auto);
    justify-content: space-between;
    align-items: center;
    row-gap: 0.55rem;
  }
  .tree:not(.is-journey) li {
    grid-column: var(--c);
    grid-row: var(--r);
    margin: 0;
    transform: translate(var(--x, 0px), var(--y, 0px));
  }
  .tree:not(.is-journey) .end { grid-row: var(--r) / span 3; }
  .tree .end a { padding-right: 2.6rem; }
  .tree .end h3 { font-size: 1.15rem; }
  .tree .end .go { top: 50%; transform: translateY(-50%); }
  .tree .end a:hover .go { transform: translate(3px, -50%); }
  /* off the grid, like a sketch */
  .tree [data-id="esport"] { --x: 0.7rem; --y: -0.2rem; }
  .tree [data-id="starcraft"] { --x: 1.7rem; }
  .tree [data-id="laering"] { --x: -0.5rem; --y: 0.2rem; }
  .tree [data-id="pedagogikk"] { --x: 0.4rem; --y: -0.15rem; }
  .tree [data-id="logikk"] { --x: 1.2rem; }
  .tree [data-id="automatisering"] { --x: 0.9rem; --y: -0.25rem; }
  .tree [data-id="lingvistikk"] { --x: -0.2rem; --y: 0.2rem; }
  .tree [data-id="sprakmodeller"] { --x: -0.7rem; }
  .tree [data-id="seo"] { --x: 1rem; }
  .tree [data-id="faktasjekk"] { --x: 0.3rem; --y: 0.3rem; }
  .tree [data-id="tv"] { --x: -0.3rem; }
  .tree [data-id="vaktsjef"] { --x: 1.3rem; --y: 0.1rem; }
  .tree [data-id="some"] { --x: 0.8rem; --y: -0.15rem; }
  .tree [data-id="strategi"] { --x: 0.9rem; --y: 0.15rem; }
  .tree [data-id="turneringer"] { --x: 1.4rem; }
  .tree [data-id="russisk"] { --x: 0.5rem; --y: -0.1rem; }
  .tree [data-id="fransk"] { --x: 1.6rem; }
  .tree [data-id="video"] { --x: 0.6rem; }
  .tree [data-id="arrangementer"] { --x: 0.3rem; --y: 0.2rem; }
  .tree [data-id="spilldesign"] { --x: 1.1rem; --y: -0.1rem; }
  .tree [data-id="kisprak"] { --x: 0.5rem; --y: 0.2rem; }
  .tree [data-id="nettsider"] { --x: 0.9rem; }
  .tree [data-id="direktesending"] { --x: -0.3rem; }
  .tree:not(.is-journey) [data-id="tillit"] .chip { max-width: 9.5rem; white-space: normal; }
  .tree:not(.is-journey) .beyond { justify-self: center; }
  .tree [data-id="journalistikk"] { --y: 0.3rem; }
}

/* Lines */
.tree-lines, .tree-exit { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
.tree-lines { z-index: 0; }
.tree-exit { z-index: 3; }
.tree .line { fill: none; stroke: #3d474e; stroke-width: 1.5; stroke-linecap: round; transition: stroke 0.4s ease, opacity 0.5s ease; }
.tree .grow { transition: stroke-dashoffset 0.75s cubic-bezier(0.4, 0, 0.2, 1), stroke 0.4s ease, opacity 0.5s ease; }
.tree .is-dead .line { stroke: var(--line); }
.tree .back .line { stroke: var(--accent); stroke-opacity: 0.75; stroke-dasharray: 5 6; }
.tree .live .line { stroke: var(--accent); stroke-width: 2; }
.tree .back.live .line { stroke-opacity: 1; }

/* Struck labels: with tree.js the line is drawn across; without it the browser's own strike shows. */
.tree.is-live s { position: relative; text-decoration: none; }
.tree.is-live s::after {
  content: "";
  position: absolute;
  left: -0.15em; right: -0.15em; top: 54%;
  height: 1.5px;
  background: currentColor;
  transform-origin: left center;
  transition: transform 0.4s ease;
}

/* ---------- The journey: a window in which the view follows one line at a time ---------- */
.tree.is-journey {
  height: var(--tree-h, 30rem);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}
.tree.is-journey li {
  position: absolute;
  left: 0; top: 0;
  margin: 0;
  transform: translate(var(--px, 0px), var(--py, 0px));
}
/* big boxes: one line of the tree is all there is to read at a time */
.tree.is-journey .chip {
  padding: 0.6rem 1.05rem;
  border-radius: 9px;
  background: var(--surface-2);
  font-size: 1.1rem;
}
.tree.is-journey .root .chip { font-size: 0.86rem; padding: 0.7rem 1.05rem; }
/* A node is hidden until the view reaches it, readable while it is on the line being followed,
   and a faint trace afterwards. */
.tree.is-journey li:not(.end) { opacity: 0; transition: opacity 0.6s ease; }
.tree.is-journey li.is-on { opacity: 1; }
.tree.is-journey li.is-past { opacity: 0.16; }
.tree.is-journey li.is-glance { opacity: 0.85; }
.tree.is-journey li.is-cursor .chip { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.tree.is-journey .edge:not(.is-on) .line { opacity: 0; }
.tree.is-journey .edge.is-past .line { opacity: 0.3; }
.tree.is-journey .struck:not(.is-struck) .chip,
.tree.is-journey .faded:not(.is-struck) .chip { color: var(--text); border-color: var(--line-strong); }
.tree.is-journey .struck:not(.is-struck) s::after { transform: scaleX(0); }
.tree.is-journey li.is-hit .chip { animation: tree-hit 0.9s ease-out; }
@keyframes tree-hit {
  0% { box-shadow: 0 0 0 0 rgba(127, 224, 170, 0.5); }
  100% { box-shadow: 0 0 0 10px rgba(127, 224, 170, 0); }
}

/* Associations: "this reminds me of that". A dotted arc and a name in a dotted pill, pale instead
   of green, so that they are not read as part of the line being followed. */
.tree .assoc {
  fill: none;
  stroke: #b3bcc2;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 0.1 6;
  opacity: 0;
  transition: opacity 0.4s ease;
}
.tree .assoc.is-on { opacity: 0.75; }
.tree .assoc-spark {
  fill: none;
  stroke: var(--text);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: 0.14 3;
  animation: tree-remind 0.75s ease-out forwards;
}
@keyframes tree-remind {
  from { stroke-dashoffset: 0.14; }
  to { stroke-dashoffset: -1; }
}
.tree-echo {
  position: absolute;
  left: 0; top: 0;
  z-index: 1;
  padding: 0.3rem 0.8rem;
  border: 1.5px dotted #8b959c;
  border-radius: 999px;
  background: rgba(19, 23, 26, 0.9);
  color: #c9d0d4;
  font-size: 0.9rem;
  line-height: 1.3;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(var(--px, 0px), var(--py, 0px));
  transition: opacity 0.4s ease;
}
.tree-echo.is-on { opacity: 0.95; }

/* The live ends stay put: beside the window, or under it on a phone. They light up when a line
   first reaches them and are links all along. One of them keeps going: the node that comes
   after it stands just above it (under it on a phone) and appears when the line first arrives. */
.tree .beyond .chip { border-color: var(--accent); }
.tree.is-journey li.beyond {
  left: auto; top: auto;
  right: 3rem;
  bottom: calc(1.25rem + var(--ki-h, 5rem) + 3.4rem);
  z-index: 4;
  transform: none;
}
.tree.is-journey li.beyond .chip { padding: 0.45rem 0.85rem; font-size: 1rem; }
.tree.is-journey .end {
  left: auto; top: auto;
  right: 1.25rem;
  z-index: 4;
  width: 16.5rem;
  margin: 0;
  transform: none;
}
.tree.is-journey .end[data-id="sjakktimer"] { top: 1.25rem; }
.tree.is-journey .end[data-id="ki"] { bottom: 1.25rem; }
.tree.is-journey::after {
  /* nodes fade out before they reach the live ends */
  content: "";
  position: absolute;
  z-index: 2;
  top: 0; bottom: 0; right: 0;
  width: 27rem;
  background: linear-gradient(to right, rgba(19, 23, 26, 0), var(--surface) 36%);
  pointer-events: none;
}
.tree.is-journey .end:not(.is-lit) a { border-color: var(--line-strong); background: var(--surface-2); }
.tree.is-journey .end:not(.is-lit) .tag,
.tree.is-journey .end:not(.is-lit) .go { color: var(--faint); }
.tree.is-journey .end.is-hit a { animation: tree-arrive 1.2s ease-out; }
@keyframes tree-arrive {
  0% { box-shadow: 0 0 0 0 rgba(127, 224, 170, 0.6); }
  100% { box-shadow: 0 0 0 16px rgba(127, 224, 170, 0); }
}
@media (max-width: 40rem) {
  .tree.is-journey { --tree-h: calc(19rem + var(--cards-h, 12rem) + 6.4rem); }
  .tree.is-journey .chip { padding: 0.5rem 0.85rem; font-size: 1rem; }
  .tree.is-journey .root .chip { font-size: 0.74rem; padding: 0.55rem 0.8rem; }
  .tree.is-journey .end { left: 1rem; right: 1rem; width: auto; }
  .tree.is-journey .end[data-id="sjakktimer"] { top: auto; bottom: calc(5.4rem + var(--ki-h, 4.5rem)); }
  .tree.is-journey .end[data-id="ki"] { bottom: 4.8rem; }
  .tree.is-journey li.beyond { right: 1.75rem; bottom: 1rem; }
  .tree.is-journey::after {
    top: auto; left: 0;
    width: auto;
    height: calc(var(--cards-h, 12rem) + 9.3rem);
    background: linear-gradient(to bottom, rgba(19, 23, 26, 0), var(--surface) 40%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .tree *, .tree-lines *, .tree-exit * { transition: none !important; animation: none !important; }
}

/* ---------- Detail: the verdict on each "KI i praksis" card is a badge, like a move annotation ---------- */
#analyse .card .tag { display: flex; align-items: center; gap: 0.6em; }
#analyse .card .tag .ann {
  display: inline-grid;
  place-items: center;
  min-width: 1.5rem;
  height: 1.5rem;
  margin: 0;
  padding: 0 0.3rem;
  border-radius: 5px;
  background: var(--accent-soft);
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1;
}
#analyse .card { transition: border-color 0.2s ease; }
#analyse .card:hover { border-color: rgba(127, 224, 170, 0.45); }

/* ---------- Detail: the row under the pointer in "Erfaring" is marked like the current move ---------- */
#erfaring .cv li { position: relative; }
#erfaring .cv li::before {
  /* the same marker the menu uses for the current page */
  content: "▸";
  position: absolute;
  left: -1.1rem; top: 0.65rem;
  font: 500 0.82rem/1.9 var(--mono);
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.15s ease;
}
#erfaring .cv li .when { transition: color 0.15s ease; }
@media (hover: hover) {
  #erfaring .cv li:hover::before { opacity: 1; }
  #erfaring .cv li:hover .when { color: var(--text); }
}

/* ---------- Detail: the address in "Kontakt" ends in the same cursor as the "Pågår." row ---------- */
#kontakt .contact-line::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.9em;
  margin-left: 0.18em;
  vertical-align: -0.08em;
  background: var(--accent);
  animation: blink 1.1s steps(1) infinite;
}
@media (prefers-reduced-motion: reduce) {
  #kontakt .contact-line::after { animation: none; }
}
