/* =============================================================================
   HoopersHub user guides - shared stylesheet

   Standalone on purpose: no build step, no CDN, no external request of any
   kind. Every asset the pages need (logo, favicon, font) lives inside this
   folder, so /guides can be copied to any static host, any URL depth, or a USB
   stick and still render correctly.

   The page carries no icons. Hierarchy is made with type size, weight, colour
   and hairline rules only, so nothing renders differently on one OS than
   another and nothing depends on an emoji font being installed. The one
   exception is the HoopersHub logo, which is the real brand asset.

   Every colour below is lifted from the app (Fire & Ice, brand guidelines
   v1.3), not approximated:
     accent           ice #47B7FF / ice-700 #1E8FD6  frontend/app/globals.css
                      --ice / --ice-700 (the app's --theme-color). The guides
                      are reference reading, so they carry the "you are here"
                      accent only; flame is reserved for one primary action.
     neutrals         ink / cloud / mist / slate / steel, frontend/app/globals.css
     status colours   frontend/app/globals.css  --success / --warning / --info
     radius           frontend/app/globals.css  --radius: 0.625rem
     shadow           frontend/app/globals.css  .shadow-card
     typeface         Manrope, frontend/app/layout.tsx (next/font/google)
   ============================================================================= */

/* --- Typeface --------------------------------------------------------------- */

/* The app loads Manrope through next/font. To keep the guides standalone the
   font is self-hosted rather than pulled from Google:
   assets/fonts/Manrope-Variable.woff2 is the latin variable subset (200-800)
   next/font itself generated and serves.

   local() is tried first, so a reader who already has Manrope installed loads
   nothing at all. The system stack in --font remains the fallback. */
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: local("Manrope"),
       url("fonts/Manrope-Variable.woff2") format("woff2");
}

/* --- Tokens ---------------------------------------------------------------- */

:root {
  /* Accent. Ice-700 #1e8fd6 is a fill and a rule colour, never body text: on
     white it only reaches ~3.5:1. --brand-ink is a darkened ice for text and
     links (~5.9:1 on white), and is the one value here that is derived rather
     than lifted. In dark mode it becomes ice #47b7ff (8.2:1 on Ink 900). */
  --brand: #1e8fd6;
  --brand-ink: #16699f;
  --brand-soft: rgba(71, 183, 255, 0.12);

  --bg: #ffffff;
  --bg-subtle: #f5f7fa;
  --bg-sunken: #e6eaf0;
  --text: #0b0f1a;
  --text-muted: #5b6675;
  --text-faint: #9aa5b5;
  --border: #e6eaf0;
  --border-strong: #d5dbe3;

  /* Status colours. The app's values (globals.css --success #22c55e,
     --warning #f59e0b, --info #3b82f6) are tuned for filled badges on white;
     used as 15px label text on their own 6-9% tint they land between 3 and
     4.7:1. These are the same hues darkened to clear AA with headroom on that
     blended backdrop, since --*-soft is what sits behind them. Dark mode uses
     the app's values directly - on near-black they are already 6:1+. */
  --ok: #146c33;
  --ok-soft: rgba(34, 197, 94, 0.08);
  --warn: #92400e;
  --warn-soft: rgba(245, 158, 11, 0.09);
  --danger: #b91c1c;
  --danger-soft: rgba(220, 38, 38, 0.07);
  --info: #1d4ed8;
  --info-soft: rgba(59, 130, 246, 0.07);

  /* Type scale. One ramp, used everywhere. Anything not on it is a bug. */
  --fs-2xs: 11px;
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-md: 14px;
  --fs-lg: 15px;
  --fs-body: 16px;
  --fs-xl: 18px;
  --fs-2xl: 20px;
  --fs-3xl: 25px;

  /* Spacing. A 4px grid, named so the rhythm is the same on every page. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 40px;
  --sp-8: 64px;
  --sp-9: 96px;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 4px 12px rgba(0, 0, 0, 0.06);

  --font: "Manrope", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  --measure: 680px;
  --bar: 57px;      /* top bar height */
  --quicknav: 46px; /* mobile quick-nav height; stacks under the top bar */
  /* Total sticky chrome. Every scroll offset below is derived from this, so
     the two bars cannot drift apart from the anchor landing position. */
  --chrome: var(--bar);
}

