/* Pikefall — the landing page.
 *
 * The game's own shell is `css/style.css`, which is 140 lines because the game
 * renders to a canvas. This file dresses the one page that has to do the
 * opposite job: say what Pikefall is to somebody who has never seen it, and
 * give somebody who has a reason to open the tab again.
 *
 * Three things it is deliberately built out of, rather than around:
 *
 * 1. **The game's own palette and faces.** Every colour here is a value from
 *    `src/constants.js` (`COLORS`) and both faces are `art.js`'s `DISPLAY_FONT`
 *    and `UI_FONT`. A landing page in a different palette from the product is
 *    an advert for a different product, and there are no webfonts to fetch —
 *    which the content-security policy would refuse anyway (`font-src 'self'`).
 *
 * 2. **The game's own framing language**, translated into CSS. `art.js` names
 *    four container kinds separated by *depth*: `panel` stands on the world
 *    with a cast shadow and a gold inlay, `plaque` is cut into a frame with its
 *    shadow gathered above and a lit lip beneath, `button` stands proud with
 *    the light on top. `.panel`, `.plaque` and `.btn` below are those three,
 *    with the same light direction. Two corner radii and no more, for the same
 *    reason the game has two: `--r-frame` for anything standing on the page,
 *    `--r-inset` for anything cut into a frame.
 *
 * 3. **No `url()`, anywhere.** Not a stylistic preference — `tools/csp.mjs`
 *    gates it, because `img-src 'self' data:` and `default-src 'none'` are
 *    affordable only while the stylesheet fetches nothing. Every texture on
 *    this page is a gradient, and the one picture is a canvas the game paints.
 */

/* --- Tokens --------------------------------------------------------------- */

:root {
  /* Ground. Deeper than the game's own `panelDark`, so that chrome lifted out
     of the game reads as sitting *on* the page rather than merging with it. */
  --ink: #14100a;
  --ink-2: #1b160e;
  --panel: #2e2718;
  --panel-lit: #4a3d2a;

  --gold: #f0c040;
  --gold-deep: #a8801c;
  --gold-shade: #6d4f10;

  --parchment: #e8d9ae;
  --vellum: #e0cfa4;
  --vellum-worn: #c4ad78;

  --text: #f5e9c8;
  --dim: #b9a880;
  --ink-text: #241c10;

  /* The four tower families, straight out of `data/towerDefs.js`. They are the
     page's only secondary colours, and they are content: each one is the
     accent that family is drawn with in the game. */
  --archer: #7fae4a;
  --barracks: #c8912e;
  --mage: #8f6fe0;
  --bombard: #c56a3a;
  --physical: #d8d2c4;

  /* `art.js`'s two faces, unchanged. */
  --display: Georgia, "Palatino Linotype", "Book Antiqua", "Times New Roman", serif;
  --ui: "Trebuchet MS", "Segoe UI", system-ui, sans-serif;

  /* The type scale is the game's `TYPE_SCALE` ratios carried onto a page read
     at arm's length instead of at a canvas. Seven steps, ~1.25x apart, and
     nothing between two of them. */
  --t-micro: 0.72rem;
  --t-small: 0.86rem;
  --t-body: 1.06rem;
  --t-lede: clamp(1.08rem, 0.98rem + 0.4vw, 1.28rem);
  --t-h3: 1.32rem;
  --t-h2: clamp(1.75rem, 1.15rem + 2.4vw, 2.9rem);
  --t-mark: clamp(2.9rem, 1.1rem + 7.4vw, 6.4rem);

  --r-frame: 10px;
  --r-inset: 5px;

  --wrap: 1120px;
  --band-pad: clamp(4rem, 8vw, 7.5rem);
}

/* --- Reset ---------------------------------------------------------------- */

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* The sticky bar would otherwise land on top of every anchored heading. */
  scroll-padding-top: 5.5rem;
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--ink);
  color: var(--text);
  font-family: var(--ui);
  font-size: var(--t-body);
  line-height: 1.62;
  overflow-x: hidden;
  /* A warm bloom behind the hero, so the page does not open on flat black. The
     game's own shell does the same thing with the letterbox bars. */
  background-image:
    radial-gradient(120% 78% at 50% 0%, #2a2214 0%, rgba(20, 16, 10, 0) 62%),
    radial-gradient(90% 60% at 78% 12%, rgba(240, 192, 64, 0.09) 0%, rgba(20, 16, 10, 0) 70%);
  background-repeat: no-repeat;
}