/* Dark mode follows the OS by default; the toggle stamps data-theme to win in
   both directions, so an explicit choice survives an OS that disagrees. The
   values match the app's .dark block in globals.css. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b0f1a;
    --bg-subtle: #141a29;
    --bg-sunken: #1c2333;
    --text: #ffffff;
    --text-muted: #9aa5b5;
    --text-faint: #6b778a;
    --border: #2a3345;
    --border-strong: #404b60;
    --brand-ink: #47b7ff;
    --brand-soft: rgba(71, 183, 255, 0.16);
    --ok: #22c55e;
    --ok-soft: rgba(34, 197, 94, 0.1);
    --warn: #f59e0b;
    --warn-soft: rgba(245, 158, 11, 0.1);
    --danger: #f87171;
    --danger-soft: rgba(248, 113, 113, 0.1);
    --info: #60a5fa;
    --info-soft: rgba(59, 130, 246, 0.12);
    --shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.25);
  }
}

:root[data-theme="dark"] {
  --bg: #0b0f1a;
  --bg-subtle: #141a29;
  --bg-sunken: #1c2333;
  --text: #ffffff;
  --text-muted: #9aa5b5;
  --text-faint: #6b778a;
  --border: #2a3345;
  --border-strong: #404b60;
  --brand-ink: #47b7ff;
  --brand-soft: rgba(71, 183, 255, 0.16);
  --ok: #22c55e;
  --ok-soft: rgba(34, 197, 94, 0.1);
  --warn: #f59e0b;
  --warn-soft: rgba(245, 158, 11, 0.1);
  --danger: #f87171;
  --danger-soft: rgba(248, 113, 113, 0.1);
  --info: #60a5fa;
  --info-soft: rgba(59, 130, 246, 0.12);
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.25);
}

/* --- Reset ----------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--chrome) + var(--sp-5));
}

/* Below 900px the sidebar is gone and .quicknav is sticky under the top bar,
   so an anchor has two bars to clear, not one. */
@media (max-width: 900px) {
  :root { --chrome: calc(var(--bar) + var(--quicknav)); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--brand-ink); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--brand); }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--radius-sm); }

::selection { background: var(--brand-soft); }

/* --- Top bar --------------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--bar);
  padding: var(--sp-2) var(--sp-5);
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--border);
}

/* The lockup is two targets, not one. The logo leaves for the app and the
   section label goes to the guides index, which is the only way back to the
   main site that survives the 620px breakpoint below, where .topbar__nav is
   dropped entirely. */
.topbar__brand {
  display: flex; align-items: center; gap: var(--sp-3);
  color: var(--text);
  min-height: 40px;
}
.topbar__home,
.topbar__section {
  display: inline-flex; align-items: center; min-height: 40px;
  text-decoration: none; color: inherit; border-radius: var(--radius-sm);
}
.topbar__home:hover, .topbar__section:hover { opacity: 0.72; }

/* The real lockup: the app's split lockup (mark tile + wordmark), from
   frontend/public/brand/lockup/hh-lockup-split-wide-{light,dark}.svg. Two
   files rather than one recoloured with currentColor, because the art is
   multi-colour: the ball and the two O's stay flame and the net ice while the
   type flips. Confusing but load-bearing filenames:
     logo-dark.svg   ink type   (#0b0f1a) -> use on a LIGHT background
     logo-light.svg  white type (#ffffff) -> use on a DARK background */
.topbar__logo { display: block; height: 36px; width: auto; }
.topbar__logo--on-dark { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .topbar__logo--on-light { display: none; }
  :root:not([data-theme="light"]) .topbar__logo--on-dark { display: block; }
}
:root[data-theme="dark"] .topbar__logo--on-light { display: none; }
:root[data-theme="dark"] .topbar__logo--on-dark { display: block; }
:root[data-theme="light"] .topbar__logo--on-light { display: block; }
:root[data-theme="light"] .topbar__logo--on-dark { display: none; }

/* "Guides" is a section label hung off the product name, so it is separated
   by a rule rather than run together with it. */
.topbar__divider {
  width: 1px; height: 18px; flex: none;
  background: var(--border-strong);
}
.topbar__section {
  font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.011em;
  color: var(--text); white-space: nowrap;
}
.topbar__spacer { flex: 1; }

.topbar__nav { display: flex; align-items: center; gap: var(--sp-1); }

.topbar__link {
  font-size: var(--fs-md); font-weight: 500; color: var(--text-muted);
  text-decoration: none; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm);
  white-space: nowrap; min-height: 40px; display: inline-flex; align-items: center;
}
.topbar__link:hover { color: var(--text); background: var(--bg-sunken); }

.theme-toggle {
  border: 1px solid var(--border-strong); background: transparent;
  color: var(--text-muted); border-radius: var(--radius-sm);
  padding: 0 var(--sp-3); font: inherit; font-size: var(--fs-sm); font-weight: 500;
  cursor: pointer; min-height: 40px; min-width: 40px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  white-space: nowrap;
}
.theme-toggle:hover { color: var(--text); border-color: var(--text-faint); }

/* Icon-only. Both glyphs ship in the button and CSS picks one, so the correct
   icon is painted before guide.js runs and the script never touches the
   button's contents. It shows what you will GET: a moon on a light page, a sun
   on a dark one. Inline SVG on currentColor, so there is still no icon font
   and no request; the guard mirrors the sheet's own
   :not([data-theme="light"]) pattern. */
.theme-toggle svg { display: block; width: 18px; height: 18px; }
.theme-toggle__sun { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle__sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle__moon { display: none; }
}
:root[data-theme="dark"] .theme-toggle__sun { display: block; }
:root[data-theme="dark"] .theme-toggle__moon { display: none; }
:root[data-theme="light"] .theme-toggle__sun { display: none; }
:root[data-theme="light"] .theme-toggle__moon { display: block; }

/* The bar is sticky, so anything that wraps costs a line of every screen for
   the whole scroll. Below 620px the cross-links are dropped (they repeat in
   the footer) and only the brand and the theme toggle survive. */
@media (max-width: 620px) {
  .topbar { padding: var(--sp-2) var(--sp-4); gap: var(--sp-2); }
  .topbar__nav { display: none; }
  .topbar__logo { height: 32px; }
}

/* --- Mobile quick nav ------------------------------------------------------- */

/* Built by assets/guide.js from the desktop index, so the list of sections
   exists in the HTML exactly once. Sticky under the top bar: on a phone the
   sidebar is gone, and a ten-section page with no way to jump is the single
   worst thing about reading this on a phone. */

.quicknav {
  position: sticky;
  top: var(--bar);
  z-index: 30;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--border);
  display: none;
}
.quicknav[hidden] { display: none !important; }

.quicknav__summary {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-4);
  min-height: var(--quicknav);
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-md);
  font-weight: 550;
  color: var(--text);
}
.quicknav__summary::-webkit-details-marker { display: none; }

.quicknav__label {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted); flex: none;
}
.quicknav__current {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1;
}
/* Chevron, drawn with a rotated border so it needs no icon file. */
.quicknav__summary::after {
  content: ""; flex: none;
  width: 7px; height: 7px; margin-left: auto;
  border-right: 1.5px solid var(--text-faint);
  border-bottom: 1.5px solid var(--text-faint);
  transform: translateY(-2px) rotate(45deg);
  transition: transform .15s ease;
}
.quicknav[open] .quicknav__summary::after { transform: translateY(1px) rotate(225deg); }

.quicknav__panel {
  border-top: 1px solid var(--border);
  max-height: min(60vh, 420px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-2) 0 var(--sp-3);
}
.quicknav__panel ol { list-style: none; margin: 0; padding: 0; counter-reset: none; }
.quicknav__panel a {
  display: flex; align-items: center;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  color: var(--text-muted); text-decoration: none;
  font-size: var(--fs-lg); line-height: 1.4;
}
.quicknav__panel a:active { background: var(--bg-sunken); }
.quicknav__panel a.is-active { color: var(--brand-ink); font-weight: 600; }
.quicknav__panel .toc--sub a { padding-left: var(--sp-7); font-size: var(--fs-md); }

@media (max-width: 900px) {
  .quicknav { display: block; }
}

/* --- Layout ---------------------------------------------------------------- */

.layout {
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  gap: var(--sp-8);
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-5) var(--sp-9);
  align-items: start;
}

@media (max-width: 900px) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    padding: var(--sp-6) var(--sp-5) var(--sp-8);
  }
}
@media (max-width: 480px) {
  .layout { padding: var(--sp-5) var(--sp-4) var(--sp-7); }
}

main { min-width: 0; max-width: var(--measure); }

/* --- Table of contents ------------------------------------------------------ */

.toc {
  position: sticky;
  top: calc(var(--chrome) + var(--sp-6));
  font-size: var(--fs-md);
}
/* --text-faint is a decorative tone only - hairlines, chevrons, dashed rules.
   It is 2.6:1 on white, so it never carries text. Small labels use
   --text-muted, which clears AA in both themes. */
.toc__title {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-muted);
  margin: 0 0 var(--sp-3); padding-left: var(--sp-3);
}
.toc ol { list-style: none; margin: 0; padding: 0; }
.toc li { margin: 0; }
.toc a {
  display: block; padding: var(--sp-2) var(--sp-3); color: var(--text-muted);
  text-decoration: none; border-left: 1px solid var(--border);
  line-height: 1.4;
}
.toc a:hover { color: var(--text); border-left-color: var(--border-strong); }
.toc a.is-active {
  color: var(--text); border-left: 1px solid var(--brand);
  box-shadow: -1px 0 0 var(--brand);
  font-weight: 600;
}
.toc .toc--sub a { padding-left: var(--sp-6); font-size: var(--fs-sm); }