img, canvas { display: block; max-width: 100%; }

a { color: inherit; }

::selection { background: rgba(240, 192, 64, 0.28); }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 40;
  padding: 0.7rem 1.1rem;
  background: var(--gold);
  color: var(--ink-text);
  font-weight: bold;
}

.skip:focus { left: 0.6rem; top: 0.6rem; }

.wrap {
  width: min(var(--wrap), 100% - 2.6rem);
  margin-inline: auto;
}

/* --- Framing: the three container kinds, by depth ------------------------- */

/* Stands on the page: a cast shadow underneath, a hairline gold inlay inside
   the rim, and the light from above. */
.panel {
  background: linear-gradient(180deg, #342c1c 0%, #241d12 100%);
  border: 1px solid var(--panel-lit);
  border-radius: var(--r-frame);
  box-shadow:
    0 18px 34px -18px rgba(0, 0, 0, 0.85),
    inset 0 1px 0 rgba(245, 233, 200, 0.10),
    inset 0 0 0 1px rgba(168, 128, 28, 0.14);
}

/* Cut into the page: the shadow gathers along the top edge and a lit lip runs
   under the bottom one. Exactly the inversion `art.js` uses. */
.plaque {
  background: linear-gradient(180deg, #1c1710 0%, #221b11 100%);
  border: 1px solid #3a3120;
  border-radius: var(--r-inset);
  box-shadow:
    inset 0 4px 10px -4px rgba(0, 0, 0, 0.9),
    inset 0 -1px 0 rgba(245, 233, 200, 0.09);
}

/* --- Buttons: proud of the frame ------------------------------------------ */

.btn {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  min-height: 48px;
  padding: 0.72rem 1.5rem;
  border-radius: var(--r-inset);
  font-family: var(--display);
  font-weight: bold;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: transform 0.14s ease, box-shadow 0.14s ease, background-color 0.14s ease;
}

.btn-label { font-size: 1.06rem; line-height: 1.2; }

.btn-sub {
  font-family: var(--ui);
  font-weight: normal;
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.72;
}

/* Struck gold, lit from above, with the shade of its own thickness beneath. */
.btn-primary {
  background: linear-gradient(180deg, #ffdc7a 0%, #f0c040 42%, #d9a52c 100%);
  color: var(--ink-text);
  border: 1px solid #ffe9a8;
  box-shadow:
    0 4px 0 var(--gold-shade),
    0 16px 26px -12px rgba(240, 192, 64, 0.55);
}

.btn-primary:focus-visible {
  transform: translateY(-2px);
  box-shadow:
    0 6px 0 var(--gold-shade),
    0 22px 30px -12px rgba(240, 192, 64, 0.65);
}

.btn-primary:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 var(--gold-shade);
}

.btn-ghost {
  /* Opaque enough to sit on grass. The hero's secondary control is the one
     piece of chrome on this page with a battlefield behind it rather than a
     scrim, which is the same reason `art.js` makes every container kind lay an
     opaque face down before it draws anything on it. */
  background: rgba(24, 19, 12, 0.86);
  color: var(--text);
  border: 1px solid var(--panel-lit);
  box-shadow: inset 0 1px 0 rgba(245, 233, 200, 0.08);
}

.btn-ghost:focus-visible {
  background: rgba(58, 48, 32, 0.94);
  transform: translateY(-2px);
}

.btn-small {
  min-height: 40px;
  padding: 0.42rem 1.05rem;
  font-size: 0.95rem;
}

.btn-big {
  min-height: 62px;
  padding: 1rem 2.6rem;
}

.btn-big .btn-label { font-size: 1.35rem; }

/* --- Top bar -------------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.7rem clamp(1rem, 3vw, 2rem);
  background: rgba(20, 16, 10, 0.82);
  border-bottom: 1px solid rgba(74, 61, 42, 0.7);
  backdrop-filter: blur(9px);
}

.topbar-mark {
  font-family: var(--display);
  font-size: 1.16rem;
  font-weight: bold;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  text-decoration: none;
}

.topbar-nav {
  display: flex;
  gap: 1.5rem;
  margin-left: auto;
  font-size: var(--t-small);
  letter-spacing: 0.05em;
}

.topbar-nav a {
  color: var(--dim);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.topbar-nav a:hover { color: var(--text); border-bottom-color: var(--gold-deep); }

/* --- Hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  display: flex;
  align-items: flex-start;
  min-height: clamp(560px, 100svh, 1080px);
  padding: clamp(3rem, 7vh, 6rem) 0 clamp(3rem, 8vh, 7rem);
  overflow: hidden;
}

/* The diorama fills the hero and the scene is anchored to the bottom of it, so
   the road lands under the copy rather than behind it. A canvas behind a
   headline is a legibility problem; a canvas under the horizon is a picture. */
.hero-field {
  position: absolute;
  inset: 0;
}

#diorama {
  width: 100%;
  height: 100%;
}

/* The scrim is two gradients rather than one flat wash: the page ground at the
   top, where the type is, fading out across the middle so the road is seen at
   full strength, and back in along the bottom edge so the hero hands over to
   the next band instead of stopping. */
.hero-fade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(130% 88% at 14% 24%, rgba(20, 16, 10, 0.96) 0%, rgba(20, 16, 10, 0.74) 34%, rgba(20, 16, 10, 0) 64%),
    linear-gradient(180deg, var(--ink) 0%, rgba(20, 16, 10, 0.62) 14%, rgba(20, 16, 10, 0) 34%),
    linear-gradient(0deg, var(--ink) 0%, rgba(20, 16, 10, 0.35) 9%, rgba(20, 16, 10, 0) 24%);
}