/* --- The way back to the help centre ----------------------------------------- */
/* Every guide links back to index.html three ways: at the top of the page
   index (and its phone quick nav copy), and as a card at the end of the
   guide. The chevron is drawn with borders, like the FAQ chevrons: no icons. */
.toc a.toc__back,
.quicknav__panel a.quicknav__back,
.guide-end__label {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--brand-ink); font-weight: 650; text-decoration: none;
}
.toc a.toc__back { margin: 0 0 var(--sp-5); padding: var(--sp-1) var(--sp-3); border-left: 0; font-size: var(--fs-md); }
.toc a.toc__back:hover { color: var(--brand); text-decoration: underline; text-underline-offset: 3px; }
.quicknav__panel a.quicknav__back { border-bottom: 1px solid var(--border); }
.toc__back::before,
.quicknav__back::before,
.guide-end__label::before {
  content: ""; flex: none; width: 7px; height: 7px;
  border-left: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateX(2px) rotate(45deg);
}

.guide-end {
  display: block; margin: var(--sp-8) 0 0; padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-subtle); text-decoration: none; color: inherit;
  transition: border-color .15s, background-color .15s;
}
.guide-end:hover { border-color: var(--brand); background: var(--brand-soft); }
.guide-end__label { font-size: var(--fs-lg); }
.guide-end__hint { display: block; margin-top: 2px; padding-left: calc(7px + var(--sp-2)); font-size: var(--fs-md); color: var(--text-muted); }
@media (prefers-reduced-motion: reduce) {
  .guide-end { transition: none; }
}

/* The sidebar's job is taken over by .quicknav below 900px. */
@media (max-width: 900px) {
  .toc { display: none; }
}

/* --- Page header: the brand panel -------------------------------------------- */

/* Every page - hub and guides alike - opens on the same dark panel carrying
   the app's own header artwork (assets/hero-bg.jpg, downsampled from
   frontend/public/images/headers/player-portal-bg.png: the original is
   1920x920 and 740KB, which is more pixels than a 900px panel can show and
   more bytes than every screenshot in the folder combined).

   The art is dark on the left and carries the red halftone on the right, so
   the title sits on near-black while the energy sits in the empty half. A
   scrim over it holds that contrast no matter how the panel is sized.

   The panel is permanently dark in both themes, the way the app's own
   --accent-strip is (globals.css calls it "always dark with light text").
   That is what gives a light-mode reader something other than a white page,
   and it stops the dark-mode screenshots further down from looking like a
   mistake. */

.hero {
  position: relative;
  overflow: hidden;
  background-color: #0d0d0d;
  border: 1px solid #232323;
  /* The red baseline is a border rather than an element. As a positioned
     child it sat under .meta, which paints last with a 74%-opaque fill, and
     the strip all but vanished on the two guide pages. A border always
     paints. */
  border-bottom: 3px solid var(--brand);
  border-radius: 14px;
  margin: 0 0 var(--sp-8);
}
.hero__inner { position: relative; padding: var(--sp-7) var(--sp-7) var(--sp-6); }

.hero__art {
  position: absolute; inset: 0; pointer-events: none;
  background: url("hero-bg.jpg") no-repeat right center / cover;
}
.hero__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(100deg,
    #0d0d0d 0%,
    rgba(13, 13, 13, 0.96) 52%,
    rgba(13, 13, 13, 0.72) 74%,
    rgba(13, 13, 13, 0.34) 100%);
}

.eyebrow {
  display: block;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-ink);
  margin: 0 0 var(--sp-4);
}
/* On the panel the accent is on near-black, where full-strength ice clears
   AA comfortably; --brand-ink is only needed on light page backgrounds. */
.hero .eyebrow { color: var(--brand); }