.hero-copy {
  position: relative;
  z-index: 1;
  width: min(var(--wrap), 100% - 2.6rem);
  margin-inline: auto;
}

.hero-copy > * { max-width: 40rem; }

.eyebrow {
  font-size: var(--t-micro);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--gold-deep);
  margin-bottom: 1.1rem;
}

.eyebrow-ink { color: #8a6a2c; }

/* The wordmark is struck metal: a bright top edge, a shadowed base, and the
   game's display face at the top of the scale. `goldText` in `art.js` does the
   same thing on canvas, and this is the CSS of that idea. */
.wordmark {
  font-family: var(--display);
  font-size: var(--t-mark);
  font-weight: bold;
  line-height: 0.94;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold);
  background: linear-gradient(176deg, #fff4cd 0%, #f7cf62 34%, #e0a92c 62%, #b8861d 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 3px 0 rgba(20, 16, 10, 0.6)) drop-shadow(0 14px 26px rgba(0, 0, 0, 0.55));
}

.hero-tagline {
  font-family: var(--display);
  font-size: clamp(1.3rem, 0.9rem + 1.5vw, 1.9rem);
  color: var(--parchment);
  margin-top: 0.7rem;
  letter-spacing: 0.02em;
}

.hero-lede {
  font-size: var(--t-lede);
  color: var(--dim);
  max-width: 34rem;
  margin-top: 1.1rem;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.9rem;
  margin-top: 2rem;
}

.hero-meta {
  display: inline-block;
  margin-top: 1.1rem;
  padding: 0.3rem 0.7rem;
  font-size: var(--t-small);
  color: var(--parchment);
  letter-spacing: 0.04em;
  /* This line sits on grass rather than on the scrim, so it carries its own
     ground — the rule every container kind in `art.js` follows, at the smallest
     size it comes in. A text shadow alone was not enough over sunlit turf. */
  background: rgba(20, 16, 10, 0.62);
  border-radius: var(--r-inset);
}

/* The returning-player strip and the arriving-share strip. Both are written by
   `src/landing/main.js` and neither exists in the served markup. */
.resume {
  margin-top: 1.6rem;
  padding: 0.85rem 1.1rem;
  border-left: 3px solid var(--gold-deep);
  background: linear-gradient(90deg, rgba(20, 16, 10, 0.94), rgba(20, 16, 10, 0.6));
  border-radius: 0 var(--r-inset) var(--r-inset) 0;
  font-size: var(--t-small);
  color: var(--parchment);
}

.resume strong { color: var(--gold); font-weight: bold; }

.resume-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.4rem;
  margin-top: 0.35rem;
  color: var(--dim);
  letter-spacing: 0.03em;
}

/* --- Bands ---------------------------------------------------------------- */

.band {
  position: relative;
  padding: var(--band-pad) 0;
}

/* The hairline that separates two bands is the gold inlay off `panel`: bright
   in the middle, gone at the margins. */
.band::before,
.band-vellum::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, rgba(168, 128, 28, 0) 0%, rgba(168, 128, 28, 0.55) 50%, rgba(168, 128, 28, 0) 100%);
}

.band-alt { background: linear-gradient(180deg, rgba(27, 22, 14, 0.92), rgba(20, 16, 10, 0.4)); }

.section-title {
  font-family: var(--display);
  font-size: var(--t-h2);
  font-weight: bold;
  line-height: 1.14;
  letter-spacing: 0.005em;
  color: var(--parchment);
  max-width: 22ch;
}

.section-lede {
  margin-top: 1.1rem;
  font-size: var(--t-lede);
  color: var(--dim);
  max-width: 56ch;
}

.section-lede + .section-lede { margin-top: 0.9rem; }

/* --- The rules ------------------------------------------------------------ */

.rule-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.2rem;
  margin-top: 2.6rem;
  counter-reset: rule;
}

.rule {
  display: flex;
  flex-direction: column;
  padding: 1.35rem 1.4rem 1.25rem;
  counter-increment: rule;
}

.rule p { font-size: var(--t-small); color: var(--dim); }

/* The number is drawn rather than typed, for the same reason the march list
   numbers itself: the section promises three and a hand-typed "03" on a fourth
   card is a promise nobody would re-check. The mark sits beside it — three
   shapes in three colours, the same three channels the game uses to tell
   armour from a ward from a flyer — so the card states its rule twice before
   the heading, once as a count and once as a symbol. */
.rule-index {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 0.5rem;
}

.rule-index::before {
  content: counter(rule, decimal-leading-zero);
  font-family: var(--display);
  font-size: var(--t-small);
  letter-spacing: 0.16em;
  color: var(--gold-deep);
}

.rule-title {
  font-family: var(--display);
  font-size: var(--t-h3);
  line-height: 1.24;
  color: var(--text);
  margin-bottom: 0.6rem;
}

/* Three marks, three shapes, three colours — the same three channels the game
   itself uses to tell armour from a ward from a flyer. */