h1 {
  font-size: clamp(30px, 4.9vw, 46px);
  line-height: 1.05;
  letter-spacing: -0.035em;
  margin: 0 0 var(--sp-4);
  font-weight: 700;
  text-wrap: balance;
}
/* Held to 14em so a title wraps before it reaches the busy half of the art. */
.hero h1 { color: #ffffff; max-width: 14em; }

.lede {
  font-size: var(--fs-xl); line-height: 1.55; color: var(--text-muted);
  margin: 0; text-wrap: pretty; max-width: 32em;
}
.hero .lede { color: rgba(255, 255, 255, 0.74); }

/* Metadata sits in the panel as a bottom band rather than a separate box
   below it: "who / how long / what you need" belongs to the title. The band
   carries its own scrim because it spans the busy half of the artwork. */
.meta {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0;
  margin: 0;
  padding: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(10, 10, 10, 0.74);
  backdrop-filter: blur(6px);
}
.meta__item { padding: var(--sp-3) var(--sp-7); min-width: 0; }
.meta__item + .meta__item { border-left: 1px solid rgba(255, 255, 255, 0.1); }
.meta dt {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.62);
  margin: 0 0 2px;
}
.meta dd {
  margin: 0; font-size: var(--fs-md); line-height: 1.45;
  color: #ffffff; text-wrap: pretty;
}

@media (max-width: 620px) {
  .hero { border-radius: 12px; }
  .hero__inner { padding: var(--sp-5) var(--sp-5) var(--sp-5); }
  /* Portrait and narrow: the art's dark half no longer covers the text, so
     the scrim goes near-solid and the art reads as a tint at the edge. */
  .hero__scrim {
    background: linear-gradient(160deg,
      #0d0d0d 0%, rgba(13, 13, 13, 0.96) 55%, rgba(13, 13, 13, 0.7) 100%);
  }
  .hero .lede { font-size: var(--fs-body); }
  .meta__item { padding: var(--sp-3) var(--sp-5); }
  .meta__item + .meta__item {
    border-left: 0; border-top: 1px solid rgba(255, 255, 255, 0.1);
  }
}

/* --- Headings --------------------------------------------------------------- */

/* Each h2 opens a section, so the section rule belongs to the heading, and a
   short red tick on that rule marks where a section starts. That replaces the
   row of <hr> elements the pages used to carry and keeps the gap between
   sections identical everywhere.

   No scroll-margin-top here: html's scroll-padding-top already offsets every
   anchor target for the sticky chrome, and the two would compose into double
   the gap. One declaration, and it covers h3 and .step targets too. */
h2 {
  position: relative;
  font-size: var(--fs-3xl);
  line-height: 1.25;
  letter-spacing: -0.024em;
  font-weight: 700;
  margin: var(--sp-9) 0 var(--sp-3);
  padding-top: var(--sp-7);
  border-top: 1px solid var(--border);
  text-wrap: balance;
}
h2::before {
  content: ""; position: absolute; top: -1px; left: 0;
  width: 40px; height: 2px; background: var(--brand);
}
h2:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
h2:first-of-type::before { display: none; }

h3 {
  font-size: var(--fs-xl); font-weight: 650; margin: var(--sp-7) 0 var(--sp-2);
  letter-spacing: -0.014em;
}
h4 { font-size: var(--fs-lg); font-weight: 650; margin: var(--sp-5) 0 var(--sp-1); letter-spacing: -0.008em; }

.section-intro { color: var(--text-muted); margin: 0 0 var(--sp-5); text-wrap: pretty; }

p { margin: 0 0 var(--sp-4); text-wrap: pretty; }
ul, ol { margin: 0 0 var(--sp-4); padding-left: var(--sp-5); }
li { margin-bottom: var(--sp-1); }
li > ul, li > ol { margin-top: var(--sp-1); }

/* Kept for any page that still uses one; the section rule lives on h2 now. */
hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-8) 0; }

/* --- Steps ------------------------------------------------------------------ */

.steps { list-style: none; margin: 0 0 var(--sp-5); padding: 0; counter-reset: step; }

.step {
  position: relative;
  padding: 0 0 var(--sp-6) var(--sp-7);
  counter-increment: step;
  margin-bottom: 0;
}
/* Filled, because the number is the thing a reader is counting through and
   the rail needs a solid anchor at each end. */
.step::before {
  content: counter(step);
  position: absolute; left: 0; top: 1px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand);
  color: #ffffff;
  font-size: var(--fs-sm); font-weight: 700;
  font-variant-numeric: tabular-nums;
  display: flex; align-items: center; justify-content: center;
}
/* Connector rail between badges. Stops at the last step so it does not dangle. */
.step::after {
  content: ""; position: absolute; left: 13px; top: 31px; bottom: var(--sp-2);
  width: 1px; background: var(--border);
}
.step:last-child { padding-bottom: 0; }
.step:last-child::after { display: none; }

.step__title {
  font-size: var(--fs-body); font-weight: 650; margin: 0 0 var(--sp-1);
  letter-spacing: -0.01em; color: var(--text);
}
.step > p:last-child, .step > figure:last-child { margin-bottom: 0; }