.rule-mark {
  width: 16px;
  height: 16px;
  flex: none;
  border: 2px solid var(--ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.rule-mark-physical { background: var(--physical); border-radius: 3px; }
.rule-mark-block { background: var(--barracks); border-radius: 50%; }
.rule-mark-air {
  background: var(--mage);
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
}

.rule p.rule-answer {
  /* Pushed to the floor of the card, so the three consequences line up across a
     row whose paragraphs are different lengths. */
  margin-top: auto;
  padding-top: 0.8rem;
  border-top: 1px dashed rgba(168, 128, 28, 0.35);
  color: var(--gold);
  font-size: var(--t-small);
}

/* --- Towers --------------------------------------------------------------- */

.tower-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1.2rem;
  margin-top: 2.8rem;
}

.tower {
  padding: 1.2rem 1.3rem 1.4rem;
  border-top-width: 3px;
  text-align: center;
}

.tower[data-family="archer"] { border-top-color: var(--archer); }
.tower[data-family="barracks"] { border-top-color: var(--barracks); }
.tower[data-family="mage"] { border-top-color: var(--mage); }
.tower[data-family="bombard"] { border-top-color: var(--bombard); }

.tower-icon {
  width: 132px;
  height: 148px;
  margin: 0 auto 0.4rem;
}

.tower-name {
  font-family: var(--display);
  font-size: var(--t-h3);
  color: var(--text);
}

.tower-blurb {
  margin-top: 0.5rem;
  font-size: var(--t-small);
  color: var(--dim);
}

.tower-branches {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px dashed rgba(168, 128, 28, 0.3);
  font-size: var(--t-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.tower-note {
  margin-top: 2.2rem;
  font-size: var(--t-small);
  color: var(--dim);
  max-width: 58ch;
}

/* --- The campaign, on vellum ---------------------------------------------- */

/* The one light band on the page, and it is light because a chart is a physical
   sheet: the section reads as parchment pulled out onto the table. The wear is
   three gradients, because a `url()` is not available and would not be taken
   even if it were. */
.band-vellum {
  position: relative;
  padding: var(--band-pad) 0;
  color: var(--ink-text);
  background:
    radial-gradient(70% 50% at 12% 8%, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0) 60%),
    radial-gradient(60% 45% at 88% 92%, rgba(140, 106, 52, 0.22), rgba(255, 255, 255, 0) 65%),
    linear-gradient(180deg, var(--vellum) 0%, #d8c69a 55%, #cbb684 100%);
  box-shadow:
    inset 0 22px 34px -26px rgba(40, 26, 10, 0.85),
    inset 0 -22px 34px -26px rgba(40, 26, 10, 0.85);
}

.section-title-ink { color: #2c2210; }
.section-lede-ink { color: #5b4a2c; }

.chart-figure {
  margin-top: 2.6rem;
  border-radius: var(--r-frame);
  overflow: hidden;
  border: 1px solid rgba(90, 64, 34, 0.45);
  box-shadow: 0 22px 44px -26px rgba(40, 26, 10, 0.9);
  background: #ded0a6;
}

#chart {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
}

.chart-figure figcaption {
  padding: 0.7rem 1rem;
  font-size: var(--t-small);
  color: #5b4a2c;
  background: rgba(255, 255, 255, 0.22);
  border-top: 1px solid rgba(90, 64, 34, 0.28);
}

/* The march is a sequence, so it is numbered. Ten maps in the order they are
   marched, which is the one list on this page where the count carries meaning
   rather than decorating a grid. */
.march {
  margin-top: 2.4rem;
  columns: 2;
  column-gap: 2.6rem;
  list-style: none;
  counter-reset: march;
}

.march li {
  counter-increment: march;
  break-inside: avoid;
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  padding: 0.55rem 0;
  border-bottom: 1px dotted rgba(90, 64, 34, 0.4);
}

.march li::before {
  content: counter(march, decimal-leading-zero);
  font-family: var(--display);
  font-size: var(--t-small);
  color: #8a6a2c;
  min-width: 1.7rem;
}

.march-name { font-weight: bold; color: #2c2210; }

.march-note {
  margin-left: auto;
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6d5a38;
  white-space: nowrap;
}

.march li.done .march-name::after {
  content: " ★";
  color: #a8801c;
}

/* --- Coming back ---------------------------------------------------------- */

.return-grid {
  /* Two columns, not three: there are four of these, and a three-up grid
     leaves the fourth standing on its own at the bottom of the section. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
  gap: 1.1rem;
  margin-top: 2.8rem;
}

.return-grid .plaque { padding: 1.4rem 1.45rem; }

.return-grid h3 {
  font-family: var(--display);
  font-size: var(--t-h3);
  color: var(--gold);
  margin-bottom: 0.6rem;
}

.return-grid p { font-size: var(--t-small); color: var(--dim); }

.figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.4rem;
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid rgba(74, 61, 42, 0.8);
  text-align: center;
}

.figure-n {
  display: block;
  font-family: var(--display);
  font-size: clamp(2.2rem, 1.2rem + 3vw, 3.4rem);
  line-height: 1;
  color: var(--gold);
}

.figure-l {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

/* --- Support -------------------------------------------------------------- */

.support-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: 2.2rem;
}

/* The one button on this page that is not the Play button, and it deliberately
   does not compete with it: `.btn-primary` is struck gold and is the page's
   single loudest object, so a donation control that borrowed it would be asking
   for money in the voice the game asks to be played in. This wears `.panel`'s
   own face — the same two stops, so it is literally the page's frame colour —
   with the accent moved onto the edge, which is the move the Armoury's
   always-full slots make rather than lighting the whole face. */
.btn-support {
  flex-direction: row;
  gap: 0.65rem;
  background: linear-gradient(180deg, #342c1c 0%, #241d12 100%);
  color: var(--parchment);
  border: 1px solid var(--gold-deep);
  box-shadow:
    0 3px 0 rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(245, 233, 200, 0.10);
}

.btn-support:focus-visible {
  transform: translateY(-2px);
  color: var(--gold);
  border-color: var(--gold);
  box-shadow:
    0 5px 0 rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(245, 233, 200, 0.14);
}

.btn-support:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
}

.btn-support .btn-label { font-size: 1rem; }

/* `currentColor`, so the glyph is lit by the same hover the label is and the
   provider marks need no colour of their own — which is what keeps two brand
   ramps off a page whose palette is the game's. */
.btn-glyph {
  flex: none;
  color: var(--gold-deep);
  transition: color 0.14s ease;
}

.btn-support:focus-visible .btn-glyph { color: var(--gold); }

.support-note {
  margin-top: 1.4rem;
  max-width: 56ch;
  font-size: var(--t-small);
  color: var(--dim);
}

.support-note a {
  color: var(--gold);
  text-decoration: none;
  border-bottom: 1px solid rgba(168, 128, 28, 0.5);
  padding-bottom: 2px;
}

.support-note a:hover { border-bottom-color: var(--gold); }

/* --- Close ---------------------------------------------------------------- */

.close {
  padding: clamp(4.5rem, 9vw, 8rem) 0;
  text-align: center;
  background:
    radial-gradient(70% 100% at 50% 100%, rgba(240, 192, 64, 0.13), rgba(20, 16, 10, 0) 70%);
  border-top: 1px solid rgba(74, 61, 42, 0.8);
}

.close-title {
  font-family: var(--display);
  font-size: var(--t-h2);
  color: var(--parchment);
  margin-bottom: 2rem;
}

.close-inner { display: grid; justify-items: center; }

/* --- Footer --------------------------------------------------------------- */

.footer {
  padding: 2.6rem 0 3.4rem;
  border-top: 1px solid rgba(74, 61, 42, 0.6);
  background: var(--ink-2);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.2rem 2.4rem;
}

.footer-mark {
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-deep);
}

.keys {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.2rem;
  font-size: var(--t-micro);
  color: var(--dim);
}

.keys > div { display: flex; align-items: center; gap: 0.4rem; }

.keys dt {
  padding: 0.15rem 0.45rem;
  border: 1px solid var(--panel-lit);
  border-radius: 4px;
  background: var(--panel);
  color: var(--parchment);
  letter-spacing: 0.06em;
}

.footer-note {
  flex: 1 1 16rem;
  text-align: right;
  font-size: var(--t-micro);
  /* 5.02:1 on `--ink-2`, against WCAG's 4.5:1 floor for text this size. It was
     #7d7150, which is 3.72:1 — the only contrast failure on the page, and the
     kind that is invisible to the person who picked it because they know what
     it says. The repository gates 3.0:1 on chrome and on the chart; a footnote
     nobody can read is not quieter, it is absent. */
  color: #948667;
}

/* The legal pair, linked from every document's footer. Deliberately quieter
   than the key legend beside it: they are the links a person looks for, not
   the ones the page wants read. */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  font-size: var(--t-micro);
  letter-spacing: 0.05em;
}

.footer-links a {
  color: #948667;   /* the footnote's own 5.02:1 grey, for the same reason */
  text-decoration: none;
  border-bottom: 1px solid rgba(148, 134, 103, 0.4);
}

.footer-links a:hover { color: var(--text); border-bottom-color: var(--gold-deep); }

/* --- The legal documents (issue #74) -------------------------------------- */

/* A measure, not a band. These are read top to bottom by somebody looking for
   one answer, so the line length is the book's rather than the landing page's
   and there is no reveal: prose that fades in is prose somebody has to wait
   for, and nobody opens a privacy policy to be entertained. */
.legal {
  width: min(46rem, 100% - 2.6rem);
  margin: clamp(2.5rem, 6vw, 4.5rem) auto clamp(3.5rem, 8vw, 6rem);
}

.legal h1 {
  font-family: var(--display);
  font-size: var(--t-h2);
  line-height: 1.14;
  color: var(--parchment);
}

.legal-updated {
  margin-top: 0.6rem;
  font-size: var(--t-small);
  color: var(--dim);
}

.legal-section { margin-top: 2.4rem; }

.legal h2 {
  font-family: var(--display);
  font-size: var(--t-h3);
  color: var(--gold);
  margin-bottom: 0.6rem;
}

.legal p + p,
.legal p + ul,
.legal ul + p,
.legal table + p { margin-top: 0.8rem; }

.legal ul { padding-left: 1.3rem; }
.legal li + li { margin-top: 0.35rem; }

.legal a {
  color: var(--gold);
  text-decoration: none;
  border-bottom: 1px solid rgba(168, 128, 28, 0.5);
}

.legal a:hover { border-bottom-color: var(--gold); }

.legal code {
  font-size: 0.92em;
  padding: 0.05rem 0.3rem;
  border-radius: 3px;
  background: var(--panel);
  color: var(--parchment);
}

/* The summary box is a plaque — cut into the page — because it is the page's
   own answer to itself rather than a thing standing on top of it. */
.legal-summary {
  margin-top: 1.8rem;
  padding: 1.1rem 1.4rem;
}

.legal-address { font-style: normal; }

.legal table {
  width: 100%;
  margin-top: 0.6rem;
  border-collapse: collapse;
  font-size: var(--t-small);
}

.legal th,
.legal td {
  padding: 0.55rem 0.6rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid rgba(74, 61, 42, 0.8);
}

.legal th { color: var(--dim); font-weight: normal; letter-spacing: 0.04em; }

/* An unstamped operator detail. It has to be impossible to mistake for the
   real thing on a deployed page, so it is the one element on the site drawn in
   `COLORS.danger` — a legal notice reading "[Operator name — set …]" in plain
   body text is exactly the kind of mistake nobody notices for a year. */
.stamp {
  padding: 0.05rem 0.35rem;
  border: 1px dashed #d84438;
  border-radius: 3px;
  background: rgba(216, 68, 56, 0.14);
  color: #ffb4a8;
}

/* --- Buttons that are buttons --------------------------------------------- */

/* `.btn` was written for links; a `<button>` brings its own border, font and
   cursor, which this takes back. */
button.btn {
  cursor: pointer;
  font-size: inherit;
  color: inherit;
}

/* The two consent answers, and the settings control. One class for both
   answers is the point: a refusal drawn smaller or greyer than the acceptance
   is a design that has already chosen for the visitor. `.btn-support`'s face,
   because neither answer is the page's call to action. */
.btn-consent {
  flex-direction: row;
  background: linear-gradient(180deg, #342c1c 0%, #241d12 100%);
  color: var(--parchment);
  border: 1px solid var(--gold-deep);
  box-shadow:
    0 3px 0 rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(245, 233, 200, 0.10);
}

.btn-consent:focus-visible {
  color: var(--gold);
  border-color: var(--gold);
}

.btn-consent:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45); }

/* --- The consent notice (issue #74) --------------------------------------- */

/* Docked to the foot of the viewport rather than centred over the page: it is
   a question the page can be read around, not a wall in front of it. Only ever
   inserted by `src/landing/consent.js`, and only when the deploy names a
   service that needs an answer — which, today, none does. */
.consent {
  position: fixed;
  z-index: 50;
  left: 50%;
  bottom: max(1rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  width: min(40rem, 100% - 2rem);
  padding: 1.2rem 1.4rem 1.1rem;
  /* `.panel` supplies the face; the deeper cast shadow is what lifts it off
     whatever section happens to be scrolled under it. */
  box-shadow:
    0 22px 48px -12px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 rgba(245, 233, 200, 0.10),
    inset 0 0 0 1px rgba(168, 128, 28, 0.14);
}

.consent-title {
  font-family: var(--display);
  font-size: var(--t-h3);
  color: var(--parchment);
}

.consent-body {
  margin-top: 0.4rem;
  font-size: var(--t-small);
  color: var(--text);
}

.consent-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem 0.9rem;
  margin-top: 1rem;
}

.consent-row .btn { min-width: 8.5rem; }

.consent-link {
  font-size: var(--t-small);
  color: var(--gold);
  text-decoration: none;
  border-bottom: 1px solid rgba(168, 128, 28, 0.5);
}

.consent-preview {
  margin-top: 0.8rem;
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffb4a8;
}

.consent-settings { margin-top: 1rem; }

.consent-settings .btn { margin-top: 0.8rem; }

/* --- Reveal on scroll ----------------------------------------------------- */

/* Only armed once the script has run, so a page with no JavaScript shows
   everything rather than nothing. */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.js .reveal.shown { opacity: 1; transform: none; }

/* A short stagger inside the three grids, so a row of cards arrives as a row
   rather than as three things that happened to move at once. */
.js .rule-grid .reveal:nth-child(2),
.js .tower-grid .reveal:nth-child(2),
.js .return-grid .reveal:nth-child(2) { transition-delay: 0.09s; }

.js .rule-grid .reveal:nth-child(3),
.js .tower-grid .reveal:nth-child(3),
.js .return-grid .reveal:nth-child(3) { transition-delay: 0.18s; }

.js .tower-grid .reveal:nth-child(4),
.js .return-grid .reveal:nth-child(4) { transition-delay: 0.27s; }

/* --- Narrow --------------------------------------------------------------- */

@media (max-width: 820px) {
  .topbar-nav { display: none; }
  .march { columns: 1; }
  .footer-note { text-align: left; }
  .hero { min-height: 88svh; }
  .cta-row .btn,
  .support-row .btn { flex: 1 1 100%; }
  .consent-row .btn { flex: 1 1 40%; }
}

/* --- Hover, where there is one (issue #76) -------------------------------- */

/* A touchscreen has no hover, and mobile browsers fake one: after a tap,
   `:hover` sticks to the element until the next tap lands somewhere else. On
   the buttons that is a lift that stays lifted — "Play now" floating 2px up
   and glowing as the page navigates, or a support button left gold after the
   share sheet closes — which reads as a stuck control. So every lift that was
   `:hover, :focus-visible` keeps its keyboard half unconditionally and its
   pointer half only where `(hover: hover)` says the pointer can hover.
   `:not(:active)` on the two lifts that have a press-down keeps the press
   winning: this block sits after the `:active` rules, and at equal specificity
   the later rule would otherwise hold a pressed button up. */
@media (hover: hover) {
  .btn-primary:hover:not(:active) {
    transform: translateY(-2px);
    box-shadow:
      0 6px 0 var(--gold-shade),
      0 22px 30px -12px rgba(240, 192, 64, 0.65);
  }

  .btn-ghost:hover {
    background: rgba(58, 48, 32, 0.94);
    transform: translateY(-2px);
  }

  .btn-support:hover {
    color: var(--gold);
    border-color: var(--gold);
  }

  .btn-support:hover:not(:active) {
    transform: translateY(-2px);
    box-shadow:
      0 5px 0 rgba(0, 0, 0, 0.45),
      inset 0 1px 0 rgba(245, 233, 200, 0.14);
  }

  .btn-support:hover .btn-glyph { color: var(--gold); }

  .btn-consent:hover {
    color: var(--gold);
    border-color: var(--gold);
  }
}

/* --- Reduced motion ------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .btn { transition: none; }
  .btn-glyph { transition: none; }
  .btn-primary:hover:not(:active), .btn-ghost:hover,
  .btn-support:hover:not(:active) { transform: none; }
  .btn-consent:active { transform: none; }
}