@media (max-width: 560px) {
  .step { padding-left: var(--sp-6); }
  .step::before { width: 24px; height: 24px; font-size: var(--fs-xs); }
  .step::after { left: 12px; top: 29px; }
}

/* --- UI reference chips ----------------------------------------------------- */

/* Renders an in-app label the way it looks in the product, so a reader can
   pattern-match against their screen instead of parsing a sentence. */
.ui {
  font-family: var(--font); font-size: 0.875em; font-weight: 600;
  background: var(--bg-sunken); border: 1px solid var(--border);
  padding: 1px 6px; border-radius: var(--radius-sm); white-space: nowrap;
  color: var(--text);
  line-height: 1.3;
}
.ui--primary { background: var(--brand); border-color: transparent; color: #fff; }
.ui--danger { background: var(--danger-soft); border-color: transparent; color: var(--danger); }

code, kbd {
  font-family: var(--mono); font-size: 0.855em;
  background: var(--bg-sunken); border: 1px solid var(--border);
  padding: 1px 5px; border-radius: var(--radius-sm);
  /* Long URLs must be allowed to break on a phone, or they widen the page. */
  overflow-wrap: break-word; word-break: break-word;
}
code:not(:where(.shot__pending *)) { color: var(--text); }

.path { color: var(--text-muted); font-size: 0.94em; }
.path .sep { color: var(--text-faint); margin: 0 3px; }

/* --- Callouts ---------------------------------------------------------------- */

/* No icon, no tinted panel by default. A hairline box, a coloured left rule
   and a coloured label carry the type of the callout. */
.note {
  padding: var(--sp-3) var(--sp-4);
  margin: 0 0 var(--sp-5);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-faint);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--bg-subtle);
  font-size: var(--fs-lg);
  line-height: 1.6;
}
.note p { margin: 0; text-wrap: pretty; }
.note p + p { margin-top: var(--sp-2); }
.note__body { min-width: 0; }
.note__label {
  font-weight: 650; display: block; margin-bottom: 2px;
  letter-spacing: -0.005em; color: var(--text);
}

.note--tip { background: var(--ok-soft); border-left-color: var(--ok); }
.note--tip .note__label { color: var(--ok); }
.note--warn { background: var(--warn-soft); border-left-color: var(--warn); }
.note--warn .note__label { color: var(--warn); }
.note--danger { background: var(--danger-soft); border-left-color: var(--danger); }
.note--danger .note__label { color: var(--danger); }
.note--info { background: var(--info-soft); border-left-color: var(--info); }
.note--info .note__label { color: var(--info); }

/* --- Screenshots -------------------------------------------------------------- */

figure { margin: 0 0 var(--sp-5); }

/* The frame belongs to the image, NOT to the <figure>, so the <figcaption> is
   not enclosed by it and can sit outside with room to breathe. */
.shot { margin: 0 0 var(--sp-5); }

.shot > img,
.shot .shot__pending {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-subtle);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.shot > img { width: 100%; display: block; }

/* Phone captures are 390px-wide viewports. Blown up to the full text column
   they look like a low-resolution desktop screen; held near their real width
   they read as a phone. */
.shot--phone > img,
.shot--phone .shot__pending { max-width: 380px; }

/* A single card cropped out of a desktop page. Stretched to the text column it
   loses sharpness and reads larger than it is; held near its real width it
   reads as the one panel the step is about. */
.shot--card > img,
.shot--card .shot__pending { max-width: 440px; }

/* Placeholder shown until a real PNG is dropped into images/. The <img> hides
   itself on error (see guide.js) and this panel is what remains, so the page
   never renders a broken-image icon. */
.shot__pending {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); padding: var(--sp-7) var(--sp-5); text-align: center;
  background: var(--bg-subtle);
  border-style: dashed;
  border-color: var(--border-strong);
  color: var(--text-muted); min-height: 160px;
}
.shot__pending strong {
  display: block; color: var(--text); font-size: var(--fs-md); font-weight: 650;
}
.shot__pending code { font-size: var(--fs-xs); background: var(--bg); color: var(--text-muted); }
.shot__pending .shot__hint { font-size: var(--fs-sm); max-width: 46ch; line-height: 1.5; }

/* A caption answers "what am I looking at", so it has to be read. Muted grey
   at 13px made it the faintest text on the page and it got skipped. Near-full
   contrast and a hairline indent tie it to the image without letting it
   compete with the body copy around it. */
figcaption {
  font-size: var(--fs-md);
  line-height: 1.55;
  color: var(--text-muted);
  margin-top: var(--sp-3);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--brand);
  max-width: 52em;
  text-wrap: pretty;
}
figcaption b { font-weight: 650; color: var(--text); }

/* --- Cards / grids ------------------------------------------------------------ */

.grid { display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-5); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }

.card {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--sp-4); background: var(--bg-subtle);
  box-shadow: var(--shadow);
  min-width: 0;
}
.card h4 { margin: 0 0 var(--sp-1); font-size: var(--fs-lg); letter-spacing: -0.008em; }
.card p { margin: 0; font-size: var(--fs-md); line-height: 1.55; color: var(--text-muted); }

.card--link {
  text-decoration: none; color: inherit; display: flex; flex-direction: column;
  padding: var(--sp-5);
  transition: border-color .15s, background .15s;
}
.card--link:hover { border-color: var(--border-strong); background: var(--bg-subtle); color: inherit; }
.card--link .card__more {
  color: var(--brand-ink); font-weight: 600; font-size: var(--fs-md);
  margin-top: var(--sp-4); display: block;
}
.card--soon {
  background: var(--bg-subtle);
  border-style: dashed;
}
.card--soon h4 { color: var(--text-muted); }
.card--soon .card__more {
  display: inline-block; margin-top: var(--sp-4);
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text-muted);
  border: 1px solid var(--border-strong); border-radius: 999px;
  padding: 2px var(--sp-2);
}

/* --- Tables -------------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto; margin: 0 0 var(--sp-5);
  border: 1px solid var(--border); border-radius: var(--radius);
  -webkit-overflow-scrolling: touch;
}
table { border-collapse: collapse; width: 100%; font-size: var(--fs-md); }
th, td {
  text-align: left; padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border); vertical-align: top;
  line-height: 1.5;
}
th {
  background: var(--bg-subtle); font-weight: 700;
  font-size: var(--fs-2xs); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--text-muted); white-space: nowrap;
}
tr:last-child td { border-bottom: 0; }

/* A sideways-scrolling table gives no hint that it scrolls. Below the reading
   measure the cells stack into labelled rows instead, using the header text
   copied onto each cell by guide.js. */
@media (max-width: 560px) {
  .table-wrap { border: 0; border-radius: 0; overflow: visible; }
  .table-wrap table, .table-wrap tbody, .table-wrap tr, .table-wrap td { display: block; width: 100%; }
  .table-wrap thead { display: none; }
  .table-wrap tr {
    border: 1px solid var(--border); border-radius: var(--radius);
    margin-bottom: var(--sp-3); padding: var(--sp-1) 0;
  }
  .table-wrap td { border-bottom: 0; padding: var(--sp-2) var(--sp-4); }
  .table-wrap td + td { border-top: 1px solid var(--border); }
  .table-wrap td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--text-muted);
    margin-bottom: 2px;
  }
}

/* --- FAQ ----------------------------------------------------------------------- */

.faq { border-top: 1px solid var(--border); margin: 0 0 var(--sp-5); }

details {
  border-bottom: 1px solid var(--border);
  background: transparent;
}
summary {
  cursor: pointer;
  padding: var(--sp-3) var(--sp-6) var(--sp-3) 0;
  font-weight: 550; font-size: var(--fs-body);
  list-style: none;
  position: relative;
  min-height: 44px;
  display: flex; align-items: center;
  color: var(--text);
  letter-spacing: -0.008em;
}
summary:hover { color: var(--brand-ink); }
summary::-webkit-details-marker { display: none; }
/* Chevron drawn from borders: no icon file, no emoji, no font dependency. */
summary::after {
  content: "";
  position: absolute; right: var(--sp-2); top: 50%;
  width: 7px; height: 7px;
  border-right: 1.5px solid var(--text-faint);
  border-bottom: 1.5px solid var(--text-faint);
  transform: translateY(-75%) rotate(45deg);
  transition: transform .15s ease, border-color .15s;
}
summary:hover::after { border-color: var(--brand); }
details[open] summary::after { transform: translateY(-25%) rotate(225deg); }
details > *:not(summary) {
  font-size: var(--fs-lg); color: var(--text-muted); line-height: 1.6;
}
details > p:last-child { margin-bottom: var(--sp-4); }

/* --- Footer ---------------------------------------------------------------------- */

.foot {
  max-width: 1080px; margin: 0 auto; padding: var(--sp-5) var(--sp-5) var(--sp-8);
  border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); align-items: center;
  font-size: var(--fs-md); color: var(--text-muted);
}
.foot__spacer { flex: 1; }
.foot a { color: var(--text-muted); text-decoration: none; }
.foot a:hover { color: var(--brand-ink); text-decoration: underline; }

.foot__brand { display: flex; align-items: center; gap: var(--sp-3); }
.foot__logo { display: block; height: 28px; width: auto; opacity: 0.75; }
.foot__logo--on-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .foot__logo--on-light { display: none; }
  :root:not([data-theme="light"]) .foot__logo--on-dark { display: block; }
}
:root[data-theme="dark"] .foot__logo--on-light { display: none; }
:root[data-theme="dark"] .foot__logo--on-dark { display: block; }
:root[data-theme="light"] .foot__logo--on-light { display: block; }
:root[data-theme="light"] .foot__logo--on-dark { display: none; }

@media (max-width: 620px) {
  .foot { padding: var(--sp-5) var(--sp-4) var(--sp-7); gap: var(--sp-3) var(--sp-5); }
  .foot__spacer { flex-basis: 100%; height: 0; }
}

/* --- Print ------------------------------------------------------------------------ */

@media print {
  :root { --bg: #fff; --text: #000; --text-muted: #333; --border: #ccc; --border-strong: #999; }
  .topbar, .toc, .quicknav, .theme-toggle, .foot, .guide-end { display: none !important; }
  .layout { display: block; max-width: none; padding: 0; }
  main { max-width: none; }
  body { font-size: 10.5pt; line-height: 1.5; }

  /* The panel is a screen device. On paper it is a black rectangle, so it is
     stripped back to a rule under the title. */
  .hero {
    background: none; border: 0; border-bottom: 2pt solid #000;
    border-radius: 0; margin-bottom: 18pt;
  }
  .hero__inner { padding: 0 0 8pt; }
  .hero__art { display: none; }
  .hero h1 { color: #000; }
  .hero .lede { color: #333; }
  .meta { border-top: 1px solid #999; background: none; backdrop-filter: none; }
  .meta__item { padding: 6pt 0; }
  .meta__item + .meta__item { border-left: 0; }
  .meta dt { color: #666; }
  .meta dd { color: #000; }

  h1 { font-size: 21pt; }
  h2 { font-size: 15pt; margin-top: 28pt; padding-top: 12pt; }
  h3 { font-size: 12pt; }
  h2::before { display: none; }

  .step, figure, .note, details, .card, tr { break-inside: avoid; }
  details { border-bottom: 0; }
  details > *:not(summary) { display: block !important; }
  summary::after { display: none; }
  .shot > img { max-width: 380px; }
  a { color: inherit; text-decoration: none; }
  h2, h3, .step__title { break-after: avoid; }
}

/* --- Arriving for one topic ---------------------------------------------------- */
/* The help centre opens a guide at its top (page.html?topic=...), never
   mid-page, so the title and "who this is for" are the first thing read.
   guide.js puts this card under the header to name the topic and go to it.
   Ice, not flame: it is "where you are headed", not the page's one action. */
.landing {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  margin: 0 0 var(--sp-8);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--brand-soft);
}
/* Sits close under the header it belongs to, then the usual gap to the text. */
.hero + .landing { margin-top: calc(var(--sp-4) - var(--sp-8)); }
.landing__text { min-width: 0; }
.landing__label {
  margin: 0 0 2px; font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--brand-ink);
}
.landing__title { margin: 0; font-size: var(--fs-xl); font-weight: 700; line-height: 1.35; color: var(--text); text-wrap: balance; }
.landing__go {
  flex: none; min-height: 40px; padding: 0 var(--sp-4);
  border: 1px solid var(--brand); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--brand-ink);
  font: inherit; font-size: var(--fs-md); font-weight: 650; cursor: pointer;
  transition: background-color .15s;
}
.landing__go:hover { background: var(--brand-soft); }

/* The topic's section in the page index, and in the phone quick nav (a clone). */
.toc a.is-topic, .quicknav__panel a.is-topic { color: var(--text); font-weight: 650; }
.toc__topic {
  display: block; margin-top: 2px;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--brand-ink);
}
.quicknav__panel a.is-topic { flex-wrap: wrap; }
.quicknav__panel .toc__topic { flex-basis: 100%; }

/* guide.js marks the step or question the reader came for when they go to it.
   A ring that fades, so they see where they landed and then read on. */
.is-target { border-radius: var(--radius-sm); animation: guide-landed 2.8s ease-out 1 both; }
@keyframes guide-landed {
  0%, 50% { box-shadow: 0 0 0 2px var(--brand), 0 0 0 8px var(--brand-soft); background: var(--brand-soft); }
  100% { box-shadow: 0 0 0 2px transparent, 0 0 0 8px transparent; background: transparent; }
}
.is-target:focus { outline: none; }
@media (prefers-reduced-motion: reduce) {
  .is-target { animation: none; box-shadow: 0 0 0 2px var(--brand); }
  .landing__go { transition: none; }
}
